summaryrefslogtreecommitdiff
path: root/chromium/ui/views
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-04 14:17:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-05 10:05:06 +0000
commit39d357e3248f80abea0159765ff39554affb40db (patch)
treeaba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/ui/views
parent87778abf5a1f89266f37d1321b92a21851d8244d (diff)
downloadqtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2 Change-Id: I20d43c737f82764d857ada9a55586901b18b9243 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/views')
-rw-r--r--chromium/ui/views/BUILD.gn761
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc32
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.h17
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.cc2
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc6
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.h1
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc16
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h2
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility.cc39
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility.h2
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc14
-rw-r--r--chromium/ui/views/accessibility/native_view_accessibility_unittest.cc30
-rw-r--r--chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc4
-rw-r--r--chromium/ui/views/animation/flood_fill_ink_drop_ripple.h2
-rw-r--r--chromium/ui/views/animation/ink_drop_highlight.cc6
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc37
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.h12
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view_unittest.cc19
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.cc72
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.h3
-rw-r--r--chromium/ui/views/animation/ink_drop_impl_unittest.cc119
-rw-r--r--chromium/ui/views/animation/ink_drop_painted_layer_delegates.cc35
-rw-r--r--chromium/ui/views/animation/ink_drop_painted_layer_delegates.h9
-rw-r--r--chromium/ui/views/animation/ink_drop_ripple.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop_ripple.h5
-rw-r--r--chromium/ui/views/animation/square_ink_drop_ripple.cc4
-rw-r--r--chromium/ui/views/animation/square_ink_drop_ripple.h2
-rw-r--r--chromium/ui/views/border.cc11
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc154
-rw-r--r--chromium/ui/views/bubble/bubble_border.h9
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate.cc13
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate.h5
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc2
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc52
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h14
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc29
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.cc8
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.h1
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.mm284
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.h8
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.mm49
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_unittest.mm142
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac.mm12
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm51
-rw-r--r--chromium/ui/views/cocoa/views_nswindow_delegate.h3
-rw-r--r--chromium/ui/views/cocoa/views_nswindow_delegate.mm4
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.cc4
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.h1
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc47
-rw-r--r--chromium/ui/views/controls/button/checkbox.h14
-rw-r--r--chromium/ui/views/controls/button/custom_button.cc24
-rw-r--r--chromium/ui/views/controls/button/custom_button_unittest.cc79
-rw-r--r--chromium/ui/views/controls/button/image_button.cc11
-rw-r--r--chromium/ui/views/controls/button/label_button.cc59
-rw-r--r--chromium/ui/views/controls/button/label_button.h12
-rw-r--r--chromium/ui/views/controls/button/label_button_border.cc24
-rw-r--r--chromium/ui/views/controls/button/label_button_unittest.cc57
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc247
-rw-r--r--chromium/ui/views/controls/button/md_text_button.h48
-rw-r--r--chromium/ui/views/controls/button/menu_button.cc24
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc79
-rw-r--r--chromium/ui/views/controls/button/radio_button.h2
-rw-r--r--chromium/ui/views/controls/button/toggle_button.cc147
-rw-r--r--chromium/ui/views/controls/button/toggle_button.h48
-rw-r--r--chromium/ui/views/controls/button/vector_icon_button.cc61
-rw-r--r--chromium/ui/views/controls/button/vector_icon_button.h43
-rw-r--r--chromium/ui/views/controls/button/vector_icon_button_delegate.cc13
-rw-r--r--chromium/ui/views/controls/button/vector_icon_button_delegate.h25
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc183
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h18
-rw-r--r--chromium/ui/views/controls/combobox/combobox_unittest.cc44
-rw-r--r--chromium/ui/views/controls/focus_ring.cc84
-rw-r--r--chromium/ui/views/controls/focus_ring.h40
-rw-r--r--chromium/ui/views/controls/focusable_border.cc37
-rw-r--r--chromium/ui/views/controls/focusable_border.h2
-rw-r--r--chromium/ui/views/controls/label.cc19
-rw-r--r--chromium/ui/views/controls/label.h2
-rw-r--r--chromium/ui/views/controls/link.cc27
-rw-r--r--chromium/ui/views/controls/link.h5
-rw-r--r--chromium/ui/views/controls/md_slider.cc133
-rw-r--r--chromium/ui/views/controls/md_slider.h56
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_config_mac.mm5
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc77
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h11
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc287
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h6
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc6
-rw-r--r--chromium/ui/views/controls/menu/menu_host.h6
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc21
-rw-r--r--chromium/ui/views/controls/menu/menu_key_event_handler.cc27
-rw-r--r--chromium/ui/views/controls/menu/menu_key_event_handler.h33
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop.h10
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_aura.cc82
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_aura.h11
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_mac.cc7
-rw-r--r--chromium/ui/views/controls/menu/menu_message_loop_mac.h7
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler.cc70
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler.h58
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm4
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc16
-rw-r--r--chromium/ui/views/controls/menu/native_menu_win.cc2
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc2
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h9
-rw-r--r--chromium/ui/views/controls/message_box_view.h3
-rw-r--r--chromium/ui/views/controls/non_md_slider.cc106
-rw-r--r--chromium/ui/views/controls/non_md_slider.h49
-rw-r--r--chromium/ui/views/controls/prefix_delegate.h6
-rw-r--r--chromium/ui/views/controls/prefix_selector.cc9
-rw-r--r--chromium/ui/views/controls/prefix_selector.h5
-rw-r--r--chromium/ui/views/controls/prefix_selector_unittest.cc6
-rw-r--r--chromium/ui/views/controls/progress_bar.cc408
-rw-r--r--chromium/ui/views/controls/progress_bar.h66
-rw-r--r--chromium/ui/views/controls/progress_bar_unittest.cc13
-rw-r--r--chromium/ui/views/controls/scroll_view.cc207
-rw-r--r--chromium/ui/views/controls/scroll_view.h38
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc400
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.cc14
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.h5
-rw-r--r--chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm1
-rw-r--r--chromium/ui/views/controls/scrollbar/native_scroll_bar.h4
-rw-r--r--chromium/ui/views/controls/single_split_view.cc264
-rw-r--r--chromium/ui/views/controls/single_split_view.h148
-rw-r--r--chromium/ui/views/controls/single_split_view_listener.h30
-rw-r--r--chromium/ui/views/controls/single_split_view_unittest.cc251
-rw-r--r--chromium/ui/views/controls/slider.cc300
-rw-r--r--chromium/ui/views/controls/slider.h56
-rw-r--r--chromium/ui/views/controls/slider_unittest.cc64
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc158
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.h18
-rw-r--r--chromium/ui/views/controls/table/table_view.cc31
-rw-r--r--chromium/ui/views/controls/table/table_view.h12
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc127
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc315
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h63
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc93
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.h26
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model_unittest.cc326
-rw-r--r--chromium/ui/views/controls/textfield/textfield_test_api.h12
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc410
-rw-r--r--chromium/ui/views/controls/tree/tree_view.cc205
-rw-r--r--chromium/ui/views/controls/tree/tree_view.h32
-rw-r--r--chromium/ui/views/controls/tree/tree_view_unittest.cc20
-rw-r--r--chromium/ui/views/controls/webview/BUILD.gn2
-rw-r--r--chromium/ui/views/controls/webview/webview.gyp51
-rw-r--r--chromium/ui/views/controls/webview/webview_tests.gyp45
-rw-r--r--chromium/ui/views/corewm/DEPS1
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.cc46
-rw-r--r--chromium/ui/views/examples/BUILD.gn9
-rw-r--r--chromium/ui/views/examples/DEPS1
-rw-r--r--chromium/ui/views/examples/button_example.cc14
-rw-r--r--chromium/ui/views/examples/button_sticker_sheet.cc131
-rw-r--r--chromium/ui/views/examples/button_sticker_sheet.h38
-rw-r--r--chromium/ui/views/examples/combobox_example.cc4
-rw-r--r--chromium/ui/views/examples/double_split_view_example.cc83
-rw-r--r--chromium/ui/views/examples/double_split_view_example.h35
-rw-r--r--chromium/ui/views/examples/examples.gyp205
-rw-r--r--chromium/ui/views/examples/examples_main.cc10
-rw-r--r--chromium/ui/views/examples/examples_window.cc10
-rw-r--r--chromium/ui/views/examples/menu_example.cc25
-rw-r--r--chromium/ui/views/examples/progress_bar_example.cc40
-rw-r--r--chromium/ui/views/examples/single_split_view_example.cc92
-rw-r--r--chromium/ui/views/examples/single_split_view_example.h37
-rw-r--r--chromium/ui/views/examples/slider_example.cc4
-rw-r--r--chromium/ui/views/examples/textfield_example.cc69
-rw-r--r--chromium/ui/views/examples/textfield_example.h2
-rw-r--r--chromium/ui/views/examples/throbber_example.cc19
-rw-r--r--chromium/ui/views/examples/toggle_button_example.cc34
-rw-r--r--chromium/ui/views/examples/toggle_button_example.h42
-rw-r--r--chromium/ui/views/examples/tree_view_example.cc65
-rw-r--r--chromium/ui/views/examples/tree_view_example.h9
-rw-r--r--chromium/ui/views/examples/vector_example.cc17
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc16
-rw-r--r--chromium/ui/views/focus/focus_traversal_unittest.cc22
-rw-r--r--chromium/ui/views/focus/view_storage.cc64
-rw-r--r--chromium/ui/views/focus/view_storage.h2
-rw-r--r--chromium/ui/views/layout/grid_layout.cc12
-rw-r--r--chromium/ui/views/layout/grid_layout.h2
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.gyp33
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.h3
-rw-r--r--chromium/ui/views/mus/BUILD.gn85
-rw-r--r--chromium/ui/views/mus/DEPS4
-rw-r--r--chromium/ui/views/mus/aura_init.cc49
-rw-r--r--chromium/ui/views/mus/aura_init.h11
-rw-r--r--chromium/ui/views/mus/clipboard_mus.cc86
-rw-r--r--chromium/ui/views/mus/clipboard_mus.h4
-rw-r--r--chromium/ui/views/mus/display_list.cc109
-rw-r--r--chromium/ui/views/mus/display_list.h69
-rw-r--r--chromium/ui/views/mus/display_list_unittest.cc113
-rw-r--r--chromium/ui/views/mus/drag_drop_client_mus.cc92
-rw-r--r--chromium/ui/views/mus/drag_drop_client_mus.h59
-rw-r--r--chromium/ui/views/mus/drop_target_mus.cc146
-rw-r--r--chromium/ui/views/mus/drop_target_mus.h93
-rw-r--r--chromium/ui/views/mus/input_method_mus.cc86
-rw-r--r--chromium/ui/views/mus/input_method_mus.h33
-rw-r--r--chromium/ui/views/mus/input_method_mus_unittest.cc101
-rw-r--r--chromium/ui/views/mus/interactive_ui_tests_manifest.json2
-rw-r--r--chromium/ui/views/mus/native_widget_mus.cc596
-rw-r--r--chromium/ui/views/mus/native_widget_mus.h113
-rw-r--r--chromium/ui/views/mus/native_widget_mus_unittest.cc162
-rw-r--r--chromium/ui/views/mus/os_exchange_data_provider_mus.cc372
-rw-r--r--chromium/ui/views/mus/os_exchange_data_provider_mus.h118
-rw-r--r--chromium/ui/views/mus/os_exchange_data_provider_mus_unittest.cc211
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router.cc152
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router.h79
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc244
-rw-r--r--chromium/ui/views/mus/screen_mus.cc130
-rw-r--r--chromium/ui/views/mus/screen_mus.h44
-rw-r--r--chromium/ui/views/mus/screen_mus_delegate.h2
-rw-r--r--chromium/ui/views/mus/surface_binding.cc128
-rw-r--r--chromium/ui/views/mus/surface_binding.h57
-rw-r--r--chromium/ui/views/mus/surface_context_factory.cc47
-rw-r--r--chromium/ui/views/mus/surface_context_factory.h36
-rw-r--r--chromium/ui/views/mus/text_input_client_impl.cc55
-rw-r--r--chromium/ui/views/mus/text_input_client_impl.h43
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc42
-rw-r--r--chromium/ui/views/mus/window_manager_connection.cc155
-rw-r--r--chromium/ui/views/mus/window_manager_connection.h67
-rw-r--r--chromium/ui/views/mus/window_manager_connection_unittest.cc118
-rw-r--r--chromium/ui/views/mus/window_manager_constants_converters.cc24
-rw-r--r--chromium/ui/views/mus/window_manager_constants_converters.h8
-rw-r--r--chromium/ui/views/mus/window_tree_host_mus.cc24
-rw-r--r--chromium/ui/views/mus/window_tree_host_mus.h13
-rw-r--r--chromium/ui/views/painter.cc9
-rw-r--r--chromium/ui/views/pointer_watcher.h37
-rw-r--r--chromium/ui/views/repeat_controller.h2
-rw-r--r--chromium/ui/views/resources/default_100_percent/slider_right_active.pngbin106 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/slider_right_active.pngbin146 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/views_resources.grd1
-rw-r--r--chromium/ui/views/resources/views_resources.gyp27
-rw-r--r--chromium/ui/views/round_rect_painter.cc8
-rw-r--r--chromium/ui/views/round_rect_painter.h2
-rw-r--r--chromium/ui/views/style/mac/combobox_background_mac.cc2
-rw-r--r--chromium/ui/views/style/mac/dialog_button_border_mac.cc72
-rw-r--r--chromium/ui/views/style/mac/dialog_button_border_mac.h37
-rw-r--r--chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc200
-rw-r--r--chromium/ui/views/style/platform_style.cc30
-rw-r--r--chromium/ui/views/style/platform_style.h24
-rw-r--r--chromium/ui/views/style/platform_style_mac.mm38
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc5
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc7
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_runner_views.cc5
-rw-r--r--chromium/ui/views/view.cc32
-rw-r--r--chromium/ui/views/view.h13
-rw-r--r--chromium/ui/views/view_unittest.cc76
-rw-r--r--chromium/ui/views/view_unittest_aura.cc2
-rw-r--r--chromium/ui/views/views.gyp1056
-rw-r--r--chromium/ui/views/views_delegate.cc2
-rw-r--r--chromium/ui/views/views_delegate.h4
-rw-r--r--chromium/ui/views/views_unittests.isolate70
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc340
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc53
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc14
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc60
-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.cc471
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h90
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_interactive_uitest.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc25
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc189
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h61
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h26
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc32
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc36
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h6
-rw-r--r--chromium/ui/views/widget/drop_helper.h4
-rw-r--r--chromium/ui/views/widget/focus_manager_event_handler.cc31
-rw-r--r--chromium/ui/views/widget/focus_manager_event_handler.h40
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc43
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h15
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h6
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm21
-rw-r--r--chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm62
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm104
-rw-r--r--chromium/ui/views/widget/native_widget_private.h5
-rw-r--r--chromium/ui/views/widget/widget.cc23
-rw-r--r--chromium/ui/views/widget/widget.h32
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc8
-rw-r--r--chromium/ui/views/widget/widget_delegate.h1
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc118
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc201
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h25
-rw-r--r--chromium/ui/views/win/hwnd_message_handler_delegate.h11
-rw-r--r--chromium/ui/views/window/custom_frame_view.cc13
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc46
-rw-r--r--chromium/ui/views/window/dialog_client_view.h6
-rw-r--r--chromium/ui/views/window/dialog_client_view_unittest.cc4
-rw-r--r--chromium/ui/views/window/dialog_delegate.cc8
-rw-r--r--chromium/ui/views/window/dialog_delegate.h11
-rw-r--r--chromium/ui/views/word_lookup_client.h35
297 files changed, 11072 insertions, 7386 deletions
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index 80ca87aa04c..aa80e6f0cae 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -5,11 +5,7 @@
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
-
-gypi_values = exec_script("//build/gypi_to_gn.py",
- [ rebase_path("views.gyp") ],
- "scope",
- [ "views.gyp" ])
+import("//ui/ozone/ozone.gni")
config("flags") {
defines = [ "TOOLKIT_VIEWS=1" ]
@@ -17,7 +13,374 @@ config("flags") {
component("views") {
all_dependent_configs = [ ":flags" ]
- sources = gypi_values.views_sources
+ sources = [
+ "accessibility/native_view_accessibility.cc",
+ "accessibility/native_view_accessibility.h",
+ "accessibility/native_view_accessibility_win.cc",
+ "accessibility/native_view_accessibility_win.h",
+ "accessible_pane_view.cc",
+ "accessible_pane_view.h",
+ "animation/bounds_animator.cc",
+ "animation/bounds_animator.h",
+ "animation/flood_fill_ink_drop_ripple.cc",
+ "animation/flood_fill_ink_drop_ripple.h",
+ "animation/ink_drop.h",
+ "animation/ink_drop_animation_ended_reason.cc",
+ "animation/ink_drop_animation_ended_reason.h",
+ "animation/ink_drop_highlight.cc",
+ "animation/ink_drop_highlight.h",
+ "animation/ink_drop_highlight_observer.h",
+ "animation/ink_drop_host.h",
+ "animation/ink_drop_host_view.cc",
+ "animation/ink_drop_host_view.h",
+ "animation/ink_drop_impl.cc",
+ "animation/ink_drop_impl.h",
+ "animation/ink_drop_painted_layer_delegates.cc",
+ "animation/ink_drop_painted_layer_delegates.h",
+ "animation/ink_drop_ripple.cc",
+ "animation/ink_drop_ripple.h",
+ "animation/ink_drop_ripple_observer.h",
+ "animation/ink_drop_state.cc",
+ "animation/ink_drop_state.h",
+ "animation/ink_drop_stub.cc",
+ "animation/ink_drop_stub.h",
+ "animation/scroll_animator.cc",
+ "animation/scroll_animator.h",
+ "animation/square_ink_drop_ripple.cc",
+ "animation/square_ink_drop_ripple.h",
+ "background.cc",
+ "background.h",
+ "border.cc",
+ "border.h",
+ "bubble/bubble_border.cc",
+ "bubble/bubble_border.h",
+ "bubble/bubble_dialog_delegate.cc",
+ "bubble/bubble_dialog_delegate.h",
+ "bubble/bubble_frame_view.cc",
+ "bubble/bubble_frame_view.h",
+ "button_drag_utils.cc",
+ "button_drag_utils.h",
+ "cocoa/bridged_content_view.h",
+ "cocoa/bridged_content_view.mm",
+ "cocoa/bridged_native_widget.h",
+ "cocoa/bridged_native_widget.mm",
+ "cocoa/bridged_native_widget_owner.h",
+ "cocoa/cocoa_mouse_capture.h",
+ "cocoa/cocoa_mouse_capture.mm",
+ "cocoa/cocoa_mouse_capture_delegate.h",
+ "cocoa/cocoa_window_move_loop.h",
+ "cocoa/cocoa_window_move_loop.mm",
+ "cocoa/drag_drop_client_mac.h",
+ "cocoa/drag_drop_client_mac.mm",
+ "cocoa/native_widget_mac_nswindow.h",
+ "cocoa/native_widget_mac_nswindow.mm",
+ "cocoa/tooltip_manager_mac.h",
+ "cocoa/tooltip_manager_mac.mm",
+ "cocoa/views_nswindow_delegate.h",
+ "cocoa/views_nswindow_delegate.mm",
+ "cocoa/views_scrollbar_bridge.h",
+ "cocoa/views_scrollbar_bridge.mm",
+ "cocoa/widget_owner_nswindow_adapter.h",
+ "cocoa/widget_owner_nswindow_adapter.mm",
+ "color_chooser/color_chooser_listener.h",
+ "color_chooser/color_chooser_view.cc",
+ "color_chooser/color_chooser_view.h",
+ "context_menu_controller.h",
+ "controls/button/blue_button.cc",
+ "controls/button/blue_button.h",
+ "controls/button/button.cc",
+ "controls/button/button.h",
+ "controls/button/checkbox.cc",
+ "controls/button/checkbox.h",
+ "controls/button/custom_button.cc",
+ "controls/button/custom_button.h",
+ "controls/button/image_button.cc",
+ "controls/button/image_button.h",
+ "controls/button/label_button.cc",
+ "controls/button/label_button.h",
+ "controls/button/label_button_border.cc",
+ "controls/button/label_button_border.h",
+ "controls/button/md_text_button.cc",
+ "controls/button/md_text_button.h",
+ "controls/button/menu_button.cc",
+ "controls/button/menu_button.h",
+ "controls/button/menu_button_listener.h",
+ "controls/button/radio_button.cc",
+ "controls/button/radio_button.h",
+ "controls/button/toggle_button.cc",
+ "controls/button/toggle_button.h",
+ "controls/button/vector_icon_button.cc",
+ "controls/button/vector_icon_button.h",
+ "controls/button/vector_icon_button_delegate.cc",
+ "controls/button/vector_icon_button_delegate.h",
+ "controls/combobox/combobox.cc",
+ "controls/combobox/combobox.h",
+ "controls/combobox/combobox_listener.h",
+ "controls/focus_ring.cc",
+ "controls/focus_ring.h",
+ "controls/focusable_border.cc",
+ "controls/focusable_border.h",
+ "controls/focusable_rounded_border_mac.cc",
+ "controls/focusable_rounded_border_mac.h",
+ "controls/glow_hover_controller.cc",
+ "controls/glow_hover_controller.h",
+ "controls/image_view.cc",
+ "controls/image_view.h",
+ "controls/label.cc",
+ "controls/label.h",
+ "controls/link.cc",
+ "controls/link.h",
+ "controls/link_listener.h",
+ "controls/md_slider.cc",
+ "controls/md_slider.h",
+ "controls/menu/display_change_listener_mac.cc",
+ "controls/menu/menu_config.cc",
+ "controls/menu/menu_config.h",
+ "controls/menu/menu_config_chromeos.cc",
+ "controls/menu/menu_config_linux.cc",
+ "controls/menu/menu_config_mac.mm",
+ "controls/menu/menu_config_win.cc",
+ "controls/menu/menu_controller.cc",
+ "controls/menu/menu_controller.h",
+ "controls/menu/menu_controller_delegate.h",
+ "controls/menu/menu_delegate.cc",
+ "controls/menu/menu_delegate.h",
+ "controls/menu/menu_host.cc",
+ "controls/menu/menu_host.h",
+ "controls/menu/menu_host_root_view.cc",
+ "controls/menu/menu_host_root_view.h",
+ "controls/menu/menu_image_util.cc",
+ "controls/menu/menu_image_util.h",
+ "controls/menu/menu_insertion_delegate_win.h",
+ "controls/menu/menu_item_view.cc",
+ "controls/menu/menu_item_view.h",
+ "controls/menu/menu_listener.cc",
+ "controls/menu/menu_listener.h",
+ "controls/menu/menu_message_loop.h",
+ "controls/menu/menu_message_loop_mac.cc",
+ "controls/menu/menu_message_loop_mac.h",
+ "controls/menu/menu_model_adapter.cc",
+ "controls/menu/menu_model_adapter.h",
+ "controls/menu/menu_runner.cc",
+ "controls/menu/menu_runner.h",
+ "controls/menu/menu_runner_handler.h",
+ "controls/menu/menu_runner_impl.cc",
+ "controls/menu/menu_runner_impl.h",
+ "controls/menu/menu_runner_impl_adapter.cc",
+ "controls/menu/menu_runner_impl_adapter.h",
+ "controls/menu/menu_runner_impl_cocoa.h",
+ "controls/menu/menu_runner_impl_cocoa.mm",
+ "controls/menu/menu_runner_impl_interface.h",
+ "controls/menu/menu_scroll_view_container.cc",
+ "controls/menu/menu_scroll_view_container.h",
+ "controls/menu/menu_separator.h",
+ "controls/menu/menu_separator_views.cc",
+ "controls/menu/menu_separator_win.cc",
+ "controls/menu/menu_types.h",
+ "controls/menu/native_menu_win.cc",
+ "controls/menu/native_menu_win.h",
+ "controls/menu/submenu_view.cc",
+ "controls/menu/submenu_view.h",
+ "controls/message_box_view.cc",
+ "controls/message_box_view.h",
+ "controls/native/native_view_host.cc",
+ "controls/native/native_view_host.h",
+ "controls/native/native_view_host_mac.h",
+ "controls/native/native_view_host_mac.mm",
+ "controls/non_md_slider.cc",
+ "controls/non_md_slider.h",
+ "controls/prefix_delegate.h",
+ "controls/prefix_selector.cc",
+ "controls/prefix_selector.h",
+ "controls/progress_bar.cc",
+ "controls/progress_bar.h",
+ "controls/resize_area.cc",
+ "controls/resize_area.h",
+ "controls/resize_area_delegate.h",
+ "controls/scroll_view.cc",
+ "controls/scroll_view.h",
+ "controls/scrollbar/base_scroll_bar.cc",
+ "controls/scrollbar/base_scroll_bar.h",
+ "controls/scrollbar/base_scroll_bar_button.cc",
+ "controls/scrollbar/base_scroll_bar_button.h",
+ "controls/scrollbar/base_scroll_bar_thumb.cc",
+ "controls/scrollbar/base_scroll_bar_thumb.h",
+ "controls/scrollbar/cocoa_scroll_bar.h",
+ "controls/scrollbar/cocoa_scroll_bar.mm",
+ "controls/scrollbar/native_scroll_bar.cc",
+ "controls/scrollbar/native_scroll_bar.h",
+ "controls/scrollbar/native_scroll_bar_views.cc",
+ "controls/scrollbar/native_scroll_bar_views.h",
+ "controls/scrollbar/native_scroll_bar_wrapper.h",
+ "controls/scrollbar/overlay_scroll_bar.cc",
+ "controls/scrollbar/overlay_scroll_bar.h",
+ "controls/scrollbar/scroll_bar.cc",
+ "controls/scrollbar/scroll_bar.h",
+ "controls/separator.cc",
+ "controls/separator.h",
+ "controls/slide_out_view.cc",
+ "controls/slide_out_view.h",
+ "controls/slider.cc",
+ "controls/slider.h",
+ "controls/styled_label.cc",
+ "controls/styled_label.h",
+ "controls/styled_label_listener.h",
+ "controls/tabbed_pane/tabbed_pane.cc",
+ "controls/tabbed_pane/tabbed_pane.h",
+ "controls/tabbed_pane/tabbed_pane_listener.h",
+ "controls/table/table_header.cc",
+ "controls/table/table_header.h",
+ "controls/table/table_utils.cc",
+ "controls/table/table_utils.h",
+ "controls/table/table_view.cc",
+ "controls/table/table_view.h",
+ "controls/table/table_view_observer.h",
+ "controls/table/table_view_row_background_painter.h",
+ "controls/textfield/textfield.cc",
+ "controls/textfield/textfield.h",
+ "controls/textfield/textfield_controller.cc",
+ "controls/textfield/textfield_controller.h",
+ "controls/textfield/textfield_model.cc",
+ "controls/textfield/textfield_model.h",
+ "controls/throbber.cc",
+ "controls/throbber.h",
+ "controls/tree/tree_view.cc",
+ "controls/tree/tree_view.h",
+ "controls/tree/tree_view_controller.cc",
+ "controls/tree/tree_view_controller.h",
+ "debug_utils.cc",
+ "debug_utils.h",
+ "drag_controller.h",
+ "drag_utils.cc",
+ "drag_utils.h",
+ "drag_utils_mac.mm",
+ "event_monitor.h",
+ "event_monitor_mac.h",
+ "event_monitor_mac.mm",
+ "focus/external_focus_tracker.cc",
+ "focus/external_focus_tracker.h",
+ "focus/focus_manager.cc",
+ "focus/focus_manager.h",
+ "focus/focus_manager_delegate.h",
+ "focus/focus_manager_factory.cc",
+ "focus/focus_manager_factory.h",
+ "focus/focus_search.cc",
+ "focus/focus_search.h",
+ "focus/view_storage.cc",
+ "focus/view_storage.h",
+ "focus/widget_focus_manager.cc",
+ "focus/widget_focus_manager.h",
+ "layout/box_layout.cc",
+ "layout/box_layout.h",
+ "layout/fill_layout.cc",
+ "layout/fill_layout.h",
+ "layout/grid_layout.cc",
+ "layout/grid_layout.h",
+ "layout/layout_constants.h",
+ "layout/layout_manager.cc",
+ "layout/layout_manager.h",
+ "linux_ui/linux_ui.cc",
+ "linux_ui/linux_ui.h",
+ "linux_ui/status_icon_linux.cc",
+ "linux_ui/status_icon_linux.h",
+ "linux_ui/window_button_order_observer.h",
+ "linux_ui/window_button_order_provider.cc",
+ "masked_targeter_delegate.cc",
+ "masked_targeter_delegate.h",
+ "metrics.cc",
+ "metrics.h",
+ "metrics_mac.cc",
+ "mouse_constants.h",
+ "mouse_watcher.cc",
+ "mouse_watcher.h",
+ "mouse_watcher_view_host.cc",
+ "mouse_watcher_view_host.h",
+ "native_cursor.h",
+ "native_cursor_mac.mm",
+ "native_theme_delegate.h",
+ "painter.cc",
+ "painter.h",
+ "pointer_watcher.h",
+ "rect_based_targeting_utils.cc",
+ "rect_based_targeting_utils.h",
+ "repeat_controller.cc",
+ "repeat_controller.h",
+ "round_rect_painter.cc",
+ "round_rect_painter.h",
+ "shadow_border.cc",
+ "shadow_border.h",
+ "style/mac/combobox_background_mac.cc",
+ "style/mac/combobox_background_mac.h",
+ "style/platform_style.cc",
+ "style/platform_style.h",
+ "style/platform_style_mac.mm",
+ "view.cc",
+ "view.h",
+ "view_constants.cc",
+ "view_constants.h",
+ "view_model.cc",
+ "view_model.h",
+ "view_model_utils.cc",
+ "view_model_utils.h",
+ "view_targeter.cc",
+ "view_targeter.h",
+ "view_targeter_delegate.cc",
+ "view_targeter_delegate.h",
+ "views_delegate.cc",
+ "views_delegate.h",
+ "views_export.h",
+ "views_exports.cc",
+ "views_switches.cc",
+ "views_switches.h",
+ "views_touch_selection_controller_factory.h",
+ "views_touch_selection_controller_factory_mac.cc",
+ "widget/drop_helper.cc",
+ "widget/drop_helper.h",
+ "widget/monitor_win.cc",
+ "widget/monitor_win.h",
+ "widget/native_widget.h",
+ "widget/native_widget_delegate.h",
+ "widget/native_widget_mac.h",
+ "widget/native_widget_mac.mm",
+ "widget/native_widget_private.h",
+ "widget/root_view.cc",
+ "widget/root_view.h",
+ "widget/root_view_targeter.cc",
+ "widget/root_view_targeter.h",
+ "widget/tooltip_manager.cc",
+ "widget/tooltip_manager.h",
+ "widget/widget.cc",
+ "widget/widget.h",
+ "widget/widget_aura_utils.cc",
+ "widget/widget_aura_utils.h",
+ "widget/widget_delegate.cc",
+ "widget/widget_delegate.h",
+ "widget/widget_deletion_observer.cc",
+ "widget/widget_deletion_observer.h",
+ "widget/widget_observer.h",
+ "widget/widget_removals_observer.h",
+ "window/client_view.cc",
+ "window/client_view.h",
+ "window/custom_frame_view.cc",
+ "window/custom_frame_view.h",
+ "window/dialog_client_view.cc",
+ "window/dialog_client_view.h",
+ "window/dialog_delegate.cc",
+ "window/dialog_delegate.h",
+ "window/frame_background.cc",
+ "window/frame_background.h",
+ "window/frame_buttons.h",
+ "window/native_frame_view.cc",
+ "window/native_frame_view.h",
+ "window/non_client_view.cc",
+ "window/non_client_view.h",
+ "window/window_button_order_provider.cc",
+ "window/window_button_order_provider.h",
+ "window/window_resources.h",
+ "window/window_shape.cc",
+ "window/window_shape.h",
+ "word_lookup_client.h",
+ ]
configs += [
"//build/config:precompiled_headers",
@@ -36,6 +399,7 @@ component("views") {
"//ui/accessibility",
"//ui/display",
"//ui/native_theme",
+ "//ui/native_theme:native_theme_browser",
"//ui/resources",
"//ui/strings",
"//ui/views/resources",
@@ -81,7 +445,21 @@ component("views") {
}
if (is_win) {
- sources += gypi_values.views_win_sources
+ sources += [
+ "widget/widget_hwnd_utils.cc",
+ "widget/widget_hwnd_utils.h",
+ "win/fullscreen_handler.cc",
+ "win/fullscreen_handler.h",
+ "win/hwnd_message_handler.cc",
+ "win/hwnd_message_handler.h",
+ "win/hwnd_message_handler_delegate.h",
+ "win/hwnd_util.h",
+ "win/hwnd_util_aurawin.cc",
+ "win/scoped_fullscreen_visibility.cc",
+ "win/scoped_fullscreen_visibility.h",
+ "win/windows_session_change_observer.cc",
+ "win/windows_session_change_observer.h",
+ ]
libs = [
"dwmapi.lib",
"imm32.lib",
@@ -112,24 +490,136 @@ component("views") {
}
if (use_aura) {
- sources += gypi_values.views_aura_sources
+ sources += [
+ "accessibility/ax_aura_obj_cache.cc",
+ "accessibility/ax_aura_obj_cache.h",
+ "accessibility/ax_view_obj_wrapper.cc",
+ "accessibility/ax_view_obj_wrapper.h",
+ "accessibility/ax_widget_obj_wrapper.cc",
+ "accessibility/ax_widget_obj_wrapper.h",
+ "accessibility/ax_window_obj_wrapper.cc",
+ "accessibility/ax_window_obj_wrapper.h",
+ "bubble/bubble_window_targeter.cc",
+ "bubble/bubble_window_targeter.h",
+ "bubble/tray_bubble_view.cc",
+ "bubble/tray_bubble_view.h",
+ "controls/menu/display_change_listener_aura.cc",
+ "controls/menu/menu_message_loop_aura.cc",
+ "controls/menu/menu_message_loop_aura.h",
+ "controls/menu/menu_pre_target_handler.cc",
+ "controls/menu/menu_pre_target_handler.h",
+ "controls/native/native_view_host_aura.cc",
+ "controls/native/native_view_host_aura.h",
+ "corewm/cursor_height_provider_win.cc",
+ "corewm/cursor_height_provider_win.h",
+ "corewm/tooltip.h",
+ "corewm/tooltip_aura.cc",
+ "corewm/tooltip_aura.h",
+ "corewm/tooltip_controller.cc",
+ "corewm/tooltip_controller.h",
+ "corewm/tooltip_win.cc",
+ "corewm/tooltip_win.h",
+ "drag_utils_aura.cc",
+ "event_monitor_aura.cc",
+ "event_monitor_aura.h",
+ "metrics_aura.cc",
+ "native_cursor_aura.cc",
+ "touchui/touch_selection_controller_impl.cc",
+ "touchui/touch_selection_controller_impl.h",
+ "touchui/touch_selection_menu_runner_views.cc",
+ "touchui/touch_selection_menu_runner_views.h",
+ "view_constants_aura.cc",
+ "view_constants_aura.h",
+ "views_touch_selection_controller_factory_aura.cc",
+ "widget/focus_manager_event_handler.cc",
+ "widget/focus_manager_event_handler.h",
+ "widget/native_widget_aura.cc",
+ "widget/native_widget_aura.h",
+ "widget/tooltip_manager_aura.cc",
+ "widget/tooltip_manager_aura.h",
+ "widget/window_reorderer.cc",
+ "widget/window_reorderer.h",
+ ]
deps += [
"//ui/aura",
"//ui/touch_selection",
"//ui/wm",
]
if (!is_chromeos) {
- sources += gypi_values.views_desktop_aura_sources
+ sources += [
+ "widget/desktop_aura/desktop_capture_client.cc",
+ "widget/desktop_aura/desktop_capture_client.h",
+ "widget/desktop_aura/desktop_cursor_loader_updater.h",
+ "widget/desktop_aura/desktop_drop_target_win.cc",
+ "widget/desktop_aura/desktop_drop_target_win.h",
+ "widget/desktop_aura/desktop_event_client.cc",
+ "widget/desktop_aura/desktop_event_client.h",
+ "widget/desktop_aura/desktop_focus_rules.cc",
+ "widget/desktop_aura/desktop_focus_rules.h",
+ "widget/desktop_aura/desktop_native_cursor_manager.cc",
+ "widget/desktop_aura/desktop_native_cursor_manager.h",
+ "widget/desktop_aura/desktop_native_widget_aura.cc",
+ "widget/desktop_aura/desktop_native_widget_aura.h",
+ "widget/desktop_aura/desktop_screen.h",
+ "widget/desktop_aura/desktop_screen_position_client.cc",
+ "widget/desktop_aura/desktop_screen_position_client.h",
+ "widget/desktop_aura/desktop_window_tree_host.h",
+ ]
if (use_x11) {
- sources += gypi_values.views_desktop_aura_x11_sources
- configs += [ "//ui/accessibility:atk" ]
+ sources += [
+ "widget/desktop_aura/desktop_drag_drop_client_aurax11.cc",
+ "widget/desktop_aura/desktop_drag_drop_client_aurax11.h",
+ "widget/desktop_aura/desktop_screen_x11.cc",
+ "widget/desktop_aura/desktop_screen_x11.h",
+ "widget/desktop_aura/desktop_window_tree_host_x11.cc",
+ "widget/desktop_aura/desktop_window_tree_host_x11.h",
+ "widget/desktop_aura/x11_desktop_handler.cc",
+ "widget/desktop_aura/x11_desktop_handler.h",
+ "widget/desktop_aura/x11_desktop_handler_observer.h",
+ "widget/desktop_aura/x11_desktop_window_move_client.cc",
+ "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_pointer_grab.cc",
+ "widget/desktop_aura/x11_pointer_grab.h",
+ "widget/desktop_aura/x11_topmost_window_finder.cc",
+ "widget/desktop_aura/x11_topmost_window_finder.h",
+ "widget/desktop_aura/x11_whole_screen_move_loop.cc",
+ "widget/desktop_aura/x11_whole_screen_move_loop.h",
+ "widget/desktop_aura/x11_window_event_filter.cc",
+ "widget/desktop_aura/x11_window_event_filter.h",
+ ]
+ if (use_atk) {
+ sources += [
+ "accessibility/native_view_accessibility_auralinux.cc",
+ "accessibility/native_view_accessibility_auralinux.h",
+ ]
+ configs += [ "//build/config/linux/atk" ]
+ }
} else if (is_win) {
- sources += gypi_values.views_desktop_aura_win_sources
+ sources += [
+ "widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc",
+ "widget/desktop_aura/desktop_drag_drop_client_win.cc",
+ "widget/desktop_aura/desktop_drag_drop_client_win.h",
+ "widget/desktop_aura/desktop_screen_win.cc",
+ "widget/desktop_aura/desktop_screen_win.h",
+ "widget/desktop_aura/desktop_window_tree_host_win.cc",
+ "widget/desktop_aura/desktop_window_tree_host_win.h",
+ ]
} else if (use_ozone) {
- sources += gypi_values.views_desktop_aura_ozone_sources
+ sources += [
+ "widget/desktop_aura/desktop_factory_ozone.cc",
+ "widget/desktop_aura/desktop_factory_ozone.h",
+ "widget/desktop_aura/desktop_screen_ozone.cc",
+ "widget/desktop_aura/desktop_window_tree_host_ozone.cc",
+ ]
}
if (is_linux) {
- sources += gypi_values.views_desktop_aura_linux_sources
+ sources += [
+ "style/platform_style_linux.cc",
+ "widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc",
+ "widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h",
+ ]
}
}
}
@@ -141,7 +631,6 @@ component("views") {
]
libs = [
"AppKit.framework",
- "ApplicationServices.framework", # Temporary hack around https://crbug.com/620127. Remove after https://crbug.com/622481 is fixed.
"CoreGraphics.framework",
"Foundation.framework",
"QuartzCore.framework", # Required by bridged_native_widget.mm.
@@ -149,9 +638,75 @@ component("views") {
}
}
-source_set("test_support_internal") {
+static_library("test_support_internal") {
testonly = true
- sources = gypi_values.views_test_support_sources
+ sources = [
+ "animation/test/flood_fill_ink_drop_ripple_test_api.cc",
+ "animation/test/flood_fill_ink_drop_ripple_test_api.h",
+ "animation/test/ink_drop_highlight_test_api.cc",
+ "animation/test/ink_drop_highlight_test_api.h",
+ "animation/test/ink_drop_host_view_test_api.cc",
+ "animation/test/ink_drop_host_view_test_api.h",
+ "animation/test/ink_drop_impl_test_api.cc",
+ "animation/test/ink_drop_impl_test_api.h",
+ "animation/test/ink_drop_ripple_test_api.cc",
+ "animation/test/ink_drop_ripple_test_api.h",
+ "animation/test/ink_drop_utils.cc",
+ "animation/test/square_ink_drop_ripple_test_api.cc",
+ "animation/test/square_ink_drop_ripple_test_api.h",
+ "animation/test/test_ink_drop.cc",
+ "animation/test/test_ink_drop.h",
+ "animation/test/test_ink_drop_animation_observer_helper.h",
+ "animation/test/test_ink_drop_highlight_observer.cc",
+ "animation/test/test_ink_drop_highlight_observer.h",
+ "animation/test/test_ink_drop_host.cc",
+ "animation/test/test_ink_drop_host.h",
+ "animation/test/test_ink_drop_ripple_observer.cc",
+ "animation/test/test_ink_drop_ripple_observer.h",
+ "controls/textfield/textfield_test_api.cc",
+ "controls/textfield/textfield_test_api.h",
+ "test/capture_tracking_view.cc",
+ "test/capture_tracking_view.h",
+ "test/combobox_test_api.cc",
+ "test/combobox_test_api.h",
+ "test/desktop_test_views_delegate.h",
+ "test/desktop_test_views_delegate_mac.mm",
+ "test/event_generator_delegate_mac.h",
+ "test/event_generator_delegate_mac.mm",
+ "test/focus_manager_test.cc",
+ "test/focus_manager_test.h",
+ "test/menu_runner_test_api.cc",
+ "test/menu_runner_test_api.h",
+ "test/menu_test_utils.cc",
+ "test/menu_test_utils.h",
+ "test/native_widget_factory.cc",
+ "test/native_widget_factory.h",
+ "test/scoped_views_test_helper.cc",
+ "test/scoped_views_test_helper.h",
+ "test/slider_test_api.cc",
+ "test/slider_test_api.h",
+ "test/test_slider.cc",
+ "test/test_slider.h",
+ "test/test_views.cc",
+ "test/test_views.h",
+ "test/test_views_delegate.h",
+ "test/test_views_delegate_mac.mm",
+ "test/test_widget_observer.cc",
+ "test/test_widget_observer.h",
+ "test/views_test_base.cc",
+ "test/views_test_base.h",
+ "test/views_test_helper.cc",
+ "test/views_test_helper.h",
+ "test/views_test_helper_mac.h",
+ "test/views_test_helper_mac.mm",
+ "test/widget_test.cc",
+ "test/widget_test.h",
+ "test/widget_test_mac.mm",
+ "test/x11_property_change_waiter.cc",
+ "test/x11_property_change_waiter.h",
+ "views_test_suite.cc",
+ "views_test_suite.h",
+ ]
# External code should depend upon "test_support".
visibility = [ "./*" ]
@@ -187,19 +742,37 @@ source_set("test_support_internal") {
]
if (use_aura) {
- sources += gypi_values.views_test_support_aura_sources
+ sources += [
+ "corewm/tooltip_controller_test_helper.cc",
+ "corewm/tooltip_controller_test_helper.h",
+ "test/desktop_test_views_delegate_aura.cc",
+ "test/test_views_delegate_aura.cc",
+ "test/views_test_helper_aura.cc",
+ "test/views_test_helper_aura.h",
+ "test/widget_test_aura.cc",
+ ]
deps += [
"//ui/aura",
"//ui/aura:test_support",
"//ui/wm",
]
if (use_x11 && !is_chromeos) {
- sources += gypi_values.views_test_support_desktop_aura_x11_sources
+ sources += [
+ "test/desktop_screen_x11_test_api.cc",
+ "test/desktop_screen_x11_test_api.h",
+ "test/test_desktop_screen_x11.cc",
+ "test/test_desktop_screen_x11.h",
+ "test/ui_controls_factory_desktop_aurax11.cc",
+ "test/ui_controls_factory_desktop_aurax11.h",
+ ]
}
}
if (use_x11) {
deps += [ "//ui/gfx/x" ]
}
+ if (ozone_platform_x11) {
+ deps += [ "//ui/base/x" ]
+ }
if (use_ozone || !use_x11) {
sources -= [
"test/x11_property_change_waiter.cc",
@@ -218,10 +791,85 @@ static_library("test_support") {
]
}
-test("views_unittests") {
- sources = gypi_values.views_unittests_sources
+# This target contains the unit tests that are shared between views_unittests
+# and views_mus_unittests.
+source_set("views_unittests_sources") {
+ testonly = true
+ sources = [
+ "accessibility/native_view_accessibility_unittest.cc",
+ "accessibility/native_view_accessibility_win_unittest.cc",
+ "accessible_pane_view_unittest.cc",
+ "animation/bounds_animator_unittest.cc",
+ "animation/flood_fill_ink_drop_ripple_unittest.cc",
+ "animation/ink_drop_highlight_unittest.cc",
+ "animation/ink_drop_host_view_unittest.cc",
+ "animation/ink_drop_impl_unittest.cc",
+ "animation/ink_drop_ripple_unittest.cc",
+ "animation/ink_drop_unittest.cc",
+ "animation/square_ink_drop_ripple_unittest.cc",
+ "border_unittest.cc",
+ "bubble/bubble_border_unittest.cc",
+ "bubble/bubble_dialog_delegate_unittest.cc",
+ "bubble/bubble_frame_view_unittest.cc",
+ "bubble/bubble_window_targeter_unittest.cc",
+ "cocoa/bridged_native_widget_unittest.mm",
+ "cocoa/cocoa_mouse_capture_unittest.mm",
+ "cocoa/drag_drop_client_mac_unittest.mm",
+ "controls/button/blue_button_unittest.cc",
+ "controls/button/custom_button_unittest.cc",
+ "controls/button/image_button_unittest.cc",
+ "controls/button/label_button_unittest.cc",
+ "controls/button/menu_button_unittest.cc",
+ "controls/combobox/combobox_unittest.cc",
+ "controls/label_unittest.cc",
+ "controls/menu/menu_controller_unittest.cc",
+ "controls/menu/menu_item_view_unittest.cc",
+ "controls/menu/menu_model_adapter_unittest.cc",
+ "controls/menu/menu_runner_cocoa_unittest.mm",
+ "controls/menu/menu_runner_unittest.cc",
+ "controls/native/native_view_host_mac_unittest.mm",
+ "controls/native/native_view_host_test_base.cc",
+ "controls/native/native_view_host_test_base.h",
+ "controls/native/native_view_host_unittest.cc",
+ "controls/prefix_selector_unittest.cc",
+ "controls/progress_bar_unittest.cc",
+ "controls/scroll_view_unittest.cc",
+ "controls/scrollbar/scrollbar_unittest.cc",
+ "controls/slider_unittest.cc",
+ "controls/styled_label_unittest.cc",
+ "controls/tabbed_pane/tabbed_pane_unittest.cc",
+ "controls/table/table_utils_unittest.cc",
+ "controls/table/table_view_unittest.cc",
+ "controls/table/test_table_model.cc",
+ "controls/table/test_table_model.h",
+ "controls/textfield/textfield_model_unittest.cc",
+ "controls/tree/tree_view_unittest.cc",
+ "event_monitor_unittest.cc",
+ "focus/focus_manager_unittest.cc",
+ "focus/focus_traversal_unittest.cc",
+ "layout/box_layout_unittest.cc",
+ "layout/grid_layout_unittest.cc",
+ "rect_based_targeting_utils_unittest.cc",
+ "view_model_unittest.cc",
+ "view_model_utils_unittest.cc",
+ "view_targeter_unittest.cc",
+ "view_unittest.cc",
+ "widget/native_widget_mac_accessibility_unittest.mm",
+ "widget/native_widget_mac_unittest.mm",
+ "widget/native_widget_unittest.cc",
+ "widget/root_view_unittest.cc",
+ "widget/widget_unittest.cc",
+ "widget/window_reorderer_unittest.cc",
+ "window/custom_frame_view_unittest.cc",
+ "window/dialog_client_view_unittest.cc",
+ "window/dialog_delegate_unittest.cc",
+ ]
- deps = [
+ configs += [ "//build/config:precompiled_headers" ]
+
+ # Make all deps in this target public so both views_unittests and
+ # views_mus_unittests will get them.
+ public_deps = [
":test_support",
"//base",
"//base:i18n",
@@ -254,7 +902,7 @@ test("views_unittests") {
]
if (is_win) {
- deps += [
+ public_deps += [
"//build/win:default_exe_manifest",
"//third_party/iaccessible2",
"//third_party/wtl",
@@ -271,7 +919,7 @@ test("views_unittests") {
"//build/config/linux:x11",
"//build/config/linux:xext",
]
- deps += [
+ public_deps += [
"//ui/events/devices",
"//ui/events/platform/x11",
"//ui/gfx/x",
@@ -279,23 +927,19 @@ test("views_unittests") {
}
if (use_aura) {
- sources += gypi_values.views_unittests_aura_sources
- deps += [
+ sources += [
+ "accessibility/ax_aura_obj_cache_unittest.cc",
+ "controls/native/native_view_host_aura_unittest.cc",
+ "touchui/touch_selection_menu_runner_views_unittest.cc",
+ "view_unittest_aura.cc",
+ "widget/native_widget_aura_unittest.cc",
+ ]
+ public_deps += [
"//ui/aura",
"//ui/aura:test_support",
"//ui/touch_selection",
"//ui/wm",
]
- if (!is_chromeos) {
- sources += gypi_values.views_unittests_desktop_aura_sources
- if (use_x11) {
- sources += gypi_values.views_unittests_desktop_aurax11_sources
- }
- }
- }
-
- if (!is_chromeos) {
- sources += gypi_values.views_unittests_desktop_sources
}
if (is_mac) {
@@ -305,10 +949,53 @@ test("views_unittests") {
"controls/native/native_view_host_unittest.cc",
"widget/window_reorderer_unittest.cc",
]
- deps += [ "//ui/accelerated_widget_mac" ]
+ public_deps += [ "//ui/accelerated_widget_mac" ]
}
}
+test("views_unittests") {
+ sources = [
+ "run_all_unittests_main.cc",
+
+ # EventGenerator doesn't work well with IME in mus so this must not be in
+ # the shared unit test sources.
+ # crbug.com/615033 crbug.com/548407
+ "controls/textfield/textfield_unittest.cc",
+ ]
+
+ if (use_aura) {
+ sources += [
+ # Tooltips. Can not be shared with mus: crbug.com/599558
+ "corewm/tooltip_controller_unittest.cc",
+
+ # Some of the tests need drag-drop support. crbug.com/614037
+ "touchui/touch_selection_controller_impl_unittest.cc",
+ ]
+
+ if (!is_chromeos) {
+ sources += [
+ "widget/desktop_aura/desktop_focus_rules_unittest.cc",
+ "widget/desktop_aura/desktop_native_widget_aura_unittest.cc",
+ ]
+ if (use_x11) {
+ sources += [
+ "widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc",
+ "widget/desktop_aura/desktop_screen_x11_unittest.cc",
+ "widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc",
+ ]
+ }
+ }
+ }
+
+ if (!is_chromeos) {
+ sources += [ "widget/desktop_widget_unittest.cc" ]
+ }
+
+ deps = [
+ ":views_unittests_sources",
+ ]
+}
+
if (is_mac) {
test("macviews_interactive_ui_tests") {
sources = [
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
index 9bd021e1d00..0f47bb4b674 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -4,8 +4,8 @@
#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
-#include "base/stl_util.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
@@ -74,17 +74,21 @@ void AXAuraObjCache::Remove(Widget* widget) {
RemoveViewSubtree(widget->GetRootView());
}
-void AXAuraObjCache::Remove(aura::Window* window) {
+void AXAuraObjCache::Remove(aura::Window* window, aura::Window* parent) {
+ int id = GetIDInternal(parent, window_to_id_map_);
+ AXAuraObjWrapper* parent_window_obj = Get(id);
RemoveInternal(window, window_to_id_map_);
+ if (parent && delegate_)
+ delegate_->OnChildWindowRemoved(parent_window_obj);
}
AXAuraObjWrapper* AXAuraObjCache::Get(int32_t id) {
- std::map<int32_t, AXAuraObjWrapper*>::iterator it = cache_.find(id);
+ auto it = cache_.find(id);
if (it == cache_.end())
- return NULL;
+ return nullptr;
- return it->second;
+ return it->second.get();
}
void AXAuraObjCache::Remove(int32_t id) {
@@ -94,14 +98,12 @@ void AXAuraObjCache::Remove(int32_t id) {
return;
cache_.erase(id);
- delete obj;
}
void AXAuraObjCache::GetTopLevelWindows(
std::vector<AXAuraObjWrapper*>* children) {
- for (std::map<aura::Window*, int32_t>::iterator it =
- window_to_id_map_.begin();
- it != window_to_id_map_.end(); ++it) {
+ for (auto it = window_to_id_map_.begin(); it != window_to_id_map_.end();
+ ++it) {
if (!it->first->parent())
children->push_back(GetOrCreate(it->first));
}
@@ -117,12 +119,11 @@ AXAuraObjWrapper* AXAuraObjCache::GetFocus() {
AXAuraObjCache::AXAuraObjCache()
: current_id_(1),
focus_client_(nullptr),
- is_destroying_(false) {
-}
+ is_destroying_(false),
+ delegate_(nullptr) {}
AXAuraObjCache::~AXAuraObjCache() {
is_destroying_ = true;
- STLDeleteContainerPairSecondPointers(cache_.begin(), cache_.end());
cache_.clear();
}
@@ -169,17 +170,16 @@ AXAuraObjWrapper* AXAuraObjCache::CreateInternal(
AuraView* aura_view,
std::map<AuraView*, int32_t>& aura_view_to_id_map) {
if (!aura_view)
- return NULL;
+ return nullptr;
- typename std::map<AuraView*, int32_t>::iterator it =
- aura_view_to_id_map.find(aura_view);
+ auto it = aura_view_to_id_map.find(aura_view);
if (it != aura_view_to_id_map.end())
return Get(it->second);
AXAuraObjWrapper* wrapper = new AuraViewWrapper(aura_view);
aura_view_to_id_map[aura_view] = current_id_;
- cache_[current_id_] = wrapper;
+ cache_[current_id_] = base::WrapUnique(wrapper);
current_id_++;
return wrapper;
}
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.h b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
index 763f8f99171..fc9a8c91352 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <map>
+#include <memory>
#include <vector>
#include "base/macros.h"
@@ -39,6 +40,11 @@ class VIEWS_EXPORT AXAuraObjCache
// Get the single instance of this class.
static AXAuraObjCache* GetInstance();
+ class Delegate {
+ public:
+ virtual void OnChildWindowRemoved(AXAuraObjWrapper* parent) = 0;
+ };
+
// Get or create an entry in the cache based on an Aura view.
AXAuraObjWrapper* GetOrCreate(View* view);
AXAuraObjWrapper* GetOrCreate(Widget* widget);
@@ -56,7 +62,10 @@ class VIEWS_EXPORT AXAuraObjCache
// Removes an entry from this cache based on an Aura view.
void Remove(View* view);
void Remove(Widget* widget);
- void Remove(aura::Window* window);
+
+ // Removes |window| and optionally notifies delegate by sending an event on
+ // the |parent| if provided.
+ void Remove(aura::Window* window, aura::Window* parent);
// Removes a view and all of its descendants from the cache.
void RemoveViewSubtree(View* view);
@@ -76,6 +85,8 @@ class VIEWS_EXPORT AXAuraObjCache
// Indicates if this object's currently being destroyed.
bool is_destroying() { return is_destroying_; }
+ void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
+
private:
friend struct base::DefaultSingletonTraits<AXAuraObjCache>;
@@ -109,7 +120,7 @@ class VIEWS_EXPORT AXAuraObjCache
std::map<views::Widget*, int32_t> widget_to_id_map_;
std::map<aura::Window*, int32_t> window_to_id_map_;
- std::map<int32_t, AXAuraObjWrapper*> cache_;
+ std::map<int32_t, std::unique_ptr<AXAuraObjWrapper>> cache_;
int32_t current_id_;
aura::client::FocusClient* focus_client_;
@@ -117,6 +128,8 @@ class VIEWS_EXPORT AXAuraObjCache
// True immediately when entering this object's destructor.
bool is_destroying_;
+ Delegate* delegate_;
+
DISALLOW_COPY_AND_ASSIGN(AXAuraObjCache);
};
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
index 3ea1e04efb2..b043dedc504 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -58,7 +58,7 @@ void AXViewObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
if (!view_->visible())
out_node_data->state |= 1 << ui::AX_STATE_INVISIBLE;
- out_node_data->location = view_->GetBoundsInScreen();
+ out_node_data->location = gfx::RectF(view_->GetBoundsInScreen());
out_node_data->AddStringAttribute(
ui::AX_ATTR_NAME, base::UTF16ToUTF8(view_data.name));
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
index adba19f7a17..2a05b196651 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -46,7 +46,7 @@ void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
ui::AX_ATTR_NAME,
base::UTF16ToUTF8(
widget_->widget_delegate()->GetAccessibleWindowTitle()));
- out_node_data->location = widget_->GetWindowBoundsInScreen();
+ out_node_data->location = gfx::RectF(widget_->GetWindowBoundsInScreen());
out_node_data->state = 0;
}
@@ -58,6 +58,10 @@ void AXWidgetObjWrapper::OnWidgetDestroying(Widget* widget) {
AXAuraObjCache::GetInstance()->Remove(widget);
}
+void AXWidgetObjWrapper::OnWidgetClosing(Widget* widget) {
+ AXAuraObjCache::GetInstance()->Remove(widget);
+}
+
void AXWidgetObjWrapper::OnWillRemoveView(Widget* widget, View* view) {
AXAuraObjCache::GetInstance()->RemoveViewSubtree(view);
}
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
index 4913581b699..244fca50176 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -31,6 +31,7 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
// WidgetObserver overrides.
void OnWidgetDestroying(Widget* widget) override;
+ void OnWidgetClosing(Widget* widget) override;
// WidgetRemovalsObserver overrides.
void OnWillRemoveView(Widget* widget, View* view) override;
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index 5b6f226ea35..7117443cc5c 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -53,7 +53,7 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
out_node_data->AddStringAttribute(ui::AX_ATTR_NAME,
base::UTF16ToUTF8(window_->title()));
out_node_data->state = 0;
- out_node_data->location = window_->bounds();
+ out_node_data->location = gfx::RectF(window_->bounds());
}
int32_t AXWindowObjWrapper::GetID() {
@@ -61,7 +61,19 @@ int32_t AXWindowObjWrapper::GetID() {
}
void AXWindowObjWrapper::OnWindowDestroyed(aura::Window* window) {
- AXAuraObjCache::GetInstance()->Remove(window);
+ AXAuraObjCache::GetInstance()->Remove(window, nullptr);
+}
+
+void AXWindowObjWrapper::OnWindowDestroying(aura::Window* window) {
+ Widget* widget = Widget::GetWidgetForNativeView(window);
+ if (widget)
+ AXAuraObjCache::GetInstance()->Remove(widget);
+}
+
+void AXWindowObjWrapper::OnWindowHierarchyChanged(
+ const HierarchyChangeParams& params) {
+ if (params.phase == WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED)
+ AXAuraObjCache::GetInstance()->Remove(params.target, params.old_parent);
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
index bcf35481d73..5a949c722f9 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -38,6 +38,8 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
// WindowObserver overrides.
void OnWindowDestroyed(aura::Window* window) override;
+ void OnWindowDestroying(aura::Window* window) override;
+ void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
private:
aura::Window* window_;
diff --git a/chromium/ui/views/accessibility/native_view_accessibility.cc b/chromium/ui/views/accessibility/native_view_accessibility.cc
index 0cdec0d1503..a984c3c6c08 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility.cc
@@ -8,6 +8,7 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/events/event_utils.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -51,12 +52,21 @@ void NativeViewAccessibility::NotifyAccessibilityEvent(ui::AXEvent event_type) {
// ui::AXPlatformNodeDelegate
const ui::AXNodeData& NativeViewAccessibility::GetData() {
+ data_ = ui::AXNodeData();
+
+ // Views may misbehave if their widget is closed; return an unknown role
+ // rather than possibly crashing.
+ if (!view_->GetWidget() || view_->GetWidget()->IsClosed()) {
+ data_.role = ui::AX_ROLE_UNKNOWN;
+ data_.state = 1 << ui::AX_STATE_DISABLED;
+ return data_;
+ }
+
ui::AXViewState state;
view_->GetAccessibleState(&state);
- data_ = ui::AXNodeData();
data_.role = state.role;
data_.state = state.state();
- data_.location = view_->GetBoundsInScreen();
+ data_.location = gfx::RectF(view_->GetBoundsInScreen());
data_.AddStringAttribute(ui::AX_ATTR_NAME, base::UTF16ToUTF8(state.name));
data_.AddStringAttribute(ui::AX_ATTR_VALUE, base::UTF16ToUTF8(state.value));
data_.AddStringAttribute(ui::AX_ATTR_ACTION,
@@ -65,6 +75,12 @@ const ui::AXNodeData& NativeViewAccessibility::GetData() {
base::UTF16ToUTF8(state.keyboard_shortcut));
data_.AddStringAttribute(ui::AX_ATTR_PLACEHOLDER,
base::UTF16ToUTF8(state.placeholder));
+
+ if (state.description.empty() &&
+ view_->GetTooltipText(gfx::Point(), &state.description))
+ data_.AddStringAttribute(ui::AX_ATTR_DESCRIPTION,
+ base::UTF16ToUTF8(state.description));
+
data_.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, state.selection_start);
data_.AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, state.selection_end);
@@ -105,6 +121,12 @@ gfx::NativeViewAccessible NativeViewAccessibility::ChildAtIndex(int index) {
return nullptr;
}
+gfx::NativeWindow NativeViewAccessibility::GetTopLevelWidget() {
+ if (view_->GetWidget())
+ return view_->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
+ return nullptr;
+}
+
gfx::NativeViewAccessible NativeViewAccessibility::GetParent() {
if (view_->parent())
return view_->parent()->GetNativeViewAccessible();
@@ -193,15 +215,22 @@ void NativeViewAccessibility::DoDefaultAction() {
bool NativeViewAccessibility::SetStringValue(const base::string16& new_value) {
// Return an error if the view can't set the value.
- ui::AXViewState state;
- view_->GetAccessibleState(&state);
- if (state.set_value_callback.is_null())
+ if (!CanSetStringValue())
return false;
+ ui::AXViewState state;
+ view_->GetAccessibleState(&state);
state.set_value_callback.Run(new_value);
return true;
}
+bool NativeViewAccessibility::CanSetStringValue() {
+ ui::AXViewState state;
+ view_->GetAccessibleState(&state);
+ return !ui::AXViewState::IsFlagSet(GetData().state, ui::AX_STATE_READ_ONLY) &&
+ !state.set_value_callback.is_null();
+}
+
void NativeViewAccessibility::OnWidgetDestroying(Widget* widget) {
if (parent_widget_ == widget) {
parent_widget_->RemoveObserver(this);
diff --git a/chromium/ui/views/accessibility/native_view_accessibility.h b/chromium/ui/views/accessibility/native_view_accessibility.h
index ac59130bace..95fcc3de365 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility.h
+++ b/chromium/ui/views/accessibility/native_view_accessibility.h
@@ -49,6 +49,7 @@ class VIEWS_EXPORT NativeViewAccessibility
const ui::AXNodeData& GetData() override;
int GetChildCount() override;
gfx::NativeViewAccessible ChildAtIndex(int index) override;
+ gfx::NativeWindow GetTopLevelWidget() override;
gfx::NativeViewAccessible GetParent() override;
gfx::Vector2d GetGlobalCoordinateOffset() override;
gfx::NativeViewAccessible HitTestSync(int x, int y) override;
@@ -56,6 +57,7 @@ class VIEWS_EXPORT NativeViewAccessibility
gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
void DoDefaultAction() override;
bool SetStringValue(const base::string16& new_value) override;
+ bool CanSetStringValue() override;
// WidgetObserver
void OnWidgetDestroying(Widget* widget) override;
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc b/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc
index 90927af368d..8e68cc00bff 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -46,7 +46,7 @@ class AuraLinuxApplication
return;
widget = widget->GetTopLevelWidget();
- if (ContainsValue(widgets_, widget))
+ if (base::ContainsValue(widgets_, widget))
return;
widgets_.push_back(widget);
@@ -57,9 +57,7 @@ class AuraLinuxApplication
return platform_node_->GetNativeViewAccessible();
}
- //
- // WidgetObserver overrides.
- //
+ // WidgetObserver:
void OnWidgetDestroying(Widget* widget) override {
auto iter = std::find(widgets_.begin(), widgets_.end(), widget);
@@ -67,14 +65,14 @@ class AuraLinuxApplication
widgets_.erase(iter);
}
- //
- // ui::AXPlatformNodeDelegate overrides.
- //
+ // ui::AXPlatformNodeDelegate:
const ui::AXNodeData& GetData() override {
return data_;
}
+ gfx::NativeWindow GetTopLevelWidget() override { return nullptr; }
+
gfx::NativeViewAccessible GetParent() override {
return nullptr;
}
@@ -115,6 +113,8 @@ class AuraLinuxApplication
return false;
}
+ bool CanSetStringValue() override { return false; }
+
private:
friend struct base::DefaultSingletonTraits<AuraLinuxApplication>;
diff --git a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc
index a60b1cb6b95..37435e205a1 100644
--- a/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc
+++ b/chromium/ui/views/accessibility/native_view_accessibility_unittest.cc
@@ -4,6 +4,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_view_state.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/views/accessibility/native_view_accessibility.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h"
@@ -30,16 +31,27 @@ class NativeViewAccessibilityTest : public ViewsTestBase {
void SetUp() override {
ViewsTestBase::SetUp();
- button_.reset(new TestButton());
+
+ widget_ = new views::Widget;
+ views::Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ widget_->Init(params);
+
+ button_ = new TestButton();
button_->SetSize(gfx::Size(20, 20));
- button_accessibility_ = NativeViewAccessibility::Create(button_.get());
+ button_accessibility_ = NativeViewAccessibility::Create(button_);
+
+ label_ = new Label();
+ button_->AddChildView(label_);
+ label_accessibility_ = NativeViewAccessibility::Create(label_);
- label_.reset(new Label);
- button_->AddChildView(label_.get());
- label_accessibility_ = NativeViewAccessibility::Create(label_.get());
+ widget_->SetContentsView(button_);
}
void TearDown() override {
+ if (!widget_->IsClosed())
+ widget_->Close();
button_accessibility_->Destroy();
button_accessibility_ = NULL;
label_accessibility_->Destroy();
@@ -48,9 +60,10 @@ class NativeViewAccessibilityTest : public ViewsTestBase {
}
protected:
- std::unique_ptr<TestButton> button_;
+ views::Widget* widget_;
+ TestButton* button_;
NativeViewAccessibility* button_accessibility_;
- std::unique_ptr<Label> label_;
+ Label* label_;
NativeViewAccessibility* label_accessibility_;
};
@@ -60,7 +73,8 @@ TEST_F(NativeViewAccessibilityTest, RoleShouldMatch) {
}
TEST_F(NativeViewAccessibilityTest, BoundsShouldMatch) {
- gfx::Rect bounds = button_accessibility_->GetData().location;
+ gfx::Rect bounds = gfx::ToEnclosingRect(
+ button_accessibility_->GetData().location);
bounds.Offset(button_accessibility_->GetGlobalCoordinateOffset());
EXPECT_EQ(button_->GetBoundsInScreen(), bounds);
}
diff --git a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc
index 3bad83e4262..e69de79a2ef 100644
--- a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc
+++ b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc
@@ -153,8 +153,8 @@ ui::Layer* FloodFillInkDropRipple::GetRootLayer() {
return &root_layer_;
}
-bool FloodFillInkDropRipple::IsVisible() const {
- return root_layer_.visible();
+bool FloodFillInkDropRipple::OverridesHighlight() const {
+ return false;
}
void FloodFillInkDropRipple::AnimateStateChange(
diff --git a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h
index bad8cd79aea..89b38db158c 100644
--- a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h
+++ b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h
@@ -57,7 +57,7 @@ class VIEWS_EXPORT FloodFillInkDropRipple : public InkDropRipple {
// InkDropRipple:
void SnapToActivated() override;
ui::Layer* GetRootLayer() override;
- bool IsVisible() const override;
+ bool OverridesHighlight() const override;
private:
friend class test::FloodFillInkDropRippleTestApi;
diff --git a/chromium/ui/views/animation/ink_drop_highlight.cc b/chromium/ui/views/animation/ink_drop_highlight.cc
index 32f1231dbc7..d2077b16c32 100644
--- a/chromium/ui/views/animation/ink_drop_highlight.cc
+++ b/chromium/ui/views/animation/ink_drop_highlight.cc
@@ -66,7 +66,11 @@ InkDropHighlight::InkDropHighlight(const gfx::Size& size,
layer_->SetOpacity(visible_opacity_);
}
-InkDropHighlight::~InkDropHighlight() {}
+InkDropHighlight::~InkDropHighlight() {
+ // Explicitly aborting all the animations ensures all callbacks are invoked
+ // while this instance still exists.
+ layer_->GetAnimator()->AbortAllAnimations();
+}
bool InkDropHighlight::IsFadingInOrVisible() const {
return last_animation_initiated_was_fade_in_;
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index 2c6ffe2b2a0..89f320d2a50 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -44,22 +44,22 @@ const int InkDropHostView::kInkDropSmallCornerRadius = 2;
// TODO(bruthig): Consider getting rid of this class.
class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
public:
- InkDropGestureHandler(InkDropHostView* host_view, InkDrop* ink_drop)
+ explicit InkDropGestureHandler(InkDropHostView* host_view)
: target_handler_(new ui::ScopedTargetHandler(host_view, this)),
- host_view_(host_view),
- ink_drop_(ink_drop) {}
+ host_view_(host_view) {}
~InkDropGestureHandler() override {}
- void SetInkDrop(InkDrop* ink_drop) { ink_drop_ = ink_drop; }
-
// ui::EventHandler:
void OnGestureEvent(ui::GestureEvent* event) override {
- InkDropState current_ink_drop_state = ink_drop_->GetTargetInkDropState();
+ InkDropState current_ink_drop_state =
+ host_view_->ink_drop()->GetTargetInkDropState();
InkDropState ink_drop_state = InkDropState::HIDDEN;
switch (event->type()) {
case ui::ET_GESTURE_TAP_DOWN:
+ if (current_ink_drop_state == InkDropState::ACTIVATED)
+ return;
ink_drop_state = InkDropState::ACTION_PENDING;
// The ui::ET_GESTURE_TAP_DOWN event needs to be marked as handled so
// that
@@ -67,16 +67,17 @@ class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
event->SetHandled();
break;
case ui::ET_GESTURE_LONG_PRESS:
+ if (current_ink_drop_state == InkDropState::ACTIVATED)
+ return;
ink_drop_state = InkDropState::ALTERNATE_ACTION_PENDING;
break;
case ui::ET_GESTURE_LONG_TAP:
ink_drop_state = InkDropState::ALTERNATE_ACTION_TRIGGERED;
break;
case ui::ET_GESTURE_END:
+ case ui::ET_GESTURE_SCROLL_BEGIN:
if (current_ink_drop_state == InkDropState::ACTIVATED)
return;
- // Fall through to ui::ET_GESTURE_SCROLL_BEGIN case.
- case ui::ET_GESTURE_SCROLL_BEGIN:
ink_drop_state = InkDropState::HIDDEN;
break;
default:
@@ -102,9 +103,6 @@ class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
// The host view to cache ui::Events to when animating the ink drop.
InkDropHostView* host_view_;
- // Animation controller for the ink drop ripple effect.
- InkDrop* ink_drop_;
-
DISALLOW_COPY_AND_ASSIGN(InkDropGestureHandler);
};
@@ -235,17 +233,16 @@ bool InkDropHostView::ShouldShowInkDropForFocus() const {
return false;
}
-void InkDropHostView::SetHasInkDrop(bool has_an_ink_drop) {
- if (has_an_ink_drop) {
+void InkDropHostView::SetInkDropMode(InkDropMode ink_drop_mode) {
+ if (ink_drop_mode == InkDropMode::OFF)
+ ink_drop_.reset(new InkDropStub());
+ else
ink_drop_.reset(new InkDropImpl(this));
- if (!gesture_handler_)
- gesture_handler_.reset(new InkDropGestureHandler(this, ink_drop_.get()));
- else
- gesture_handler_->SetInkDrop(ink_drop_.get());
- } else {
+
+ if (ink_drop_mode != InkDropMode::ON)
gesture_handler_.reset();
- ink_drop_.reset(new InkDropStub());
- }
+ else if (!gesture_handler_)
+ gesture_handler_.reset(new InkDropGestureHandler(this));
}
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h
index 030faa810d1..2f30b24b3b7 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.h
+++ b/chromium/ui/views/animation/ink_drop_host_view.h
@@ -38,6 +38,16 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
void set_ink_drop_size(const gfx::Size& size) { ink_drop_size_ = size; }
protected:
+ // Used in SetInkDropMode() to specify whether the ink drop effect is enabled
+ // or not for the view. In case of having an ink drop, it also specifies
+ // whether the default gesture event handler for the ink drop should be
+ // installed or the subclass will handle gesture events itself.
+ enum class InkDropMode {
+ OFF,
+ ON,
+ ON_NO_GESTURE_HANDLER,
+ };
+
static const int kInkDropSmallCornerRadius;
void set_ink_drop_visible_opacity(float visible_opacity) {
@@ -84,7 +94,7 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
// Toggle to enable/disable an InkDrop on this View. Descendants can override
// CreateInkDropHighlight() and CreateInkDropRipple() to change the look/feel
// of the InkDrop.
- void SetHasInkDrop(bool has_an_ink_drop);
+ void SetInkDropMode(InkDropMode ink_drop_mode);
private:
class InkDropGestureHandler;
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 b0cf3116379..4526a11a4d6 100644
--- a/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
@@ -16,6 +16,7 @@
namespace views {
namespace test {
+using InkDropMode = InkDropHostViewTestApi::InkDropMode;
class InkDropHostViewColor : public InkDropHostView {
protected:
@@ -65,17 +66,21 @@ TEST_F(InkDropHostViewTest, GetInkDropCenterBasedOnLastEventForLocatedEvent) {
EXPECT_EQ(gfx::Point(5, 6), test_api_.GetInkDropCenterBasedOnLastEvent());
}
-// Verifies that SetHasInkDrop() sets up gesture handling properly.
-TEST_F(InkDropHostViewTest, SetHasInkDropGestureHandler) {
+// Verifies that SetInkDropMode() sets up gesture handling properly.
+TEST_F(InkDropHostViewTest, SetInkDropModeGestureHandler) {
EXPECT_FALSE(test_api_.HasGestureHandler());
- test_api_.SetHasInkDrop(true);
+ test_api_.SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
+ EXPECT_FALSE(test_api_.HasGestureHandler());
+
+ test_api_.SetInkDropMode(InkDropMode::ON);
EXPECT_TRUE(test_api_.HasGestureHandler());
- test_api_.SetHasInkDrop(true);
+ // Enabling gesture handler the second time should just work (no crash).
+ test_api_.SetInkDropMode(InkDropMode::ON);
EXPECT_TRUE(test_api_.HasGestureHandler());
- test_api_.SetHasInkDrop(false);
+ test_api_.SetInkDropMode(InkDropMode::OFF);
EXPECT_FALSE(test_api_.HasGestureHandler());
}
@@ -83,7 +88,7 @@ TEST_F(InkDropHostViewTest, SetHasInkDropGestureHandler) {
TEST_F(InkDropHostViewTest, NoInkDropOnTouchOrGestureEvents) {
host_view_.SetSize(gfx::Size(20, 20));
- test_api_.SetHasInkDrop(true);
+ test_api_.SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
// Ensure the target ink drop is in the expected state.
EXPECT_EQ(test_api_.ink_drop()->GetTargetInkDropState(),
@@ -117,7 +122,7 @@ TEST_F(InkDropHostViewTest, NoInkDropOnTouchOrGestureEvents) {
TEST_F(InkDropHostViewTest, DismissInkDropOnTouchOrGestureEvents) {
host_view_.SetSize(gfx::Size(20, 20));
- test_api_.SetHasInkDrop(true);
+ test_api_.SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
// Ensure the target ink drop is in the expected state.
EXPECT_EQ(test_api_.ink_drop()->GetTargetInkDropState(),
diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc
index cde9818ce5d..9d65896d284 100644
--- a/chromium/ui/views/animation/ink_drop_impl.cc
+++ b/chromium/ui/views/animation/ink_drop_impl.cc
@@ -17,23 +17,23 @@ namespace {
// The duration, in milliseconds, of the highlight state fade in animation when
// it is triggered by user input.
-const int kHighlightFadeInFromUserInputDurationInMs = 250;
+const int kHighlightFadeInFromUserInputDurationMs = 250;
// The duration, in milliseconds, of the highlight state fade out animation when
// it is triggered by user input.
-const int kHighlightFadeOutFromUserInputDurationInMs = 250;
+const int kHighlightFadeOutFromUserInputDurationMs = 250;
// The duration, in milliseconds, of the highlight state fade in animation when
// it is triggered by an ink drop ripple animation ending.
-const int kHighlightFadeInAfterRippleDurationInMs = 250;
+const int kHighlightFadeInAfterRippleDurationMs = 250;
// The duration, in milliseconds, of the highlight state fade out animation when
// it is triggered by an ink drop ripple animation starting.
-const int kHighlightFadeOutBeforeRippleDurationInMs = 120;
+const int kHighlightFadeOutBeforeRippleDurationMs = 120;
// The amount of time in milliseconds that |highlight_| should delay after a
-// ripple animation before fading in.
-const int kHighlightFadeInAfterRippleDelayInMs = 1000;
+// ripple animation before fading in, for highlight due to mouse hover.
+const int kHoverFadeInAfterRippleDelayMs = 1000;
// Returns true if an ink drop with the given |ink_drop_state| should
// automatically transition to the InkDropState::HIDDEN state.
@@ -78,10 +78,21 @@ void InkDropImpl::AnimateToState(InkDropState ink_drop_state) {
if (!ink_drop_ripple_)
CreateInkDropRipple();
- if (ink_drop_state != views::InkDropState::HIDDEN) {
- SetHighlight(false, base::TimeDelta::FromMilliseconds(
- kHighlightFadeOutBeforeRippleDurationInMs),
- true);
+ if (ink_drop_ripple_->OverridesHighlight()) {
+ // When deactivating and the host is focused, snap back to the highlight
+ // state. (In the case of highlighting due to hover, we'll animate the
+ // highlight back in after a delay.)
+ if (ink_drop_state == views::InkDropState::DEACTIVATED && is_focused_) {
+ ink_drop_ripple_->HideImmediately();
+ SetHighlight(true, base::TimeDelta(), false);
+ return;
+ }
+
+ if (ink_drop_state != views::InkDropState::HIDDEN) {
+ SetHighlight(false, base::TimeDelta::FromMilliseconds(
+ kHighlightFadeOutBeforeRippleDurationMs),
+ true);
+ }
}
ink_drop_ripple_->AnimateToState(ink_drop_state);
@@ -92,7 +103,8 @@ void InkDropImpl::SnapToActivated() {
if (!ink_drop_ripple_)
CreateInkDropRipple();
- SetHighlight(false, base::TimeDelta(), false);
+ if (ink_drop_ripple_->OverridesHighlight())
+ SetHighlight(false, base::TimeDelta(), false);
ink_drop_ripple_->SnapToActivated();
}
@@ -102,9 +114,9 @@ void InkDropImpl::SetHovered(bool is_hovered) {
SetHighlight(ShouldHighlight(),
ShouldHighlight()
? base::TimeDelta::FromMilliseconds(
- kHighlightFadeInFromUserInputDurationInMs)
+ kHighlightFadeInFromUserInputDurationMs)
: base::TimeDelta::FromMilliseconds(
- kHighlightFadeOutFromUserInputDurationInMs),
+ kHighlightFadeOutFromUserInputDurationMs),
false);
}
@@ -159,6 +171,7 @@ void InkDropImpl::DestroyInkDropHighlight() {
void InkDropImpl::AddRootLayerToHostIfNeeded() {
DCHECK(highlight_ || ink_drop_ripple_);
+ DCHECK(!root_layer_->children().empty());
if (!root_layer_added_to_host_) {
root_layer_added_to_host_ = true;
ink_drop_host_->AddInkDropLayer(root_layer_.get());
@@ -188,8 +201,15 @@ void InkDropImpl::AnimationEnded(InkDropState ink_drop_state,
if (ShouldAnimateToHidden(ink_drop_state)) {
ink_drop_ripple_->AnimateToState(views::InkDropState::HIDDEN);
} else if (ink_drop_state == views::InkDropState::HIDDEN) {
- if (is_hovered_)
- StartHighlightAfterRippleTimer();
+ // Re-highlight, as necessary. For hover, there's a delay; for focus, jump
+ // straight into the animation.
+ if (!IsHighlightFadingInOrVisible()) {
+ if (is_focused_)
+ HighlightAfterRippleTimerFired();
+ else if (is_hovered_)
+ StartHighlightAfterRippleTimer();
+ }
+
// TODO(bruthig): Investigate whether creating and destroying
// InkDropRipples is expensive and consider creating an
// InkDropRipplePool. See www.crbug.com/522175.
@@ -214,15 +234,18 @@ void InkDropImpl::AnimationEnded(InkDropHighlight::AnimationType animation_type,
void InkDropImpl::SetHighlight(bool should_highlight,
base::TimeDelta animation_duration,
bool explode) {
- StopHighlightAfterRippleTimer();
+ highlight_after_ripple_timer_.reset();
if (IsHighlightFadingInOrVisible() == should_highlight)
return;
if (should_highlight) {
CreateInkDropHighlight();
- if (highlight_ && !(ink_drop_ripple_ && ink_drop_ripple_->IsVisible()))
+ if (highlight_ &&
+ !(ink_drop_ripple_ && ink_drop_ripple_->IsVisible() &&
+ ink_drop_ripple_->OverridesHighlight())) {
highlight_->FadeIn(animation_duration);
+ }
} else {
highlight_->FadeOut(animation_duration, explode);
}
@@ -233,26 +256,17 @@ bool InkDropImpl::ShouldHighlight() const {
}
void InkDropImpl::StartHighlightAfterRippleTimer() {
- StopHighlightAfterRippleTimer();
-
- if (!highlight_after_ripple_timer_)
- highlight_after_ripple_timer_.reset(new base::OneShotTimer);
-
+ highlight_after_ripple_timer_.reset(new base::OneShotTimer);
highlight_after_ripple_timer_->Start(
FROM_HERE,
- base::TimeDelta::FromMilliseconds(kHighlightFadeInAfterRippleDelayInMs),
+ base::TimeDelta::FromMilliseconds(kHoverFadeInAfterRippleDelayMs),
base::Bind(&InkDropImpl::HighlightAfterRippleTimerFired,
base::Unretained(this)));
}
-void InkDropImpl::StopHighlightAfterRippleTimer() {
- if (highlight_after_ripple_timer_)
- highlight_after_ripple_timer_.reset();
-}
-
void InkDropImpl::HighlightAfterRippleTimerFired() {
SetHighlight(true, base::TimeDelta::FromMilliseconds(
- kHighlightFadeInAfterRippleDurationInMs),
+ kHighlightFadeInAfterRippleDurationMs),
true);
highlight_after_ripple_timer_.reset();
}
diff --git a/chromium/ui/views/animation/ink_drop_impl.h b/chromium/ui/views/animation/ink_drop_impl.h
index 2b92d7a7589..7f4cca37911 100644
--- a/chromium/ui/views/animation/ink_drop_impl.h
+++ b/chromium/ui/views/animation/ink_drop_impl.h
@@ -107,9 +107,6 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
// |highlight_after_ripple_timer_| instance if it exists.
void StartHighlightAfterRippleTimer();
- // Stops and destroys the current |highlight_after_ripple_timer_| instance.
- void StopHighlightAfterRippleTimer();
-
// Callback for when the |highlight_after_ripple_timer_| fires.
void HighlightAfterRippleTimerFired();
diff --git a/chromium/ui/views/animation/ink_drop_impl_unittest.cc b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
index b6fc8cebb0c..b7c85dcf28b 100644
--- a/chromium/ui/views/animation/ink_drop_impl_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
@@ -8,7 +8,6 @@
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/animation/test/ink_drop_impl_test_api.h"
#include "ui/views/animation/test/test_ink_drop_host.h"
@@ -253,4 +252,122 @@ TEST_F(InkDropImplTest, LayersArentRemovedWhenPreemptingFadeOut) {
EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
}
+TEST_F(InkDropImplTest, AnimationWhenDeactivated) {
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.AnimateToState(InkDropState::ACTIVATED);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ test_api_.CompleteAnimations();
+
+ ink_drop_.AnimateToState(InkDropState::DEACTIVATED);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_TRUE(test_api_.HasActiveAnimations());
+ EXPECT_FALSE(test_api_.IsHighlightFadingInOrVisible());
+}
+
+TEST_F(InkDropImplTest, AnimationSkippedWhenFocusedAndDeactivated) {
+ ink_drop_host_.set_should_show_highlight(true);
+
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.SetFocused(true);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.AnimateToState(InkDropState::ACTIVATED);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ test_api_.CompleteAnimations();
+
+ ink_drop_.AnimateToState(InkDropState::DEACTIVATED);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_FALSE(test_api_.HasActiveAnimations());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+ EXPECT_EQ(InkDropState::HIDDEN, ink_drop_.GetTargetInkDropState());
+}
+
+TEST_F(InkDropImplTest, FocusHighlightComesBackImmediatelyAfterAction) {
+ ink_drop_host_.set_should_show_highlight(true);
+
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.SetFocused(true);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.AnimateToState(InkDropState::ACTION_PENDING);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_FALSE(test_api_.IsHighlightFadingInOrVisible());
+
+ ink_drop_.AnimateToState(InkDropState::ACTION_TRIGGERED);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+
+ test_api_.CompleteAnimations();
+
+ // No delay (unlike in the hover case).
+ EXPECT_FALSE(task_runner_->HasPendingTask());
+
+ // Highlight should be back.
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+}
+
+TEST_F(InkDropImplTest, HighlightCanCoexistWithRipple) {
+ ink_drop_host_.set_should_show_highlight(true);
+ ink_drop_host_.set_ripple_overrides_highlight(false);
+
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.SetHovered(true);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.AnimateToState(InkDropState::ACTION_PENDING);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+
+ ink_drop_.AnimateToState(InkDropState::ACTION_TRIGGERED);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+
+ test_api_.CompleteAnimations();
+
+ // Nothing to fade in because the highlight has always been visible.
+ EXPECT_FALSE(task_runner_->HasPendingTask());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+
+ // Now try with the ripple showing before the highlight comes in.
+ ink_drop_.AnimateToState(InkDropState::HIDDEN);
+ ink_drop_.SetHovered(false);
+ test_api_.CompleteAnimations();
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.AnimateToState(InkDropState::ACTION_PENDING);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ ink_drop_.SetHovered(true);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+}
+
+TEST_F(InkDropImplTest, HighlightCanCoexistWithSnapToActivatedRipple) {
+ ink_drop_host_.set_should_show_highlight(true);
+ ink_drop_host_.set_ripple_overrides_highlight(false);
+
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.SetHovered(true);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.SnapToActivated();
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+
+ // Now try with the ripple showing before the highlight comes in.
+ ink_drop_.AnimateToState(InkDropState::HIDDEN);
+ ink_drop_.SetHovered(false);
+ test_api_.CompleteAnimations();
+ EXPECT_EQ(0, ink_drop_host_.num_ink_drop_layers());
+
+ ink_drop_.SnapToActivated();
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ ink_drop_.SetHovered(true);
+ EXPECT_EQ(1, ink_drop_host_.num_ink_drop_layers());
+ EXPECT_TRUE(test_api_.IsHighlightFadingInOrVisible());
+}
+
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_painted_layer_delegates.cc b/chromium/ui/views/animation/ink_drop_painted_layer_delegates.cc
index 0ca68999ba9..75609d7a2fc 100644
--- a/chromium/ui/views/animation/ink_drop_painted_layer_delegates.cc
+++ b/chromium/ui/views/animation/ink_drop_painted_layer_delegates.cc
@@ -6,7 +6,7 @@
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRRect.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
@@ -133,10 +133,12 @@ void RoundedRectangleLayerDelegate::OnPaintLayer(
BorderShadowLayerDelegate::BorderShadowLayerDelegate(
const std::vector<gfx::ShadowValue>& shadows,
const gfx::Rect& shadowed_area_bounds,
+ SkColor fill_color,
int corner_radius)
: BasePaintedLayerDelegate(gfx::kPlaceholderColor),
shadows_(shadows),
bounds_(shadowed_area_bounds),
+ fill_color_(fill_color),
corner_radius_(corner_radius) {}
BorderShadowLayerDelegate::~BorderShadowLayerDelegate() {}
@@ -153,25 +155,24 @@ gfx::Vector2dF BorderShadowLayerDelegate::GetCenteringOffset() const {
void BorderShadowLayerDelegate::OnPaintLayer(const ui::PaintContext& context) {
SkPaint paint;
- paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows_));
- paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setStyle(SkPaint::kFill_Style);
paint.setAntiAlias(true);
- paint.setColor(SK_ColorTRANSPARENT);
- paint.setStrokeJoin(SkPaint::kRound_Join);
- SkRect path_bounds = gfx::RectFToSkRect(
- gfx::RectF(bounds_ - GetPaintedBounds().OffsetFromOrigin()));
+ paint.setColor(fill_color_);
+
+ gfx::RectF rrect_bounds =
+ gfx::RectF(bounds_ - GetPaintedBounds().OffsetFromOrigin());
+ SkRRect r_rect = SkRRect::MakeRectXY(gfx::RectFToSkRect(rrect_bounds),
+ corner_radius_, corner_radius_);
+ // First the fill color.
ui::PaintRecorder recorder(context, GetPaintedBounds().size());
- const SkScalar corner = SkFloatToScalar(corner_radius_);
- SkPath path;
- path.addRoundRect(path_bounds, corner, corner, SkPath::kCCW_Direction);
- recorder.canvas()->DrawPath(path, paint);
-
- SkPaint clear_paint;
- clear_paint.setAntiAlias(true);
- clear_paint.setXfermodeMode(SkXfermode::kClear_Mode);
- recorder.canvas()->sk_canvas()->drawRoundRect(path_bounds, corner, corner,
- clear_paint);
+ recorder.canvas()->sk_canvas()->drawRRect(r_rect, paint);
+
+ // Now the shadow.
+ paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows_));
+ recorder.canvas()->sk_canvas()->clipRRect(r_rect, SkRegion::kDifference_Op,
+ true);
+ recorder.canvas()->sk_canvas()->drawRRect(r_rect, paint);
}
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h b/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h
index 56148d28015..c4cab4f310b 100644
--- a/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h
+++ b/chromium/ui/views/animation/ink_drop_painted_layer_delegates.h
@@ -114,11 +114,12 @@ class VIEWS_EXPORT RoundedRectangleLayerDelegate
};
// A BasePaintedLayerDelegate that paints a shadow around the outside of a
-// specified roundrect.
+// specified roundrect, and also fills the round rect.
class VIEWS_EXPORT BorderShadowLayerDelegate : public BasePaintedLayerDelegate {
public:
BorderShadowLayerDelegate(const std::vector<gfx::ShadowValue>& shadows,
const gfx::Rect& shadowed_area_bounds,
+ SkColor fill_color,
int corner_radius);
~BorderShadowLayerDelegate() override;
@@ -133,9 +134,11 @@ class VIEWS_EXPORT BorderShadowLayerDelegate : public BasePaintedLayerDelegate {
const std::vector<gfx::ShadowValue> shadows_;
// The bounds of the shadowed area.
- gfx::Rect bounds_;
+ const gfx::Rect bounds_;
- int corner_radius_;
+ const SkColor fill_color_;
+
+ const int corner_radius_;
DISALLOW_COPY_AND_ASSIGN(BorderShadowLayerDelegate);
};
diff --git a/chromium/ui/views/animation/ink_drop_ripple.cc b/chromium/ui/views/animation/ink_drop_ripple.cc
index 06e38439bbe..9b4ee3c151f 100644
--- a/chromium/ui/views/animation/ink_drop_ripple.cc
+++ b/chromium/ui/views/animation/ink_drop_ripple.cc
@@ -84,6 +84,10 @@ void InkDropRipple::SnapToActivated() {
animation_observer->SetActive();
}
+bool InkDropRipple::IsVisible() {
+ return GetRootLayer()->visible();
+}
+
void InkDropRipple::HideImmediately() {
AbortAllAnimations();
SetStateToHidden();
diff --git a/chromium/ui/views/animation/ink_drop_ripple.h b/chromium/ui/views/animation/ink_drop_ripple.h
index efc4972e904..5b4a12d3957 100644
--- a/chromium/ui/views/animation/ink_drop_ripple.h
+++ b/chromium/ui/views/animation/ink_drop_ripple.h
@@ -78,7 +78,10 @@ class VIEWS_EXPORT InkDropRipple {
// Returns true when the ripple is visible. This is different from checking if
// the ink_drop_state() == HIDDEN because the ripple may be visible while it
// animates to the target HIDDEN state.
- virtual bool IsVisible() const = 0;
+ bool IsVisible();
+
+ // Returns true if this ripple is mutually exclusive with InkDropHighlight.
+ virtual bool OverridesHighlight() const = 0;
// Returns a test api to access internals of this. Default implmentations
// should return nullptr and test specific subclasses can override to return
diff --git a/chromium/ui/views/animation/square_ink_drop_ripple.cc b/chromium/ui/views/animation/square_ink_drop_ripple.cc
index a01bbfd12bb..49fd5512e24 100644
--- a/chromium/ui/views/animation/square_ink_drop_ripple.cc
+++ b/chromium/ui/views/animation/square_ink_drop_ripple.cc
@@ -214,8 +214,8 @@ ui::Layer* SquareInkDropRipple::GetRootLayer() {
return &root_layer_;
}
-bool SquareInkDropRipple::IsVisible() const {
- return root_layer_.visible();
+bool SquareInkDropRipple::OverridesHighlight() const {
+ return true;
}
float SquareInkDropRipple::GetCurrentOpacity() const {
diff --git a/chromium/ui/views/animation/square_ink_drop_ripple.h b/chromium/ui/views/animation/square_ink_drop_ripple.h
index 059d8395e45..293d46a03e9 100644
--- a/chromium/ui/views/animation/square_ink_drop_ripple.h
+++ b/chromium/ui/views/animation/square_ink_drop_ripple.h
@@ -67,7 +67,7 @@ class VIEWS_EXPORT SquareInkDropRipple : public InkDropRipple {
// InkDropRipple:
void SnapToActivated() override;
ui::Layer* GetRootLayer() override;
- bool IsVisible() const override;
+ bool OverridesHighlight() const override;
private:
friend class test::SquareInkDropRippleTestApi;
diff --git a/chromium/ui/views/border.cc b/chromium/ui/views/border.cc
index f2eb92ff111..153411dc40d 100644
--- a/chromium/ui/views/border.cc
+++ b/chromium/ui/views/border.cc
@@ -187,20 +187,19 @@ std::unique_ptr<Border> Border::NullBorder() {
// static
std::unique_ptr<Border> Border::CreateSolidBorder(int thickness,
SkColor color) {
- return base::WrapUnique(new SolidSidedBorder(gfx::Insets(thickness), color));
+ return base::MakeUnique<SolidSidedBorder>(gfx::Insets(thickness), color);
}
// static
std::unique_ptr<Border> Border::CreateEmptyBorder(const gfx::Insets& insets) {
- return base::WrapUnique(new EmptyBorder(insets));
+ return base::MakeUnique<EmptyBorder>(insets);
}
// static
std::unique_ptr<Border> Border::CreateRoundedRectBorder(int thickness,
int corner_radius,
SkColor color) {
- return base::WrapUnique(
- new RoundedRectBorder(thickness, corner_radius, color));
+ return base::MakeUnique<RoundedRectBorder>(thickness, corner_radius, color);
}
// static
@@ -217,8 +216,8 @@ std::unique_ptr<Border> Border::CreateSolidSidedBorder(int top,
int bottom,
int right,
SkColor color) {
- return base::WrapUnique(
- new SolidSidedBorder(gfx::Insets(top, left, bottom, right), color));
+ return base::MakeUnique<SolidSidedBorder>(
+ gfx::Insets(top, left, bottom, right), color);
}
// static
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index f81bb2d7618..d7c7149b9f2 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -7,12 +7,15 @@
#include <algorithm>
#include "base/logging.h"
+#include "third_party/skia/include/core/SkDrawLooper.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
+#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/path.h"
+#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/views/painter.h"
@@ -57,6 +60,37 @@ BorderImages::~BorderImages() {}
namespace {
+// Blur and offset values for the two shadows drawn around each dialog. The
+// values are all in dip.
+const int kSmallShadowVerticalOffset = 2;
+const int kSmallShadowBlur = 4;
+const SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33);
+
+const int kLargeShadowVerticalOffset = 2;
+const int kLargeShadowBlur = 6;
+const SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A);
+
+bool UseMd() {
+ return ui::MaterialDesignController::IsSecondaryUiMaterial();
+}
+
+// Utility functions for getting alignment points on the edge of a rectangle.
+gfx::Point CenterTop(const gfx::Rect& rect) {
+ return gfx::Point(rect.CenterPoint().x(), rect.y());
+}
+
+gfx::Point CenterBottom(const gfx::Rect& rect) {
+ return gfx::Point(rect.CenterPoint().x(), rect.bottom());
+}
+
+gfx::Point LeftCenter(const gfx::Rect& rect) {
+ return gfx::Point(rect.x(), rect.CenterPoint().y());
+}
+
+gfx::Point RightCenter(const gfx::Rect& rect) {
+ return gfx::Point(rect.right(), rect.CenterPoint().y());
+}
+
// Bubble border and arrow image resource ids. They don't use the IMAGE_GRID
// macro because there is no center image.
const int kNoShadowImages[] = {
@@ -143,6 +177,7 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
arrow_paint_type_(PAINT_NORMAL),
alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
shadow_(shadow),
+ images_(nullptr),
background_color_(color),
use_theme_background_color_(false) {
#if defined(OS_MACOSX)
@@ -151,13 +186,51 @@ BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
shadow_ = NO_ASSETS;
#endif // OS_MACOSX
DCHECK(shadow_ < SHADOW_COUNT);
- images_ = GetBorderImages(shadow_);
+ if (UseMd()) {
+ // Harmony bubbles don't use arrows.
+ alignment_ = ALIGN_EDGE_TO_ANCHOR_EDGE;
+ arrow_paint_type_ = PAINT_NONE;
+ } else {
+ images_ = GetBorderImages(shadow_);
+ }
}
BubbleBorder::~BubbleBorder() {}
+void BubbleBorder::set_paint_arrow(ArrowPaintType value) {
+ if (UseMd())
+ return;
+ arrow_paint_type_ = value;
+}
+
gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
const gfx::Size& contents_size) const {
+ // In MD, there are no arrows, so positioning logic is significantly simpler.
+ // TODO(estade): handle more anchor positions.
+ if (UseMd() &&
+ (arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER ||
+ arrow_ == LEFT_CENTER || arrow_ == RIGHT_CENTER)) {
+ gfx::Rect contents_bounds(contents_size);
+ if (arrow_ == TOP_RIGHT) {
+ contents_bounds +=
+ anchor_rect.bottom_right() - contents_bounds.top_right();
+ } else if (arrow_ == TOP_LEFT) {
+ contents_bounds +=
+ anchor_rect.bottom_left() - contents_bounds.origin();
+ } else if (arrow_ == BOTTOM_CENTER) {
+ contents_bounds += CenterTop(anchor_rect) - CenterBottom(contents_bounds);
+ } else if (arrow_ == LEFT_CENTER) {
+ contents_bounds += RightCenter(anchor_rect) - LeftCenter(contents_bounds);
+ } else if (arrow_ == RIGHT_CENTER) {
+ contents_bounds += LeftCenter(anchor_rect) - RightCenter(contents_bounds);
+ }
+ contents_bounds.Inset(-GetInsets());
+ // |arrow_offset_| is used to adjust bubbles that would normally be
+ // partially offscreen.
+ contents_bounds += gfx::Vector2d(-arrow_offset_, 0);
+ return contents_bounds;
+ }
+
int x = anchor_rect.x();
int y = anchor_rect.y();
int w = anchor_rect.width();
@@ -166,7 +239,7 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
const int arrow_offset = GetArrowOffset(size);
// |arrow_shift| is necessary to visually align the tip of the bubble arrow
// with the anchor point. This shift is an inverse of the shadow thickness.
- int arrow_shift =
+ int arrow_shift = UseMd() ? 0 :
images_->arrow_interior_thickness + kStroke - images_->arrow_thickness;
// When arrow is painted transparently the visible border of the bubble needs
// to be positioned at the same bounds as when the arrow is shown.
@@ -206,14 +279,20 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
}
int BubbleBorder::GetBorderThickness() const {
- return images_->border_thickness - images_->border_interior_thickness;
+ // TODO(estade): this shouldn't be called in MD.
+ return UseMd()
+ ? 0
+ : images_->border_thickness - images_->border_interior_thickness;
}
int BubbleBorder::GetBorderCornerRadius() const {
- return images_->corner_radius;
+ return UseMd() ? 3 : images_->corner_radius;
}
int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const {
+ if (UseMd())
+ return 0;
+
const int edge_length = is_arrow_on_horizontal(arrow_) ?
border_size.width() : border_size.height();
if (is_arrow_at_center(arrow_) && arrow_offset_ == 0)
@@ -234,7 +313,18 @@ bool BubbleBorder::GetArrowPath(const gfx::Rect& view_bounds,
return true;
}
+void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) {
+ // TODO(estade): remove this function.
+ DCHECK(!UseMd());
+ images_->border_interior_thickness = border_interior_thickness;
+ if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL)
+ images_->border_thickness = border_interior_thickness;
+}
+
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
+ if (UseMd())
+ return PaintMd(view, canvas);
+
gfx::Rect bounds(view.GetContentsBounds());
bounds.Inset(-GetBorderThickness(), -GetBorderThickness());
const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds());
@@ -250,8 +340,7 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
// Clip the arrow bounds out to avoid painting the overlapping edge area.
canvas->Save();
- SkRect arrow_rect(gfx::RectToSkRect(arrow_bounds));
- canvas->sk_canvas()->clipRect(arrow_rect, SkRegion::kDifference_Op);
+ canvas->ClipRect(arrow_bounds, SkRegion::kDifference_Op);
Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds);
canvas->Restore();
@@ -259,6 +348,13 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
}
gfx::Insets BubbleBorder::GetInsets() const {
+ if (UseMd()) {
+ gfx::Insets blur(kLargeShadowBlur);
+ gfx::Insets offset(-kLargeShadowVerticalOffset, 0,
+ kLargeShadowVerticalOffset, 0);
+ return blur + offset;
+ }
+
// The insets contain the stroke and shadow pixels outside the bubble fill.
const int inset = GetBorderThickness();
if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_))
@@ -284,6 +380,8 @@ gfx::Size BubbleBorder::GetSizeForContentsSize(
gfx::Size size(contents_size);
const gfx::Insets insets = GetInsets();
size.Enlarge(insets.width(), insets.height());
+ if (UseMd())
+ return size;
// Ensure the bubble is large enough to not overlap border and arrow images.
const int min = 2 * images_->border_thickness;
@@ -355,6 +453,7 @@ gfx::Rect BubbleBorder::GetArrowRect(const gfx::Rect& bounds) const {
void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
SkPath* path) const {
+ DCHECK(!UseMd());
const bool horizontal = is_arrow_on_horizontal(arrow_);
const int thickness = images_->arrow_interior_thickness;
float tip_x = horizontal ? arrow_bounds.CenterPoint().x() :
@@ -380,6 +479,7 @@ void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
const gfx::Rect& arrow_bounds) const {
+ DCHECK(!UseMd());
canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y());
SkPath path;
GetArrowPathFromArrowBounds(arrow_bounds, &path);
@@ -390,6 +490,38 @@ void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
canvas->DrawPath(path, paint);
}
+void BubbleBorder::PaintMd(const View& view, gfx::Canvas* canvas) {
+ gfx::ScopedCanvas scoped(canvas);
+
+ SkPaint paint;
+ std::vector<gfx::ShadowValue> shadows;
+ // gfx::ShadowValue counts blur pixels both inside and outside the shape,
+ // whereas these blur values only describe the outside portion, hence they
+ // must be doubled.
+ shadows.emplace_back(gfx::Vector2d(0, kSmallShadowVerticalOffset),
+ 2 * kSmallShadowBlur, kSmallShadowColor);
+ shadows.emplace_back(gfx::Vector2d(0, kLargeShadowVerticalOffset),
+ 2 * kLargeShadowBlur, kLargeShadowColor);
+ paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
+ paint.setColor(SkColorSetA(SK_ColorBLACK, 0x26));
+ paint.setAntiAlias(true);
+
+ gfx::Rect bounds(view.GetLocalBounds());
+ bounds.Inset(GetInsets());
+ SkRRect r_rect =
+ SkRRect::MakeRectXY(gfx::RectToSkRect(bounds), GetBorderCornerRadius(),
+ GetBorderCornerRadius());
+ // Clip out a round rect so the fill and shadow don't draw over the contents
+ // of the bubble.
+ SkRRect clip_r_rect = r_rect;
+ // Stroke width is a single pixel at any scale factor.
+ const SkScalar one_pixel = SkFloatToScalar(1 / canvas->image_scale());
+ clip_r_rect.inset(one_pixel, one_pixel);
+ canvas->sk_canvas()->clipRRect(clip_r_rect, SkRegion::kDifference_Op,
+ true /*doAntiAlias*/);
+ canvas->sk_canvas()->drawRRect(r_rect, paint);
+}
+
internal::BorderImages* BubbleBorder::GetImagesForTest() const {
return images_;
}
@@ -404,8 +536,14 @@ void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
paint.setStyle(SkPaint::kFill_Style);
paint.setColor(border_->background_color());
SkPath path;
- gfx::Rect bounds(view->GetLocalBounds());
- bounds.Inset(border_->GetInsets());
+ gfx::RectF bounds(view->GetLocalBounds());
+ bounds.Inset(gfx::InsetsF(border_->GetInsets()));
+ if (UseMd()) {
+ // The border is 1px at all scale factors. Leave room for it. It's partially
+ // transparent, so we don't want to draw any background underneath it.
+ const SkScalar one_pixel = SkFloatToScalar(1 / canvas->image_scale());
+ bounds.Inset(gfx::InsetsF(one_pixel));
+ }
canvas->DrawRoundRect(bounds, border_->GetBorderCornerRadius(), paint);
}
diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h
index 2ebdf9c6156..181f5daee38 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -112,6 +112,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
};
// The way the arrow should be painted.
+ // TODO(estade): Harmony doesn't use this enum; remove it.
enum ArrowPaintType {
// Fully render the arrow.
PAINT_NORMAL,
@@ -182,7 +183,7 @@ class VIEWS_EXPORT BubbleBorder : public Border {
void set_arrow_offset(int offset) { arrow_offset_ = offset; }
// Sets the way the arrow is actually painted. Default is PAINT_NORMAL.
- void set_paint_arrow(ArrowPaintType value) { arrow_paint_type_ = value; }
+ void set_paint_arrow(ArrowPaintType value);
// Get the desired widget bounds (in screen coordinates) given the anchor rect
// and bubble content size; calculated from shadow and arrow image dimensions.
@@ -205,6 +206,10 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// The returned path does not account for arrow stroke and shadow.
bool GetArrowPath(const gfx::Rect& view_bounds, gfx::Path* path) const;
+ // Sets border thickness overriding the thickness set on |images_| creation.
+ // May only be invoked after |arrow_paint_type_| has been set.
+ void SetBorderInteriorThickness(int border_interior_thickness);
+
// Overridden from Border:
void Paint(const View& view, gfx::Canvas* canvas) override;
gfx::Insets GetInsets() const override;
@@ -225,6 +230,8 @@ class VIEWS_EXPORT BubbleBorder : public Border {
SkPath* path) const;
void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const;
+ void PaintMd(const View& view, gfx::Canvas* canvas);
+
internal::BorderImages* GetImagesForTest() const;
Arrow arrow_;
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.cc b/chromium/ui/views/bubble/bubble_dialog_delegate.cc
index 066626b81da..77994311514 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate.cc
@@ -6,6 +6,7 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect.h"
@@ -189,6 +190,11 @@ void BubbleDialogDelegateView::SetArrowPaintType(
SizeToContents();
}
+void BubbleDialogDelegateView::SetBorderInteriorThickness(int thickness) {
+ GetBubbleFrameView()->bubble_border()->SetBorderInteriorThickness(thickness);
+ SizeToContents();
+}
+
void BubbleDialogDelegateView::OnAnchorBoundsChanged() {
SizeToContents();
}
@@ -289,10 +295,15 @@ void BubbleDialogDelegateView::UpdateColorsFromTheme(
const ui::NativeTheme* theme) {
if (!color_explicitly_set_)
color_ = theme->GetSystemColor(ui::NativeTheme::kColorId_BubbleBackground);
- set_background(Background::CreateSolidBackground(color()));
BubbleFrameView* frame_view = GetBubbleFrameView();
if (frame_view)
frame_view->bubble_border()->set_background_color(color());
+
+ // When there's an opaque layer, the bubble border background won't show
+ // through, so explicitly paint a background color.
+ set_background(layer() && layer()->fills_bounds_opaquely()
+ ? Background::CreateSolidBackground(color())
+ : nullptr);
}
void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget,
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.h b/chromium/ui/views/bubble/bubble_dialog_delegate.h
index e9bccb66883..4f791cd7358 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate.h
@@ -99,7 +99,7 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
virtual gfx::Rect GetAnchorRect() const;
// Allows delegates to provide custom parameters before widget initialization.
- // For example, mus needs to set a custom mus::Window* parent.
+ // For example, mus needs to set a custom ui::Window* parent.
virtual void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
Widget* widget) const;
@@ -113,6 +113,9 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// Sets the bubble arrow paint type.
void SetArrowPaintType(BubbleBorder::ArrowPaintType paint_type);
+ // Sets the bubble border interior thickness.
+ void SetBorderInteriorThickness(int thickness);
+
// Call this method when the anchor bounds have changed to reposition the
// bubble. The bubble is automatically repositioned when the anchor view
// bounds change as a result of the widget's bounds changing.
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc
index ea787f8d094..d64355810fe 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc
@@ -321,7 +321,7 @@ TEST_F(BubbleDialogDelegateTest, CloseMethods) {
BubbleDialogDelegateView::CreateBubble(bubble_delegate);
bubble_widget->Show();
BubbleFrameView* frame_view = bubble_delegate->GetBubbleFrameView();
- LabelButton* close_button = frame_view->close_;
+ Button* close_button = frame_view->close_;
ASSERT_TRUE(close_button);
frame_view->ButtonPressed(
close_button,
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index 43bac842f05..b61cb89cef1 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -11,6 +11,7 @@
#include "ui/base/default_style.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/compositor/paint_context.h"
#include "ui/compositor/paint_recorder.h"
@@ -19,11 +20,13 @@
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/vector_icons_public.h"
#include "ui/native_theme/native_theme.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/vector_icon_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_constants.h"
@@ -93,29 +96,39 @@ BubbleFrameView::BubbleFrameView(const gfx::Insets& title_margins,
close_ = CreateCloseButton(this);
close_->SetVisible(false);
+#if defined(OS_WIN)
+ // Windows will automatically create a tooltip for the close button based on
+ // the HTCLOSE result from NonClientHitTest().
+ close_->SetTooltipText(base::string16());
+#endif
AddChildView(close_);
}
BubbleFrameView::~BubbleFrameView() {}
// static
-LabelButton* BubbleFrameView::CreateCloseButton(ButtonListener* listener) {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- LabelButton* close = new LabelButton(listener, base::string16());
- close->SetImage(CustomButton::STATE_NORMAL,
- *rb.GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
- close->SetImage(CustomButton::STATE_HOVERED,
- *rb.GetImageNamed(IDR_CLOSE_DIALOG_H).ToImageSkia());
- close->SetImage(CustomButton::STATE_PRESSED,
- *rb.GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
- close->SetBorder(nullptr);
- close->SetSize(close->GetPreferredSize());
-#if !defined(OS_WIN)
- // Windows will automatically create a tooltip for the close button based on
- // the HTCLOSE result from NonClientHitTest().
- close->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
-#endif
- return close;
+Button* BubbleFrameView::CreateCloseButton(VectorIconButtonDelegate* delegate) {
+ Button* close_button = nullptr;
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
+ VectorIconButton* close = new VectorIconButton(delegate);
+ close->SetIcon(gfx::VectorIconId::BAR_CLOSE);
+ close->SetSize(close->GetPreferredSize());
+ close_button = close;
+ } else {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ LabelButton* close = new LabelButton(delegate, base::string16());
+ close->SetImage(CustomButton::STATE_NORMAL,
+ *rb.GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
+ close->SetImage(CustomButton::STATE_HOVERED,
+ *rb.GetImageNamed(IDR_CLOSE_DIALOG_H).ToImageSkia());
+ close->SetImage(CustomButton::STATE_PRESSED,
+ *rb.GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
+ close->SetBorder(nullptr);
+ close->SetSize(close->GetPreferredSize());
+ close_button = close;
+ }
+ close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
+ return close_button;
}
gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
@@ -244,7 +257,10 @@ gfx::Insets BubbleFrameView::GetInsets() const {
const bool has_title = icon_height > 0 || label_height > 0;
const int title_padding = has_title ? title_margins_.height() : 0;
const int title_height = std::max(icon_height, label_height) + title_padding;
- const int close_height = close_->visible() ? close_->height() : 0;
+ const int close_height =
+ GetWidget()->widget_delegate()->ShouldShowCloseButton()
+ ? close_->height()
+ : 0;
insets += gfx::Insets(std::max(title_height, close_height), 0, 0, 0);
return insets;
}
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index 90f1030c7d9..e15c77991a8 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -9,7 +9,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "ui/gfx/geometry/insets.h"
-#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/vector_icon_button_delegate.h"
#include "ui/views/window/non_client_view.h"
namespace gfx {
@@ -19,13 +19,13 @@ class FontList;
namespace views {
class Label;
-class LabelButton;
+class Button;
class BubbleBorder;
class ImageView;
// The non-client frame view of bubble-styled widgets.
class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
- public ButtonListener {
+ public VectorIconButtonDelegate {
public:
// Internal class name.
static const char kViewClassName[];
@@ -35,7 +35,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
~BubbleFrameView() override;
// Creates a close button used in the corner of the dialog.
- static LabelButton* CreateCloseButton(ButtonListener* listener);
+ static Button* CreateCloseButton(VectorIconButtonDelegate* delegate);
// NonClientFrameView overrides:
gfx::Rect GetBoundsForClientView() const override;
@@ -65,7 +65,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
void OnThemeChanged() override;
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
- // Overridden from ButtonListener:
+ // Overridden from VectorIconButtonDelegate:
void ButtonPressed(Button* sender, const ui::Event& event) override;
// Use bubble_border() and SetBubbleBorder(), not border() and SetBorder().
@@ -85,7 +85,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
bool close_button_clicked() const { return close_button_clicked_; }
- LabelButton* GetCloseButtonForTest() { return close_; }
+ Button* GetCloseButtonForTest() { return close_; }
protected:
// Returns the available screen bounds if the frame were to show in |rect|.
@@ -125,7 +125,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
// The optional title icon, title, and (x) close button.
views::ImageView* title_icon_;
Label* title_;
- LabelButton* close_;
+ Button* close_;
// A view to contain the footnote view, if it exists.
View* footnote_container_;
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index 9e338c563d8..bf955dd451c 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -12,6 +12,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/controls/button/label_button.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
@@ -61,9 +62,15 @@ class TestBubbleFrameViewWidgetDelegate : public WidgetDelegate {
return contents_view_;
}
+ bool ShouldShowCloseButton() const override { return should_show_close_; }
+ void SetShouldShowCloseButton(bool should_show_close) {
+ should_show_close_ = should_show_close;
+ }
+
private:
Widget* widget_;
View* contents_view_ = nullptr; // Owned by |widget_|.
+ bool should_show_close_ = false;
};
class TestBubbleFrameView : public BubbleFrameView {
@@ -98,6 +105,10 @@ class TestBubbleFrameView : public BubbleFrameView {
return available_bounds_;
}
+ TestBubbleFrameViewWidgetDelegate* widget_delegate() {
+ return widget_delegate_.get();
+ }
+
private:
ViewsTestBase* test_base_;
@@ -124,6 +135,24 @@ TEST_F(BubbleFrameViewTest, GetBoundsForClientView) {
EXPECT_EQ(insets.top() + margin_y, frame.GetBoundsForClientView().y());
}
+TEST_F(BubbleFrameViewTest, GetBoundsForClientViewWithClose) {
+ TestBubbleFrameView frame(this);
+ // TestBubbleFrameView::GetWidget() is responsible for creating the widget and
+ // widget delegate at first call, so it is called here for that side-effect.
+ ignore_result(frame.GetWidget());
+ frame.widget_delegate()->SetShouldShowCloseButton(true);
+ frame.ResetWindowControls();
+ EXPECT_EQ(kArrow, frame.bubble_border()->arrow());
+ EXPECT_EQ(kColor, frame.bubble_border()->background_color());
+
+ int margin_x = frame.content_margins().left();
+ int margin_y = frame.content_margins().top() +
+ frame.GetCloseButtonForTest()->height();
+ gfx::Insets insets = frame.bubble_border()->GetInsets();
+ EXPECT_EQ(insets.left() + margin_x, frame.GetBoundsForClientView().x());
+ EXPECT_EQ(insets.top() + margin_y, frame.GetBoundsForClientView().y());
+}
+
// Tests that the arrow is mirrored as needed to better fit the screen.
TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) {
TestBubbleFrameView frame(this);
diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc
index 876c6c28dbe..059458a0e64 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.cc
+++ b/chromium/ui/views/bubble/tray_bubble_view.cc
@@ -200,6 +200,7 @@ TrayBubbleContentMask::TrayBubbleContentMask(int corner_radius)
: layer_(ui::LAYER_TEXTURED),
corner_radius_(corner_radius) {
layer_.set_delegate(this);
+ layer_.SetFillsBoundsOpaquely(false);
}
TrayBubbleContentMask::~TrayBubbleContentMask() {
@@ -327,6 +328,7 @@ TrayBubbleView::TrayBubbleView(View* anchor,
owned_bubble_border_(bubble_border_),
is_gesture_dragging_(false),
mouse_actively_entered_(false) {
+ set_can_activate(params_.can_activate);
DCHECK(anchor_widget()); // Computed by BubbleDialogDelegateView().
set_notify_enter_exit_on_child(true);
set_close_on_deactivate(init_params.close_on_deactivate);
@@ -414,10 +416,6 @@ void TrayBubbleView::OnBeforeBubbleWidgetInit(Widget::InitParams* params,
delegate_->OnBeforeBubbleWidgetInit(anchor_widget(), bubble_widget, params);
}
-bool TrayBubbleView::CanActivate() const {
- return params_.can_activate;
-}
-
NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) {
BubbleFrameView* frame = static_cast<BubbleFrameView*>(
BubbleDialogDelegateView::CreateNonClientFrameView(widget));
@@ -492,7 +490,7 @@ void TrayBubbleView::OnMouseExited(const ui::MouseEvent& event) {
}
void TrayBubbleView::GetAccessibleState(ui::AXViewState* state) {
- if (delegate_ && params_.can_activate) {
+ if (delegate_ && CanActivate()) {
state->role = ui::AX_ROLE_WINDOW;
state->name = delegate_->GetAccessibleNameForBubble();
}
diff --git a/chromium/ui/views/bubble/tray_bubble_view.h b/chromium/ui/views/bubble/tray_bubble_view.h
index 4712e6a756f..ecba48f0143 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.h
+++ b/chromium/ui/views/bubble/tray_bubble_view.h
@@ -154,7 +154,6 @@ class VIEWS_EXPORT TrayBubbleView : public views::BubbleDialogDelegateView,
bool is_gesture_dragging() const { return is_gesture_dragging_; }
// Overridden from views::WidgetDelegate.
- bool CanActivate() const override;
views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) override;
bool WidgetHasHitTestMask() const override;
diff --git a/chromium/ui/views/cocoa/bridged_content_view.mm b/chromium/ui/views/cocoa/bridged_content_view.mm
index b6c94e328eb..7c49cd04443 100644
--- a/chromium/ui/views/cocoa/bridged_content_view.mm
+++ b/chromium/ui/views/cocoa/bridged_content_view.mm
@@ -7,6 +7,7 @@
#include "base/logging.h"
#import "base/mac/mac_util.h"
#import "base/mac/scoped_nsobject.h"
+#import "base/mac/sdk_forward_declarations.h"
#include "base/strings/sys_string_conversions.h"
#include "skia/ext/skia_utils_mac.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
@@ -17,9 +18,11 @@
#include "ui/base/ime/text_input_client.h"
#include "ui/compositor/canvas_painter.h"
#import "ui/events/cocoa/cocoa_event_utils.h"
+#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
#include "ui/gfx/canvas_paint_mac.h"
+#include "ui/gfx/decorated_text.h"
#include "ui/gfx/geometry/rect.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/gfx/path.h"
@@ -32,6 +35,7 @@
#include "ui/views/view.h"
#include "ui/views/widget/native_widget_mac.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/word_lookup_client.h"
using views::MenuController;
@@ -207,6 +211,42 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
ui::KeyboardCodeFromNSEvent(event), ui::EF_NONE);
}
+NSAttributedString* GetAttributedString(
+ const gfx::DecoratedText& decorated_text) {
+ base::scoped_nsobject<NSMutableAttributedString> str(
+ [[NSMutableAttributedString alloc]
+ initWithString:base::SysUTF16ToNSString(decorated_text.text)]);
+ [str beginEditing];
+
+ NSValue* const line_style =
+ @(NSUnderlineStyleSingle | NSUnderlinePatternSolid);
+
+ for (const auto& attribute : decorated_text.attributes) {
+ DCHECK(!attribute.range.is_reversed());
+ DCHECK_LE(attribute.range.end(), [str length]);
+
+ NSMutableDictionary* attrs = [NSMutableDictionary dictionary];
+ NSRange range = attribute.range.ToNSRange();
+
+ if (attribute.font.GetNativeFont())
+ attrs[NSFontAttributeName] = attribute.font.GetNativeFont();
+
+ // NSFont does not have underline as an attribute. Hence handle it
+ // separately.
+ const bool underline = attribute.font.GetStyle() & gfx::Font::UNDERLINE;
+ if (underline)
+ attrs[NSUnderlineStyleAttributeName] = line_style;
+
+ if (attribute.strike)
+ attrs[NSStrikethroughStyleAttributeName] = line_style;
+
+ [str setAttributes:attrs range:range];
+ }
+
+ [str endEditing];
+ return str.autorelease();
+}
+
} // namespace
@interface BridgedContentView ()
@@ -332,7 +372,8 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
views::View* view = hostedView_->GetTooltipHandlerForPoint(locationInContent);
if (view) {
gfx::Point viewPoint = locationInContent;
- views::View::ConvertPointToTarget(hostedView_, view, &viewPoint);
+ views::View::ConvertPointToScreen(hostedView_, &viewPoint);
+ views::View::ConvertPointFromScreen(view, &viewPoint);
if (!view->GetTooltipText(viewPoint, &newTooltipText))
DCHECK(newTooltipText.empty());
}
@@ -344,7 +385,7 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
- (void)updateWindowMask {
DCHECK(![self inLiveResize]);
- DCHECK(base::mac::IsOSMavericks());
+ DCHECK(base::mac::IsOS10_9());
DCHECK(hostedView_);
views::Widget* widget = hostedView_->GetWidget();
@@ -436,11 +477,23 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
if (textInputClient_ && ![self activeMenuController]) {
// If a single character is inserted by keyDown's call to
// interpretKeyEvents: then use InsertChar() to allow editing events to be
- // merged.
- if (isCharacterEvent)
- textInputClient_->InsertChar(GetCharacterEventFromNSEvent(keyDownEvent_));
- else
+ // merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible
+ // to determine the correct key code for each unicode character. Also a
+ // correct keycode is not needed in the current context. Send ui::EF_NONE as
+ // the key modifier since |text| already accounts for the pressed key
+ // modifiers.
+
+ // Also, note we don't use |keyDownEvent_| to generate the synthetic
+ // ui::KeyEvent since for text inserted using an IME, [keyDownEvent_
+ // characters] might not be the same as |text|. This is because
+ // |keyDownEvent_| will correspond to the event that caused the composition
+ // text to be confirmed, say, Return key press.
+ if (isCharacterEvent) {
+ textInputClient_->InsertChar(ui::KeyEvent([text characterAtIndex:0],
+ ui::VKEY_UNKNOWN, ui::EF_NONE));
+ } else {
textInputClient_->InsertText(base::SysNSStringToUTF16(text));
+ }
return;
}
@@ -593,7 +646,7 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
// We prevent updating the window mask and clipping the border around the
// view, during a live resize. Hence update the window mask and redraw the
// view after resize has completed.
- if (base::mac::IsOSMavericks()) {
+ if (base::mac::IsOS10_9()) {
[self updateWindowMask];
[self setNeedsDisplay:YES];
}
@@ -620,7 +673,7 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
// crbug.com/543671.
if (windowMask_ && ![self inLiveResize] &&
!IsRectInsidePath(dirtyRect, windowMask_)) {
- DCHECK(base::mac::IsOSMavericks());
+ DCHECK(base::mac::IsOS10_9());
gfx::ScopedNSGraphicsContextSaveGState state;
// The outer rectangular path corresponding to the window.
@@ -649,6 +702,14 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
ui::CanvasPainter(&canvas, 1.f).context());
}
+- (BOOL)isOpaque {
+ if (!hostedView_)
+ return NO;
+
+ ui::Layer* layer = hostedView_->GetWidget()->GetLayer();
+ return layer && layer->fills_bounds_opaquely();
+}
+
// To maximize consistency with the Cocoa browser (mac_views_browser=0), accept
// mouse clicks immediately so that clicking on Chrome from an inactive window
// will allow the event to be processed, rather than merely activate the window.
@@ -715,8 +776,38 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
if (!hostedView_)
return;
- ui::MouseWheelEvent event(theEvent);
- hostedView_->GetWidget()->OnMouseEvent(&event);
+ ui::ScrollEvent event(theEvent);
+ hostedView_->GetWidget()->OnScrollEvent(&event);
+}
+
+- (void)quickLookWithEvent:(NSEvent*)theEvent {
+ if (!hostedView_)
+ return;
+
+ const gfx::Point locationInContent = ui::EventLocationFromNative(theEvent);
+ views::View* target = hostedView_->GetEventHandlerForPoint(locationInContent);
+ if (!target)
+ return;
+
+ views::WordLookupClient* wordLookupClient = target->GetWordLookupClient();
+ if (!wordLookupClient)
+ return;
+
+ gfx::Point locationInTarget = locationInContent;
+ views::View::ConvertPointToTarget(hostedView_, target, &locationInTarget);
+ gfx::DecoratedText decoratedWord;
+ gfx::Point baselinePoint;
+ if (!wordLookupClient->GetDecoratedWordAtPoint(
+ locationInTarget, &decoratedWord, &baselinePoint)) {
+ return;
+ }
+
+ // Convert |baselinePoint| to the coordinate system of |hostedView_|.
+ views::View::ConvertPointToTarget(target, hostedView_, &baselinePoint);
+ NSPoint baselinePointAppKit = NSMakePoint(
+ baselinePoint.x(), NSHeight([self frame]) - baselinePoint.y());
+ [self showDefinitionForAttributedString:GetAttributedString(decoratedWord)
+ atPoint:baselinePointAppKit];
}
////////////////////////////////////////////////////////////////////////////////
@@ -742,8 +833,10 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
// Selection movement and scrolling.
- (void)moveForward:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveLeft:sender]
- : [self moveRight:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_FORWARD
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveRight:(id)sender {
@@ -754,8 +847,10 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
}
- (void)moveBackward:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveRight:sender]
- : [self moveLeft:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_BACKWARD
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveLeft:(id)sender {
@@ -766,27 +861,31 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
}
- (void)moveUp:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE
+ [self handleAction:ui::TextEditCommand::MOVE_UP
keyCode:ui::VKEY_UP
domCode:ui::DomCode::ARROW_UP
eventFlags:0];
}
- (void)moveDown:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE
+ [self handleAction:ui::TextEditCommand::MOVE_DOWN
keyCode:ui::VKEY_DOWN
domCode:ui::DomCode::ARROW_DOWN
eventFlags:0];
}
- (void)moveWordForward:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveWordLeft:sender]
- : [self moveWordRight:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_WORD_FORWARD
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveWordBackward:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveWordRight:sender]
- : [self moveWordLeft:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_WORD_BACKWARD
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveToBeginningOfLine:(id)sender {
@@ -804,75 +903,91 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
}
- (void)moveToBeginningOfParagraph:(id)sender {
- [self moveToBeginningOfLine:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveToEndOfParagraph:(id)sender {
- [self moveToEndOfLine:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveToEndOfDocument:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE
+ [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT
keyCode:ui::VKEY_END
domCode:ui::DomCode::END
eventFlags:ui::EF_CONTROL_DOWN];
}
- (void)moveToBeginningOfDocument:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE
+ [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT
keyCode:ui::VKEY_HOME
domCode:ui::DomCode::HOME
eventFlags:ui::EF_CONTROL_DOWN];
}
- (void)pageDown:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE
+ // The pageDown: action message is bound to the key combination
+ // [Option+PageDown].
+ [self handleAction:ui::TextEditCommand::MOVE_PAGE_DOWN
keyCode:ui::VKEY_NEXT
domCode:ui::DomCode::PAGE_DOWN
- eventFlags:0];
+ eventFlags:ui::EF_ALT_DOWN];
}
- (void)pageUp:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE
+ // The pageUp: action message is bound to the key combination [Option+PageUp].
+ [self handleAction:ui::TextEditCommand::MOVE_PAGE_UP
keyCode:ui::VKEY_PRIOR
domCode:ui::DomCode::PAGE_UP
- eventFlags:0];
+ eventFlags:ui::EF_ALT_DOWN];
}
- (void)moveBackwardAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveRightAndModifySelection:sender]
- : [self moveLeftAndModifySelection:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_BACKWARD_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveForwardAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveLeftAndModifySelection:sender]
- : [self moveRightAndModifySelection:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_FORWARD_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveWordForwardAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveWordLeftAndModifySelection:sender]
- : [self moveWordRightAndModifySelection:sender];
+ [self handleAction:ui::TextEditCommand::MOVE_WORD_FORWARD_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveWordBackwardAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveWordRightAndModifySelection:sender]
- : [self moveWordLeftAndModifySelection:sender];
+ [self
+ handleAction:ui::TextEditCommand::MOVE_WORD_BACKWARD_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveUpAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ [self handleAction:ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION
keyCode:ui::VKEY_UP
domCode:ui::DomCode::ARROW_UP
eventFlags:ui::EF_SHIFT_DOWN];
}
- (void)moveDownAndModifySelection:(id)sender {
- [self
- handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_DOWN
- domCode:ui::DomCode::ARROW_DOWN
- eventFlags:ui::EF_SHIFT_DOWN];
+ [self handleAction:ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_DOWN
+ domCode:ui::DomCode::ARROW_DOWN
+ eventFlags:ui::EF_SHIFT_DOWN];
}
- (void)moveToBeginningOfLineAndModifySelection:(id)sender {
@@ -892,56 +1007,62 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
}
- (void)moveToBeginningOfParagraphAndModifySelection:(id)sender {
- [self moveToBeginningOfLineAndModifySelection:sender];
+ [self handleAction:ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_PARAGRAPH_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveToEndOfParagraphAndModifySelection:(id)sender {
- [self moveToEndOfLineAndModifySelection:sender];
+ [self handleAction:ui::TextEditCommand::
+ MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)moveToEndOfDocumentAndModifySelection:(id)sender {
- [self
- handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_END
- domCode:ui::DomCode::END
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
+ [self handleAction:ui::TextEditCommand::
+ MOVE_TO_END_OF_DOCUMENT_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_END
+ domCode:ui::DomCode::END
+ eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
}
- (void)moveToBeginningOfDocumentAndModifySelection:(id)sender {
[self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ MOVE_TO_BEGINNING_OF_DOCUMENT_AND_MODIFY_SELECTION
keyCode:ui::VKEY_HOME
domCode:ui::DomCode::HOME
eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
}
- (void)pageDownAndModifySelection:(id)sender {
- [self
- handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_NEXT
- domCode:ui::DomCode::PAGE_DOWN
- eventFlags:ui::EF_SHIFT_DOWN];
+ [self handleAction:ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_NEXT
+ domCode:ui::DomCode::PAGE_DOWN
+ eventFlags:ui::EF_SHIFT_DOWN];
}
- (void)pageUpAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ [self handleAction:ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION
keyCode:ui::VKEY_PRIOR
domCode:ui::DomCode::PAGE_UP
eventFlags:ui::EF_SHIFT_DOWN];
}
- (void)moveParagraphForwardAndModifySelection:(id)sender {
- [self
- handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_DOWN
- domCode:ui::DomCode::ARROW_DOWN
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
+ [self handleAction:ui::TextEditCommand::
+ MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION
+ keyCode:ui::VKEY_DOWN
+ domCode:ui::DomCode::ARROW_DOWN
+ eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
}
- (void)moveParagraphBackwardAndModifySelection:(id)sender {
[self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION
keyCode:ui::VKEY_UP
domCode:ui::DomCode::ARROW_UP
eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
@@ -1065,11 +1186,24 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
}
- (void)deleteToBeginningOfParagraph:(id)sender {
- [self deleteToBeginningOfLine:sender];
+ [self handleAction:ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
}
- (void)deleteToEndOfParagraph:(id)sender {
- [self deleteToEndOfLine:sender];
+ [self handleAction:ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH
+ keyCode:ui::VKEY_UNKNOWN
+ domCode:ui::DomCode::NONE
+ eventFlags:0];
+}
+
+- (void)yank:(id)sender {
+ [self handleAction:ui::TextEditCommand::YANK
+ keyCode:ui::VKEY_Y
+ domCode:ui::DomCode::US_Y
+ eventFlags:ui::EF_CONTROL_DOWN];
}
// Cancellation.
@@ -1213,9 +1347,21 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
if ([text isKindOfClass:[NSAttributedString class]])
text = [text string];
+
+ textInputClient_->DeleteRange(gfx::Range(replacementRange));
ui::CompositionText composition;
composition.text = base::SysNSStringToUTF16(text);
composition.selection = gfx::Range(selectedRange);
+
+ // Add a black underline with a transparent background to the composition
+ // text. TODO(karandeepb): On Cocoa textfields, the target clause of the
+ // composition has a thick underlines. The composition text also has
+ // discontinous underlines for different clauses. This is also supported in
+ // the Chrome renderer. Add code to extract underlines from |text| once our
+ // render text implementation supports thick underlines and discontinous
+ // underlines for consecutive characters. See http://crbug.com/612675.
+ composition.underlines.push_back(ui::CompositionUnderline(
+ 0, [text length], SK_ColorBLACK, false, SK_ColorTRANSPARENT));
textInputClient_->SetCompositionText(composition);
}
@@ -1286,4 +1432,10 @@ ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) {
return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point];
}
+- (id)accessibilityFocusedUIElement {
+ if (!hostedView_)
+ return nil;
+ return [hostedView_->GetNativeViewAccessible() accessibilityFocusedUIElement];
+}
+
@end
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h
index ba4c5847c73..d1e2d08a516 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget.h
+++ b/chromium/ui/views/cocoa/bridged_native_widget.h
@@ -142,6 +142,9 @@ class VIEWS_EXPORT BridgedNativeWidget
// being reordered in (or out of) the screen list.
void OnVisibilityChanged();
+ // Called by the NSWindowDelegate when the system control tint changes.
+ void OnSystemControlTintChanged();
+
// Called by the NSWindowDelegate on a scale factor or color space change.
void OnBackingPropertiesChanged();
@@ -311,6 +314,11 @@ class VIEWS_EXPORT BridgedNativeWidget
// shadow needs to be invalidated when a frame is received for the new shape.
bool invalidate_shadow_on_frame_swap_ = false;
+ // Whether the window's visibility is suppressed currently. For opaque non-
+ // modal windows, the window's alpha value is set to 0, till the frame from
+ // the compositor arrives to avoid "blinking".
+ bool initial_visibility_suppressed_ = false;
+
AssociatedViews associated_views_;
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidget);
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm
index 16af930118c..d10b7f17673 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget.mm
@@ -12,6 +12,7 @@
#import "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#import "base/mac/sdk_forward_declarations.h"
+#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
@@ -23,6 +24,7 @@
#include "ui/gfx/geometry/dip_util.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/gfx/mac/nswindow_frame_controls.h"
+#import "ui/native_theme/native_theme_mac.h"
#import "ui/views/cocoa/bridged_content_view.h"
#import "ui/views/cocoa/drag_drop_client_mac.h"
#import "ui/views/cocoa/cocoa_mouse_capture.h"
@@ -399,6 +401,12 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
name:NSApplicationDidHideNotification
object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:window_delegate_
+ selector:@selector(onSystemControlTintChanged:)
+ name:NSControlTintDidChangeNotification
+ object:nil];
+
// Validate the window's initial state, otherwise the bridge's initial
// tracking state will be incorrect.
DCHECK(![window_ isVisible]);
@@ -564,6 +572,20 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) {
return;
}
+ // Non-modal windows are not animated. Hence opaque non-modal windows can
+ // appear with a "flash" if they are made visible before the frame from the
+ // compositor arrives. To get around this, set the alpha value of the window
+ // to 0, till we receive the correct frame from the compositor. Also, ignore
+ // mouse clicks till then.
+ // TODO(karandeepb): Investigate whether similar technique is needed for other
+ // dialog types.
+ if (layer() && [window_ isOpaque] &&
+ !native_widget_mac_->GetWidget()->IsModal()) {
+ initial_visibility_suppressed_ = true;
+ [window_ setAlphaValue:0.0];
+ [window_ setIgnoresMouseEvents:YES];
+ }
+
if (new_state == SHOW_AND_ACTIVATE_WINDOW) {
[window_ makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
@@ -686,8 +708,10 @@ void BridgedNativeWidget::OnWindowWillClose() {
parent_->RemoveChildWindow(this);
parent_ = nullptr;
}
- [window_ setDelegate:nil];
[[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
+ // Note this also clears the NSWindow delegate, after informing Widget
+ // delegates about the closure. NativeWidgetMac then deletes |this| before
+ // returning.
native_widget_mac_->OnWindowWillClose();
}
@@ -775,7 +799,7 @@ void BridgedNativeWidget::OnSizeChanged() {
// We don't update the window mask during a live resize, instead it is done
// after the resize is completed in viewDidEndLiveResize: in
// BridgedContentView.
- if (base::mac::IsOSMavericks() && ![window_ inLiveResize])
+ if (base::mac::IsOS10_9() && ![window_ inLiveResize])
[bridged_view_ updateWindowMask];
}
@@ -819,6 +843,11 @@ void BridgedNativeWidget::OnVisibilityChanged() {
if (layer()) {
layer()->SetVisible(window_visible_);
layer()->SchedulePaint(gfx::Rect(GetClientAreaSize()));
+
+ // For translucent windows which are made visible, recalculate shadow when
+ // the frame from the compositor arrives.
+ if (![window_ isOpaque])
+ invalidate_shadow_on_frame_swap_ = window_visible_;
}
NotifyVisibilityChangeDown();
@@ -833,6 +862,10 @@ void BridgedNativeWidget::OnVisibilityChanged() {
[window_ setAutodisplay:window_visible_];
}
+void BridgedNativeWidget::OnSystemControlTintChanged() {
+ ui::NativeThemeMac::instance()->NotifyObservers();
+}
+
void BridgedNativeWidget::OnBackingPropertiesChanged() {
if (layer())
UpdateLayerProperties();
@@ -944,7 +977,7 @@ void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type,
CreateCompositor();
DCHECK(compositor_);
- SetLayer(new ui::Layer(layer_type));
+ SetLayer(base::MakeUnique<ui::Layer>(layer_type));
// Note, except for controls, this will set the layer to be hidden, since it
// is only called during Init().
layer()->SetVisible(window_visible_);
@@ -968,7 +1001,7 @@ void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type,
// to generate a window shadow from the composited CALayer. To get around
// this, let the window background remain opaque and clip the window
// boundary in drawRect method of BridgedContentView. See crbug.com/543671.
- if (base::mac::IsOSYosemiteOrLater())
+ if (base::mac::IsAtLeastOS10_10())
[window_ setBackgroundColor:[NSColor clearColor]];
}
@@ -1089,6 +1122,12 @@ void BridgedNativeWidget::AcceleratedWidgetSwapCompleted() {
if (!compositor_widget_->HasFrameOfSize(GetClientAreaSize()))
return;
+ if (initial_visibility_suppressed_) {
+ initial_visibility_suppressed_ = false;
+ [window_ setAlphaValue:1.0];
+ [window_ setIgnoresMouseEvents:NO];
+ }
+
if (invalidate_shadow_on_frame_swap_) {
invalidate_shadow_on_frame_swap_ = false;
[window_ invalidateShadow];
@@ -1259,7 +1298,7 @@ void BridgedNativeWidget::AddCompositorSuperview() {
if (widget_type_ == Widget::InitParams::TYPE_MENU) {
// Giving the canvas opacity messes up subpixel font rendering, so use a
// solid background, but make the CALayer transparent.
- if (base::mac::IsOSYosemiteOrLater()) {
+ if (base::mac::IsAtLeastOS10_10()) {
[background_layer setOpacity:kYosemiteMenuOpacity];
CGSSetWindowBackgroundBlurRadius(
_CGSDefaultConnection(), [window_ windowNumber], kYosemiteMenuBlur);
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
index 4554eee36a5..2b21d350de4 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -19,12 +19,16 @@
#import "testing/gtest_mac.h"
#import "ui/base/cocoa/window_size_constants.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/base/test/material_design_controller_test_api.h"
+#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/gfx/test/ui_cocoa_test_helper.h"
#import "ui/views/cocoa/bridged_content_view.h"
#import "ui/views/cocoa/native_widget_mac_nswindow.h"
#import "ui/views/cocoa/views_nswindow_delegate.h"
#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_model.h"
#include "ui/views/view.h"
#include "ui/views/widget/native_widget_mac.h"
#include "ui/views/widget/root_view.h"
@@ -57,6 +61,11 @@ using base::SysUTF8ToNSString;
namespace {
+enum class TestCase {
+ ALL, // Test all strings.
+ LTR_ONLY, // Only test Left To Right strings.
+};
+
// Implemented NSResponder action messages for use in tests.
NSArray* const kMoveActions = @[
@"moveForward:",
@@ -113,7 +122,7 @@ NSArray* const kDeleteActions = @[
];
NSArray* const kMiscActions =
- @[ @"insertText:", @"cancelOperation:", @"transpose:" ];
+ @[ @"insertText:", @"cancelOperation:", @"transpose:", @"yank:" ];
// Empty range shortcut for readibility.
NSRange EmptyRange() {
@@ -237,6 +246,7 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
// Overridden from testing::Test:
void SetUp() override {
ui::CocoaTest::SetUp();
+ ui::MaterialDesignController::Initialize();
init_params_.native_widget = native_widget_mac_;
@@ -256,6 +266,11 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
native_widget_mac_->GetWidget()->Init(init_params_);
}
+ void TearDown() override {
+ ui::test::MaterialDesignControllerTestAPI::Uninitialize();
+ ui::CocoaTest::TearDown();
+ }
+
protected:
std::unique_ptr<Widget> widget_;
MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|.
@@ -304,6 +319,9 @@ class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase {
// |start|.
void MakeSelection(int start, int end);
+ // Helper method to set the private |keyDownEvent_| field on |ns_view_|.
+ void SetKeyDownEvent(NSEvent* event);
+
// testing::Test:
void SetUp() override;
void TearDown() override;
@@ -319,11 +337,12 @@ class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase {
// Test editing commands in |selectors| against the expectations set by
// |dummy_text_view_|. This is done by selecting every substring within a set
- // of test strings (both RTL and non-RTL) and performing every selector on
- // both the NSTextView and the BridgedContentView hosting a focused
- // views::TextField to ensure the resulting text and selection ranges match.
- // |selectors| is an NSArray of NSStrings.
- void TestEditingCommands(NSArray* selectors);
+ // of test strings (both RTL and non-RTL by default) and performing every
+ // selector on both the NSTextView and the BridgedContentView hosting a
+ // focused views::TextField to ensure the resulting text and selection ranges
+ // match. |selectors| is an NSArray of NSStrings. |cases| determines whether
+ // RTL strings are to be tested.
+ void TestEditingCommands(NSArray* selectors, TestCase cases = TestCase::ALL);
std::unique_ptr<views::View> view_;
@@ -426,6 +445,10 @@ void BridgedNativeWidgetTest::MakeSelection(int start, int end) {
[dummy_text_view_ doCommandBySelector:sel];
}
+void BridgedNativeWidgetTest::SetKeyDownEvent(NSEvent* event) {
+ [ns_view_ setValue:event forKey:@"keyDownEvent_"];
+}
+
void BridgedNativeWidgetTest::SetUp() {
BridgedNativeWidgetTestBase::SetUp();
@@ -449,6 +472,9 @@ void BridgedNativeWidgetTest::SetUp() {
}
void BridgedNativeWidgetTest::TearDown() {
+ // Clear kill buffer so that no state persists between tests.
+ TextfieldModel::ClearKillBuffer();
+
if (bridge())
bridge()->SetRootView(nullptr);
view_.reset();
@@ -483,6 +509,12 @@ void BridgedNativeWidgetTest::TestDeleteBeginning(SEL sel) {
EXPECT_NSEQ_3(@" bar ", GetExpectedText(), GetActualText());
EXPECT_EQ_RANGE_3(NSMakeRange(5, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
+
+ // Verify yanking inserts the deleted text.
+ PerformCommand(@selector(yank:));
+ EXPECT_NSEQ_3(@" bar baz", GetExpectedText(), GetActualText());
+ EXPECT_EQ_RANGE_3(NSMakeRange(8, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
}
void BridgedNativeWidgetTest::TestDeleteEnd(SEL sel) {
@@ -511,13 +543,22 @@ void BridgedNativeWidgetTest::TestDeleteEnd(SEL sel) {
EXPECT_NSEQ_3(@"bar", GetExpectedText(), GetActualText());
EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
+
+ // Verify yanking inserts the deleted text.
+ PerformCommand(@selector(yank:));
+ EXPECT_NSEQ_3(@"foo bar", GetExpectedText(), GetActualText());
+ EXPECT_EQ_RANGE_3(NSMakeRange(4, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
}
-void BridgedNativeWidgetTest::TestEditingCommands(NSArray* selectors) {
- const base::string16 test_strings[] = {
- base::WideToUTF16(L"ab c"),
- base::WideToUTF16(L"\x0634\x0632 \x064A") // RTL string.
- };
+void BridgedNativeWidgetTest::TestEditingCommands(NSArray* selectors,
+ TestCase cases) {
+ std::vector<base::string16> test_strings;
+ test_strings.push_back(base::WideToUTF16(L"ab c"));
+ if (cases == TestCase::ALL) {
+ test_strings.push_back(
+ base::WideToUTF16(L"\x0634\x0632 \x064A")); // RTL string.
+ }
for (const base::string16& test_string : test_strings) {
for (NSString* selector_string in selectors) {
@@ -863,6 +904,51 @@ TEST_F(BridgedNativeWidgetTest, TextInput_Compose) {
GetExpectedSelectionRange(), GetActualSelectionRange());
}
+// Test IME composition for accented characters.
+TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
+ InstallTextField("abc");
+
+ // Simulate action messages generated when the key 'a' is pressed repeatedly
+ // and leads to the showing of an IME candidate window. To simulate an event,
+ // set the private keyDownEvent field on the BridgedContentView.
+
+ // First an insertText: message with key 'a' is generated.
+ SetKeyDownEvent(cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true, ui::VKEY_A, 0));
+ [ns_view_ insertText:@"a" replacementRange:EmptyRange()];
+ [dummy_text_view_ insertText:@"a" replacementRange:EmptyRange()];
+ EXPECT_EQ_3(NO, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]);
+ EXPECT_NSEQ_3(@"abca", GetExpectedText(), GetActualText());
+
+ // Next the IME popup appears. On selecting the accented character using arrow
+ // keys, setMarkedText action message is generated which replaces the earlier
+ // inserted 'a'.
+ SetKeyDownEvent(cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true, ui::VKEY_RIGHT, 0));
+ [ns_view_ setMarkedText:@"Ă "
+ selectedRange:NSMakeRange(0, 1)
+ replacementRange:NSMakeRange(3, 1)];
+ [dummy_text_view_ setMarkedText:@"Ă "
+ selectedRange:NSMakeRange(0, 1)
+ replacementRange:NSMakeRange(3, 1)];
+ EXPECT_EQ_3(YES, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]);
+ EXPECT_EQ_RANGE_3(NSMakeRange(3, 1), [dummy_text_view_ markedRange],
+ [ns_view_ markedRange]);
+ EXPECT_EQ_RANGE_3(NSMakeRange(3, 1), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
+ EXPECT_NSEQ_3(@"abcĂ ", GetExpectedText(), GetActualText());
+
+ // On pressing enter, the marked text is confirmed.
+ SetKeyDownEvent(cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0));
+ [ns_view_ insertText:@"Ă " replacementRange:EmptyRange()];
+ [dummy_text_view_ insertText:@"Ă " replacementRange:EmptyRange()];
+ EXPECT_EQ_3(NO, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]);
+ EXPECT_EQ_RANGE_3(NSMakeRange(4, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
+ EXPECT_NSEQ_3(@"abcĂ ", GetExpectedText(), GetActualText());
+}
+
// Test moving the caret left and right using text input protocol.
TEST_F(BridgedNativeWidgetTest, TextInput_MoveLeftRight) {
InstallTextField("foo");
@@ -897,6 +983,12 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteBackward) {
EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
+ // Verify that deletion did not modify the kill buffer.
+ PerformCommand(@selector(yank:));
+ EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText());
+ EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
+
// Try to delete again on an empty string.
PerformCommand(@selector(deleteBackward:));
EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText());
@@ -922,6 +1014,12 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteForward) {
EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText());
EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
+
+ // Verify that deletion did not modify the kill buffer.
+ PerformCommand(@selector(yank:));
+ EXPECT_NSEQ_3(nil, GetExpectedText(), GetActualText());
+ EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
}
// Test forward word deletion using text input protocol.
@@ -951,6 +1049,12 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteWordForward) {
EXPECT_NSEQ_3(@"o b baz", GetExpectedText(), GetActualText());
EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
+
+ // Verify that deletion did not modify the kill buffer.
+ PerformCommand(@selector(yank:));
+ EXPECT_NSEQ_3(@"o b baz", GetExpectedText(), GetActualText());
+ EXPECT_EQ_RANGE_3(NSMakeRange(0, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
}
// Test backward word deletion using text input protocol.
@@ -982,6 +1086,12 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteWordBackward) {
EXPECT_NSEQ_3(@"faz", GetExpectedText(), GetActualText());
EXPECT_EQ_RANGE_3(NSMakeRange(1, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
+
+ // Verify that deletion did not modify the kill buffer.
+ PerformCommand(@selector(yank:));
+ EXPECT_NSEQ_3(@"faz", GetExpectedText(), GetActualText());
+ EXPECT_EQ_RANGE_3(NSMakeRange(1, 0), GetExpectedSelectionRange(),
+ GetActualSelectionRange());
}
// Test deleting to beginning/end of line/paragraph using text input protocol.
@@ -1007,12 +1117,12 @@ TEST_F(BridgedNativeWidgetTest, TextInput_MoveEditingCommands) {
TestEditingCommands(kMoveActions);
}
-// Todo(karandeepb): Enable this test once the behavior of all move and select
-// commands are fixed.
// Test move and select commands against expectations set by |dummy_text_view_|.
-TEST_F(BridgedNativeWidgetTest,
- TextInput_MoveAndSelectEditingCommands_DISABLED) {
- TestEditingCommands(kSelectActions);
+TEST_F(BridgedNativeWidgetTest, TextInput_MoveAndSelectEditingCommands) {
+ // The behavior of NSTextView for RTL strings is buggy for some move and
+ // select commands. Hence don't test against an RTL string. See
+ // rdar://27863290.
+ TestEditingCommands(kSelectActions, TestCase::LTR_ONLY);
}
// Test delete commands against expectations set by |dummy_text_view_|.
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac.mm b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
index ed85acbfe9e..9dda333f01b 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
@@ -25,7 +25,8 @@
- (id)initWithData:(const ui::OSExchangeData&)data {
if ((self = [super init])) {
- data_.reset(new OSExchangeData(data.provider().Clone()));
+ data_.reset(new OSExchangeData(
+ std::unique_ptr<OSExchangeData::Provider>(data.provider().Clone())));
}
return self;
}
@@ -78,6 +79,11 @@ void DragDropClientMac::StartDragAndDrop(
const ui::OSExchangeDataProviderMac& provider =
static_cast<const ui::OSExchangeDataProviderMac&>(data.provider());
+ // Release capture before beginning the dragging session. Capture may have
+ // been acquired on the mouseDown, but capture is not required during the
+ // dragging session and the mouseUp that would release it will be suppressed.
+ bridge_->ReleaseCapture();
+
// Synthesize an event for dragging, since we can't be sure that
// [NSApp currentEvent] will return a valid dragging event.
NSWindow* window = bridge_->ns_window();
@@ -131,6 +137,8 @@ NSDragOperation DragDropClientMac::DragUpdate(id<NSDraggingInfo> sender) {
if (!data_source_.get()) {
data_source_.reset([[CocoaDragDropDataProvider alloc]
initWithPasteboard:[sender draggingPasteboard]]);
+ operation_ = ui::DragDropTypes::NSDragOperationToDragOperation(
+ [sender draggingSourceOperationMask]);
}
drag_operation = drop_helper_.OnDragOver(
@@ -143,6 +151,8 @@ NSDragOperation DragDropClientMac::Drop(id<NSDraggingInfo> sender) {
int drag_operation = drop_helper_.OnDrop(
*[data_source_ data], LocationInView([sender draggingLocation]),
operation_);
+ data_source_.reset();
+ operation_ = 0;
return ui::DragDropTypes::DragOperationToNSDragOperation(drag_operation);
}
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
index 7c9f510e5c3..364b73e0d69 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -6,8 +6,10 @@
#import <Cocoa/Cocoa.h>
+#import "base/mac/scoped_objc_class_swizzler.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#import "ui/views/cocoa/bridged_native_widget.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view.h"
@@ -16,6 +18,18 @@
using base::ASCIIToUTF16;
+@interface NSView (DragSessionTestingDonor)
+@end
+
+@implementation NSView (DragSessionTestingDonor)
+- (NSDraggingSession*)cr_beginDraggingSessionWithItems:(NSArray*)items
+ event:(NSEvent*)event
+ source:(id<NSDraggingSource>)
+ source {
+ return nil;
+}
+@end
+
// Mocks the NSDraggingInfo sent to the DragDropClientMac's DragUpdate() and
// Drop() methods. Out of the required methods of the protocol, only
// draggingLocation and draggingPasteboard are used.
@@ -61,7 +75,7 @@ using base::ASCIIToUTF16;
}
- (NSDragOperation)draggingSourceOperationMask {
- return NSDragOperationNone;
+ return NSDragOperationEvery;
}
- (NSWindow*)draggingDestinationWindow {
@@ -209,6 +223,41 @@ TEST_F(DragDropClientMacTest, BasicDragDrop) {
EXPECT_EQ(Drop(), NSDragOperationMove);
}
+// Ensure that capture is released before the end of a drag and drop operation.
+TEST_F(DragDropClientMacTest, ReleaseCapture) {
+ // DragDropView doesn't actually capture the mouse, so explicitly acquire it
+ // to test that StartDragAndDrop() actually releases it.
+ // Although this is not an interactive UI test, acquiring capture should be OK
+ // since the runloop will exit before the system has any opportunity to
+ // capture anything.
+ bridge_->AcquireCapture();
+ EXPECT_TRUE(bridge_->HasCapture());
+
+ // Create the drop data
+ OSExchangeData data;
+ const base::string16& text = ASCIIToUTF16("text");
+ data.SetString(text);
+ SetData(data);
+
+ // There's no way to cleanly stop NSDraggingSession inside unit tests, so just
+ // don't start it at all.
+ base::mac::ScopedObjCClassSwizzler swizzle(
+ [NSView class], @selector(beginDraggingSessionWithItems:event:source:),
+ @selector(cr_beginDraggingSessionWithItems:event:source:));
+
+ // Immediately quit drag'n'drop, or we'll hang.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&DragDropClientMac::EndDrag,
+ base::Unretained(drag_drop_client())));
+
+ // It will call ReleaseCapture().
+ drag_drop_client()->StartDragAndDrop(
+ target_, data, 0, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
+
+ // The capture should be released.
+ EXPECT_FALSE(bridge_->HasCapture());
+}
+
// Tests if the drag and drop target rejects the dropped data with the
// incorrect format.
TEST_F(DragDropClientMacTest, InvalidFormatDragDrop) {
diff --git a/chromium/ui/views/cocoa/views_nswindow_delegate.h b/chromium/ui/views/cocoa/views_nswindow_delegate.h
index 3c0e06e8e41..715af24dec9 100644
--- a/chromium/ui/views/cocoa/views_nswindow_delegate.h
+++ b/chromium/ui/views/cocoa/views_nswindow_delegate.h
@@ -42,6 +42,9 @@ VIEWS_EXPORT
// a notification such as NSApplicationDidHideNotification.
- (void)onWindowOrderChanged:(NSNotification*)notification;
+// Notify that the system control tint changed.
+- (void)onSystemControlTintChanged:(NSNotification*)notification;
+
// Called on the delegate of a modal sheet when its modal session ends.
- (void)sheetDidEnd:(NSWindow*)sheet
returnCode:(NSInteger)returnCode
diff --git a/chromium/ui/views/cocoa/views_nswindow_delegate.mm b/chromium/ui/views/cocoa/views_nswindow_delegate.mm
index 7500a9596be..6e578e2fa67 100644
--- a/chromium/ui/views/cocoa/views_nswindow_delegate.mm
+++ b/chromium/ui/views/cocoa/views_nswindow_delegate.mm
@@ -39,6 +39,10 @@
parent_->OnVisibilityChanged();
}
+- (void)onSystemControlTintChanged:(NSNotification*)notification {
+ parent_->OnSystemControlTintChanged();
+}
+
- (void)sheetDidEnd:(NSWindow*)sheet
returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo {
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc
index 7fd92737484..8913282a7f3 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_view.cc
@@ -446,10 +446,6 @@ void ColorChooserView::WindowClosing() {
listener_->OnColorChooserDialogClosed();
}
-View* ColorChooserView::GetContentsView() {
- return this;
-}
-
void ColorChooserView::ContentsChanged(Textfield* sender,
const base::string16& new_contents) {
SkColor color = SK_ColorBLACK;
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.h b/chromium/ui/views/color_chooser/color_chooser_view.h
index 912e6000076..4d42a93b95e 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.h
+++ b/chromium/ui/views/color_chooser/color_chooser_view.h
@@ -52,7 +52,6 @@ class VIEWS_EXPORT ColorChooserView : public WidgetDelegateView,
View* GetInitiallyFocusedView() override;
ui::ModalType GetModalType() const override;
void WindowClosing() override;
- View* GetContentsView() override;
// TextfieldController overrides:
void ContentsChanged(Textfield* sender,
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index c1db4715f33..e52c23bf3ff 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -12,12 +12,16 @@
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icons_public.h"
#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/animation/ink_drop_highlight.h"
+#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/painter.h"
#include "ui/views/resources/grit/views_resources.h"
+#include "ui/views/style/platform_style.h"
namespace views {
@@ -32,6 +36,12 @@ Checkbox::Checkbox(const base::string16& label)
if (UseMd()) {
set_request_focus_on_press(false);
+ SetInkDropMode(PlatformStyle::kUseRipples ? InkDropMode::ON
+ : InkDropMode::OFF);
+ set_has_ink_drop_action_on_click(true);
+ // The "small" size is 21dp, the large size is 1.33 * 21dp = 28dp.
+ set_ink_drop_size(gfx::Size(21, 21));
+ SetFocusPainter(nullptr);
} else {
std::unique_ptr<LabelButtonBorder> button_border(new LabelButtonBorder());
// Inset the trailing side by a couple pixels for the focus border.
@@ -127,10 +137,12 @@ void Checkbox::OnPaint(gfx::Canvas* canvas) {
SkPaint focus_paint;
focus_paint.setAntiAlias(true);
- focus_paint.setColor(GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_FocusedBorderColor));
+ focus_paint.setColor(
+ SkColorSetA(GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_FocusedBorderColor),
+ 0x66));
focus_paint.setStyle(SkPaint::kStroke_Style);
- focus_paint.setStrokeWidth(1);
+ focus_paint.setStrokeWidth(2);
PaintFocusRing(canvas, focus_paint);
}
@@ -152,14 +164,27 @@ void Checkbox::OnNativeThemeChanged(const ui::NativeTheme* theme) {
UpdateImage();
}
+std::unique_ptr<InkDropRipple> Checkbox::CreateInkDropRipple() const {
+ return CreateDefaultInkDropRipple(image()->bounds().CenterPoint());
+}
+
+std::unique_ptr<InkDropHighlight> Checkbox::CreateInkDropHighlight() const {
+ return nullptr;
+}
+
+SkColor Checkbox::GetInkDropBaseColor() const {
+ return GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ButtonEnabledColor);
+}
+
gfx::ImageSkia Checkbox::GetImage(ButtonState for_state) const {
if (UseMd()) {
return gfx::CreateVectorIcon(
- checked_ ? gfx::VectorIconId::CHECKBOX_ACTIVE
- : gfx::VectorIconId::CHECKBOX_NORMAL,
- 16, GetNativeTheme()->GetSystemColor(
- checked_ ? ui::NativeTheme::kColorId_FocusedBorderColor
- : ui::NativeTheme::kColorId_UnfocusedBorderColor));
+ GetVectorIconId(), 16,
+ // When not checked, the icon color matches the button text color.
+ GetNativeTheme()->GetSystemColor(
+ checked_ ? ui::NativeTheme::kColorId_FocusedBorderColor
+ : ui::NativeTheme::kColorId_ButtonEnabledColor));
}
const size_t checked_index = checked_ ? 1 : 0;
@@ -182,10 +207,14 @@ void Checkbox::SetCustomImage(bool checked,
void Checkbox::PaintFocusRing(gfx::Canvas* canvas, const SkPaint& paint) {
gfx::RectF focus_rect(image()->bounds());
- focus_rect.Inset(gfx::InsetsF(-.5f));
canvas->DrawRoundRect(focus_rect, 2.f, paint);
}
+gfx::VectorIconId Checkbox::GetVectorIconId() const {
+ return checked() ? gfx::VectorIconId::CHECKBOX_ACTIVE
+ : gfx::VectorIconId::CHECKBOX_NORMAL;
+}
+
void Checkbox::NotifyClick(const ui::Event& event) {
SetChecked(!checked());
LabelButton::NotifyClick(event);
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index 919c141587e..9c03ae6d7f9 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -14,8 +14,15 @@
class SkPaint;
+namespace gfx {
+enum class VectorIconId;
+}
+
namespace views {
+class InkDropHover;
+class InkDropRipple;
+
// A native themed class representing a checkbox. This class does not use
// platform specific objects to replicate the native platforms looks and feel.
class VIEWS_EXPORT Checkbox : public LabelButton {
@@ -45,6 +52,9 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
void OnFocus() override;
void OnBlur() override;
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
+ std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
+ std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const override;
+ SkColor GetInkDropBaseColor() const override;
gfx::ImageSkia GetImage(ButtonState for_state) const override;
// Set the image shown for each button state depending on whether it is
@@ -57,6 +67,10 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// Paints a focus indicator for the view.
virtual void PaintFocusRing(gfx::Canvas* canvas, const SkPaint& paint);
+ // Gets the vector icon id used to draw the icon based on the current state of
+ // |checked_|.
+ virtual gfx::VectorIconId GetVectorIconId() const;
+
private:
// Overridden from Button:
void NotifyClick(const ui::Event& event) override;
diff --git a/chromium/ui/views/controls/button/custom_button.cc b/chromium/ui/views/controls/button/custom_button.cc
index 62b96997799..5bcd0c907fc 100644
--- a/chromium/ui/views/controls/button/custom_button.cc
+++ b/chromium/ui/views/controls/button/custom_button.cc
@@ -5,7 +5,6 @@
#include "ui/views/controls/button/custom_button.h"
#include "ui/accessibility/ax_view_state.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -163,15 +162,17 @@ bool CustomButton::OnMousePressed(const ui::MouseEvent& event) {
bool CustomButton::OnMouseDragged(const ui::MouseEvent& event) {
if (state_ != STATE_DISABLED) {
const bool should_enter_pushed = ShouldEnterPushedState(event);
+ const bool should_show_pending =
+ should_enter_pushed && notify_action_ == NOTIFY_ON_RELEASE && !InDrag();
if (HitTestPoint(event.location())) {
SetState(should_enter_pushed ? STATE_PRESSED : STATE_HOVERED);
- if (!InDrag() && should_enter_pushed &&
+ if (should_show_pending &&
ink_drop()->GetTargetInkDropState() == views::InkDropState::HIDDEN) {
AnimateInkDrop(views::InkDropState::ACTION_PENDING, &event);
}
} else {
SetState(STATE_NORMAL);
- if (!InDrag() && should_enter_pushed &&
+ if (should_show_pending &&
ink_drop()->GetTargetInkDropState() ==
views::InkDropState::ACTION_PENDING) {
AnimateInkDrop(views::InkDropState::HIDDEN, &event);
@@ -201,11 +202,9 @@ void CustomButton::OnMouseReleased(const ui::MouseEvent& event) {
void CustomButton::OnMouseCaptureLost() {
// Starting a drag results in a MouseCaptureLost. Reset button state.
- // TODO(varkha) While in drag only reset the state with Material Design.
- // The same logic may applies everywhere so gather any feedback and update.
- bool reset_button_state =
- !InDrag() || ui::MaterialDesignController::IsModeMaterial();
- if (state_ != STATE_DISABLED && reset_button_state)
+ // TODO(varkha): Reset the state even while in drag. The same logic may
+ // applies everywhere so gather any feedback and update.
+ if (state_ != STATE_DISABLED)
SetState(STATE_NORMAL);
AnimateInkDrop(views::InkDropState::HIDDEN, nullptr /* event */);
}
@@ -468,8 +467,13 @@ void CustomButton::NotifyClick(const ui::Event& event) {
}
void CustomButton::OnClickCanceled(const ui::Event& event) {
- AnimateInkDrop(views::InkDropState::HIDDEN,
- ui::LocatedEvent::FromIfValid(&event));
+ if (ink_drop()->GetTargetInkDropState() ==
+ views::InkDropState::ACTION_PENDING ||
+ ink_drop()->GetTargetInkDropState() ==
+ views::InkDropState::ALTERNATE_ACTION_PENDING) {
+ AnimateInkDrop(views::InkDropState::HIDDEN,
+ ui::LocatedEvent::FromIfValid(&event));
+ }
Button::OnClickCanceled(event);
}
diff --git a/chromium/ui/views/controls/button/custom_button_unittest.cc b/chromium/ui/views/controls/button/custom_button_unittest.cc
index a911e292dce..816d8a4d9cf 100644
--- a/chromium/ui/views/controls/button/custom_button_unittest.cc
+++ b/chromium/ui/views/controls/button/custom_button_unittest.cc
@@ -9,7 +9,6 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/layout.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/display/screen.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
@@ -57,8 +56,9 @@ class TestContextMenuController : public ContextMenuController {
class TestCustomButton : public CustomButton, public ButtonListener {
public:
- explicit TestCustomButton()
+ explicit TestCustomButton(bool has_ink_drop_action_on_click)
: CustomButton(this) {
+ set_has_ink_drop_action_on_click(has_ink_drop_action_on_click);
}
~TestCustomButton() override {}
@@ -108,7 +108,7 @@ class CustomButtonTest : public ViewsTestBase {
widget_->Init(params);
widget_->Show();
- button_ = new TestCustomButton();
+ button_ = new TestCustomButton(false);
widget_->SetContentsView(button_);
}
@@ -117,9 +117,10 @@ class CustomButtonTest : public ViewsTestBase {
ViewsTestBase::TearDown();
}
- void CreateButtonWithInkDrop(std::unique_ptr<InkDrop> ink_drop) {
+ void CreateButtonWithInkDrop(std::unique_ptr<InkDrop> ink_drop,
+ bool has_ink_drop_action_on_click) {
delete button_;
- button_ = new TestCustomButton();
+ button_ = new TestCustomButton(has_ink_drop_action_on_click);
InkDropHostViewTestApi(button_).SetInkDrop(std::move(ink_drop));
widget_->SetContentsView(button_);
}
@@ -350,7 +351,7 @@ TEST_F(CustomButtonTest, AsCustomButton) {
// may enter a different ink drop state.
TEST_F(CustomButtonTest, ButtonClickTogglesInkDrop) {
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
ui::test::EventGenerator generator(widget()->GetNativeWindow());
generator.set_current_location(gfx::Point(50, 50));
@@ -365,7 +366,7 @@ TEST_F(CustomButtonTest, ButtonClickTogglesInkDrop) {
// Releasing capture should also reset PRESSED button state to NORMAL.
TEST_F(CustomButtonTest, CaptureLossHidesInkDrop) {
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
ui::test::EventGenerator generator(widget()->GetNativeWindow());
generator.set_current_location(gfx::Point(50, 50));
@@ -378,15 +379,12 @@ TEST_F(CustomButtonTest, CaptureLossHidesInkDrop) {
widget()->ReleaseCapture();
SetDraggedView(nullptr);
EXPECT_EQ(InkDropState::HIDDEN, ink_drop->GetTargetInkDropState());
- EXPECT_EQ(ui::MaterialDesignController::IsModeMaterial()
- ? Button::ButtonState::STATE_NORMAL
- : Button::ButtonState::STATE_PRESSED,
- button()->state());
+ EXPECT_EQ(Button::ButtonState::STATE_NORMAL, button()->state());
}
TEST_F(CustomButtonTest, HideInkDropWhenShowingContextMenu) {
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
TestContextMenuController context_menu_controller;
button()->set_context_menu_controller(&context_menu_controller);
button()->set_hide_ink_drop_when_showing_context_menu(true);
@@ -402,7 +400,7 @@ TEST_F(CustomButtonTest, HideInkDropWhenShowingContextMenu) {
TEST_F(CustomButtonTest, DontHideInkDropWhenShowingContextMenu) {
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
TestContextMenuController context_menu_controller;
button()->set_context_menu_controller(&context_menu_controller);
button()->set_hide_ink_drop_when_showing_context_menu(false);
@@ -420,7 +418,7 @@ TEST_F(CustomButtonTest, HideInkDropOnBlur) {
gfx::Point center(10, 10);
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
button()->OnFocus();
@@ -440,7 +438,7 @@ TEST_F(CustomButtonTest, HideInkDropOnBlur) {
TEST_F(CustomButtonTest, InkDropAfterTryingToShowContextMenu) {
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
button()->set_context_menu_controller(nullptr);
ink_drop->SetHovered(true);
@@ -452,12 +450,15 @@ TEST_F(CustomButtonTest, InkDropAfterTryingToShowContextMenu) {
EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop->GetTargetInkDropState());
}
-TEST_F(CustomButtonTest, InkDropShowHideOnMouseDragged) {
+// Tests that when button is set to notify on release, dragging mouse out and
+// back transitions ink drop states correctly.
+TEST_F(CustomButtonTest, InkDropShowHideOnMouseDraggedNotifyOnRelease) {
gfx::Point center(10, 10);
gfx::Point oob(-1, -1);
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
+ button()->set_notify_action(CustomButton::NOTIFY_ON_RELEASE);
button()->OnMousePressed(ui::MouseEvent(
ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(),
@@ -490,12 +491,54 @@ TEST_F(CustomButtonTest, InkDropShowHideOnMouseDragged) {
EXPECT_FALSE(button()->pressed());
}
+// Tests that when button is set to notify on press, dragging mouse out and back
+// does not change the ink drop state.
+TEST_F(CustomButtonTest, InkDropShowHideOnMouseDraggedNotifyOnPress) {
+ gfx::Point center(10, 10);
+ gfx::Point oob(-1, -1);
+
+ TestInkDrop* ink_drop = new TestInkDrop();
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), true);
+ button()->set_notify_action(CustomButton::NOTIFY_ON_PRESS);
+
+ button()->OnMousePressed(ui::MouseEvent(
+ ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+
+ EXPECT_EQ(InkDropState::ACTION_TRIGGERED, ink_drop->GetTargetInkDropState());
+ EXPECT_TRUE(button()->pressed());
+
+ button()->OnMouseDragged(
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, oob, oob, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+
+ EXPECT_EQ(InkDropState::ACTION_TRIGGERED, ink_drop->GetTargetInkDropState());
+
+ button()->OnMouseDragged(ui::MouseEvent(
+ ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+
+ EXPECT_EQ(InkDropState::ACTION_TRIGGERED, ink_drop->GetTargetInkDropState());
+
+ button()->OnMouseDragged(
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, oob, oob, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+
+ EXPECT_EQ(InkDropState::ACTION_TRIGGERED, ink_drop->GetTargetInkDropState());
+
+ button()->OnMouseReleased(
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, oob, oob, ui::EventTimeForNow(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+
+ EXPECT_EQ(InkDropState::ACTION_TRIGGERED, ink_drop->GetTargetInkDropState());
+}
+
TEST_F(CustomButtonTest, InkDropStaysHiddenWhileDragging) {
gfx::Point center(10, 10);
gfx::Point oob(-1, -1);
TestInkDrop* ink_drop = new TestInkDrop();
- CreateButtonWithInkDrop(base::WrapUnique(ink_drop));
+ CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
button()->OnMousePressed(ui::MouseEvent(
ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(),
diff --git a/chromium/ui/views/controls/button/image_button.cc b/chromium/ui/views/controls/button/image_button.cc
index a9fda37f5b4..483d971bbea 100644
--- a/chromium/ui/views/controls/button/image_button.cc
+++ b/chromium/ui/views/controls/button/image_button.cc
@@ -215,7 +215,7 @@ void ToggleImageButton::SetToggled(bool toggled) {
toggled_ = toggled;
SchedulePaint();
- NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
+ NotifyAccessibilityEvent(ui::AX_EVENT_ARIA_ATTRIBUTE_CHANGED, true);
}
void ToggleImageButton::SetToggledImage(ButtonState image_state,
@@ -270,6 +270,15 @@ bool ToggleImageButton::GetTooltipText(const gfx::Point& p,
void ToggleImageButton::GetAccessibleState(ui::AXViewState* state) {
ImageButton::GetAccessibleState(state);
GetTooltipText(gfx::Point(), &state->name);
+
+ // Use the visual pressed image as a cue for making this control into an
+ // accessible toggle button.
+ if ((toggled_ && !images_[ButtonState::STATE_NORMAL].isNull()) ||
+ (!toggled_ && !alternate_images_[ButtonState::STATE_NORMAL].isNull())) {
+ state->role = ui::AX_ROLE_TOGGLE_BUTTON;
+ if (toggled_)
+ state->AddStateFlag(ui::AX_STATE_PRESSED);
+ }
}
} // namespace views
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 0979be6bfc5..3d7453d774e 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -12,7 +12,6 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
@@ -92,7 +91,6 @@ namespace views {
// static
const int LabelButton::kHoverAnimationDurationMs = 170;
-const int LabelButton::kFocusRectInset = 3;
const char LabelButton::kViewClassName[] = "LabelButton";
LabelButton::LabelButton(ButtonListener* listener, const base::string16& text)
@@ -127,8 +125,7 @@ LabelButton::LabelButton(ButtonListener* listener, const base::string16& text)
label_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
// Inset the button focus rect from the actual border; roughly match Windows.
- SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(gfx::Insets(
- kFocusRectInset, kFocusRectInset, kFocusRectInset, kFocusRectInset)));
+ SetFocusPainter(Painter::CreateDashedFocusPainterWithInsets(gfx::Insets(3)));
}
LabelButton::~LabelButton() {}
@@ -192,6 +189,10 @@ void LabelButton::SetFontList(const gfx::FontList& font_list) {
label_->SetFontList(cached_normal_font_list_);
}
+void LabelButton::AdjustFontSize(int font_size_delta) {
+ LabelButton::SetFontList(GetFontList().DeriveWithSizeDelta(font_size_delta));
+}
+
void LabelButton::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
label_->SetElideBehavior(elide_behavior);
}
@@ -386,7 +387,13 @@ void LabelButton::EnableCanvasFlippingForRTLUI(bool flip) {
}
std::unique_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const {
- return PlatformStyle::CreateLabelButtonBorder(style());
+ if (style_ != Button::STYLE_TEXTBUTTON)
+ return base::MakeUnique<LabelButtonAssetBorder>(style_);
+ std::unique_ptr<LabelButtonBorder> border =
+ base::MakeUnique<LabelButtonBorder>();
+ border->set_insets(views::LabelButtonAssetBorder::GetDefaultInsetsForStyle(
+ style_));
+ return border;
}
void LabelButton::SetBorder(std::unique_ptr<Border> border) {
@@ -422,6 +429,9 @@ void LabelButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
ResetLabelEnabledColor();
// Invalidate the layout to pickup the new insets from the border.
InvalidateLayout();
+ // The entire button has to be repainted here, since the native theme can
+ // define the tint for the entire background/border/focus ring.
+ SchedulePaint();
}
void LabelButton::AddInkDropLayer(ui::Layer* ink_drop_layer) {
@@ -441,10 +451,9 @@ std::unique_ptr<views::InkDropRipple> LabelButton::CreateInkDropRipple() const {
return GetText().empty()
? CreateDefaultInkDropRipple(
image()->GetMirroredBounds().CenterPoint())
- : std::unique_ptr<views::InkDropRipple>(
- new views::FloodFillInkDropRipple(
- GetLocalBounds(), GetInkDropCenterBasedOnLastEvent(),
- GetInkDropBaseColor(), ink_drop_visible_opacity()));
+ : base::MakeUnique<views::FloodFillInkDropRipple>(
+ GetLocalBounds(), GetInkDropCenterBasedOnLastEvent(),
+ GetInkDropBaseColor(), ink_drop_visible_opacity());
}
std::unique_ptr<views::InkDropHighlight> LabelButton::CreateInkDropHighlight()
@@ -454,10 +463,10 @@ std::unique_ptr<views::InkDropHighlight> LabelButton::CreateInkDropHighlight()
return GetText().empty()
? CreateDefaultInkDropHighlight(
gfx::RectF(image()->GetMirroredBounds()).CenterPoint())
- : base::WrapUnique(new views::InkDropHighlight(
+ : base::MakeUnique<views::InkDropHighlight>(
size(), kInkDropSmallCornerRadius,
gfx::RectF(GetLocalBounds()).CenterPoint(),
- GetInkDropBaseColor()));
+ GetInkDropBaseColor());
}
void LabelButton::StateChanged() {
@@ -481,11 +490,24 @@ void LabelButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const {
void LabelButton::ResetColorsFromNativeTheme() {
const ui::NativeTheme* theme = GetNativeTheme();
+ bool button_style = style() == STYLE_BUTTON;
+ // Button colors are used only for STYLE_BUTTON, otherwise we use label
+ // colors. As it turns out, these are almost always the same color anyway in
+ // pre-MD, although in the MD world labels and buttons get different colors.
+ // TODO(estade): simplify this by removing STYLE_BUTTON.
SkColor colors[STATE_COUNT] = {
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonEnabledColor),
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonHoverColor),
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonHoverColor),
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonDisabledColor),
+ theme->GetSystemColor(button_style
+ ? ui::NativeTheme::kColorId_ButtonEnabledColor
+ : ui::NativeTheme::kColorId_LabelEnabledColor),
+ theme->GetSystemColor(button_style
+ ? ui::NativeTheme::kColorId_ButtonHoverColor
+ : ui::NativeTheme::kColorId_LabelEnabledColor),
+ theme->GetSystemColor(button_style
+ ? ui::NativeTheme::kColorId_ButtonHoverColor
+ : ui::NativeTheme::kColorId_LabelEnabledColor),
+ theme->GetSystemColor(button_style
+ ? ui::NativeTheme::kColorId_ButtonDisabledColor
+ : ui::NativeTheme::kColorId_LabelDisabledColor),
};
// Use hardcoded colors for inverted color scheme support and STYLE_BUTTON.
@@ -496,11 +518,11 @@ void LabelButton::ResetColorsFromNativeTheme() {
label_->set_background(Background::CreateSolidBackground(SK_ColorBLACK));
label_->SetAutoColorReadabilityEnabled(true);
label_->SetShadows(gfx::ShadowValues());
- } else if (style() == STYLE_BUTTON) {
- PlatformStyle::ApplyLabelButtonTextStyle(label_, &colors);
- label_->set_background(nullptr);
} else {
+ if (style() == STYLE_BUTTON)
+ PlatformStyle::ApplyLabelButtonTextStyle(label_, &colors);
label_->set_background(nullptr);
+ label_->SetAutoColorReadabilityEnabled(false);
}
for (size_t state = STATE_NORMAL; state < STATE_COUNT; ++state) {
@@ -541,6 +563,7 @@ void LabelButton::SetTextInternal(const base::string16& text) {
void LabelButton::ChildPreferredSizeChanged(View* child) {
ResetCachedPreferredSize();
PreferredSizeChanged();
+ Layout();
}
ui::NativeTheme::Part LabelButton::GetThemePart() const {
diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h
index 0b5e24e7834..96fc7af6b1f 100644
--- a/chromium/ui/views/controls/button/label_button.h
+++ b/chromium/ui/views/controls/button/label_button.h
@@ -31,9 +31,6 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// The length of the hover fade animation.
static const int kHoverAnimationDurationMs;
- // Amount to inset each edge of the button when drawing the focus rectangle.
- static const int kFocusRectInset;
-
static const char kViewClassName[];
LabelButton(ButtonListener* listener, const base::string16& text);
@@ -46,7 +43,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// Gets or sets the text shown on the button.
const base::string16& GetText() const;
- void SetText(const base::string16& text);
+ virtual void SetText(const base::string16& text);
// Sets the text color shown for the specified button |for_state| to |color|.
void SetTextColor(ButtonState for_state, SkColor color);
@@ -62,7 +59,11 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
// Gets or sets the font list used by this button.
const gfx::FontList& GetFontList() const;
- void SetFontList(const gfx::FontList& font_list);
+ // TODO(estade): make this function protected.
+ virtual void SetFontList(const gfx::FontList& font_list);
+
+ // Adjusts the font size up or down by the given amount.
+ virtual void AdjustFontSize(int font_size_delta);
// Sets the elide behavior of this button.
void SetElideBehavior(gfx::ElideBehavior elide_behavior);
@@ -154,6 +155,7 @@ class VIEWS_EXPORT LabelButton : public CustomButton,
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, Image);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, LabelAndImage);
FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, FontList);
+ FRIEND_TEST_ALL_PREFIXES(LabelButtonTest, ResetColorsFromNativeTheme);
void SetTextInternal(const base::string16& text);
diff --git a/chromium/ui/views/controls/button/label_button_border.cc b/chromium/ui/views/controls/button/label_button_border.cc
index e8347bb9c79..6c3f3ea7c84 100644
--- a/chromium/ui/views/controls/button/label_button_border.cc
+++ b/chromium/ui/views/controls/button/label_button_border.cc
@@ -139,20 +139,28 @@ void LabelButtonAssetBorder::Paint(const View& view, gfx::Canvas* canvas) {
if (animation && animation->is_animating()) {
// Linearly interpolate background and foreground painters during animation.
+ uint8_t fg_alpha =
+ static_cast<uint8_t>(animation->CurrentValueBetween(0, 255));
+
const SkRect sk_rect = gfx::RectToSkRect(rect);
- canvas->sk_canvas()->saveLayer(&sk_rect, NULL);
- state = native_theme_delegate->GetBackgroundThemeState(&extra);
- PaintHelper(this, canvas, state, rect, extra);
+ SkAutoCanvasRestore auto_restore(canvas->sk_canvas(), false);
+ canvas->sk_canvas()->saveLayer(&sk_rect, nullptr);
+
+ {
+ // First, modulate the background by 1 - alpha.
+ SkAutoCanvasRestore auto_restore(canvas->sk_canvas(), false);
+ canvas->sk_canvas()->saveLayerAlpha(&sk_rect, 255 - fg_alpha);
+ state = native_theme_delegate->GetBackgroundThemeState(&extra);
+ PaintHelper(this, canvas, state, rect, extra);
+ }
+ // Then modulate the foreground by alpha, and blend using kPlus_Mode.
SkPaint paint;
- double scale = animation->GetCurrentValue();
- paint.setXfermode(SkArithmeticMode::Make(0.0f, scale, 1.0 - scale, 0.0));
+ paint.setAlpha(fg_alpha);
+ paint.setXfermodeMode(SkXfermode::kPlus_Mode);
canvas->sk_canvas()->saveLayer(&sk_rect, &paint);
state = native_theme_delegate->GetForegroundThemeState(&extra);
PaintHelper(this, canvas, state, rect, extra);
- canvas->sk_canvas()->restore();
-
- canvas->sk_canvas()->restore();
} else {
PaintHelper(this, canvas, state, rect, extra);
}
diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc
index 1b13b8c50a2..5df8d448391 100644
--- a/chromium/ui/views/controls/button/label_button_unittest.cc
+++ b/chromium/ui/views/controls/button/label_button_unittest.cc
@@ -14,6 +14,7 @@
#include "ui/base/ui_base_switches.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -79,20 +80,22 @@ class LabelButtonTest : public test::WidgetTest {
// Establish the expected text colors for testing changes due to state.
themed_normal_text_color_ = button_->GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_ButtonEnabledColor);
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- // The Linux theme provides a non-black highlight text color, but it's not
- // used for styled buttons.
- styled_highlight_text_color_ = themed_normal_text_color_;
- styled_normal_text_color_ = themed_normal_text_color_;
-#else
- styled_highlight_text_color_ = button_->GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_ButtonHighlightColor);
+ ui::NativeTheme::kColorId_LabelEnabledColor);
// For styled buttons only, platforms other than Desktop Linux either ignore
// NativeTheme and use a hardcoded black or (on Mac) have a NativeTheme that
// reliably returns black.
styled_normal_text_color_ = SK_ColorBLACK;
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // The Linux theme provides a non-black highlight text color, but it's not
+ // used for styled buttons.
+ styled_highlight_text_color_ = styled_normal_text_color_ =
+ button_->GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ButtonEnabledColor);
+#elif defined(OS_MACOSX)
+ styled_highlight_text_color_ = SK_ColorWHITE;
+#else
+ styled_highlight_text_color_ = styled_normal_text_color_;
#endif
}
@@ -310,16 +313,29 @@ TEST_F(LabelButtonTest, ChangeTextSize) {
const base::string16 text(ASCIIToUTF16("abc"));
const base::string16 longer_text(ASCIIToUTF16("abcdefghijklm"));
button_->SetText(text);
-
+ button_->SizeToPreferredSize();
+ gfx::Rect bounds(button_->bounds());
const int original_width = button_->GetPreferredSize().width();
+ EXPECT_EQ(original_width, bounds.width());
- // The button size increases when the text size is increased.
+ // Reserve more space in the button.
+ bounds.set_width(bounds.width() * 10);
+ button_->SetBoundsRect(bounds);
+
+ // Label view in the button is sized to short text.
+ const int original_label_width = button_->label()->bounds().width();
+
+ // The button preferred size and the label size increase when the text size
+ // is increased.
button_->SetText(longer_text);
- EXPECT_GT(button_->GetPreferredSize().width(), original_width);
+ EXPECT_GT(button_->label()->bounds().width(), original_label_width * 2);
+ EXPECT_GT(button_->GetPreferredSize().width(), original_width * 2);
- // The button returns to its original size when the original text is restored.
+ // The button and the label view return to its original size when the original
+ // text is restored.
button_->SetMinSize(gfx::Size());
button_->SetText(text);
+ EXPECT_EQ(original_label_width, button_->label()->bounds().width());
EXPECT_EQ(original_width, button_->GetPreferredSize().width());
}
@@ -405,6 +421,21 @@ TEST_F(LabelButtonTest, HighlightedButtonStyle) {
default_before->label()->enabled_color());
}
+// Ensure the label gets the correct enabled color after
+// LabelButton::ResetColorsFromNativeTheme() is invoked.
+TEST_F(LabelButtonTest, ResetColorsFromNativeTheme) {
+ ASSERT_FALSE(color_utils::IsInvertedColorScheme());
+ ASSERT_NE(button_->label()->background_color(), SK_ColorBLACK);
+ EXPECT_EQ(themed_normal_text_color_, button_->label()->enabled_color());
+
+ button_->label()->SetBackgroundColor(SK_ColorBLACK);
+ button_->label()->SetAutoColorReadabilityEnabled(true);
+ EXPECT_NE(themed_normal_text_color_, button_->label()->enabled_color());
+
+ button_->ResetColorsFromNativeTheme();
+ EXPECT_EQ(themed_normal_text_color_, button_->label()->enabled_color());
+}
+
// Test fixture for a LabelButton that has an ink drop configured.
class InkDropLabelButtonTest : public ViewsTestBase {
public:
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index 76cd0d335eb..70492dca432 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -7,37 +7,31 @@
#include "base/i18n/case_conversion.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_painted_layer_delegates.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/blue_button.h"
+#include "ui/views/controls/focus_ring.h"
#include "ui/views/painter.h"
+#include "ui/views/style/platform_style.h"
namespace views {
namespace {
-// Inset between clickable region border and button contents (text).
-const int kHorizontalPadding = 16;
-
// Minimum size to reserve for the button contents.
const int kMinWidth = 48;
-// The stroke width of the focus border in normal and call to action mode.
-const int kFocusBorderThickness = 1;
-const int kFocusBorderThicknessCta = 2;
-
-// The corner radius of the focus border roundrect.
-const int kFocusBorderCornerRadius = 3;
-
LabelButton* CreateButton(ButtonListener* listener,
const base::string16& text,
bool md) {
if (md)
- return MdTextButton::CreateMdButton(listener, text);
+ return MdTextButton::Create(listener, text);
LabelButton* button = new LabelButton(listener, text);
button->SetStyle(CustomButton::STYLE_BUTTON);
@@ -55,41 +49,6 @@ const gfx::FontList& GetMdFontList() {
} // namespace
-namespace internal {
-
-class MdFocusRing : public View {
- public:
- MdFocusRing() : thickness_(kFocusBorderThickness) {
- SetPaintToLayer(true);
- layer()->SetFillsBoundsOpaquely(false);
- }
- ~MdFocusRing() override {}
-
- int thickness() const { return thickness_; }
- void set_thickness(int thickness) { thickness_ = thickness; }
-
- // View:
- bool CanProcessEventsWithinSubtree() const override { return false; }
-
- void OnPaint(gfx::Canvas* canvas) override {
- MdTextButton::PaintMdFocusRing(canvas, this, thickness_, 0x33);
- }
-
- private:
- int thickness_;
-
- DISALLOW_COPY_AND_ASSIGN(MdFocusRing);
-};
-
-} // namespace internal
-
-// static
-LabelButton* MdTextButton::CreateStandardButton(ButtonListener* listener,
- const base::string16& text) {
- return CreateButton(listener, text,
- ui::MaterialDesignController::IsModeMaterial());
-}
-
// static
LabelButton* MdTextButton::CreateSecondaryUiButton(ButtonListener* listener,
const base::string16& text) {
@@ -102,8 +61,8 @@ LabelButton* MdTextButton::CreateSecondaryUiBlueButton(
ButtonListener* listener,
const base::string16& text) {
if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- MdTextButton* md_button = MdTextButton::CreateMdButton(listener, text);
- md_button->SetCallToAction(true);
+ MdTextButton* md_button = MdTextButton::Create(listener, text);
+ md_button->SetProminent(true);
return md_button;
}
@@ -111,56 +70,37 @@ LabelButton* MdTextButton::CreateSecondaryUiBlueButton(
}
// static
-MdTextButton* MdTextButton::CreateMdButton(ButtonListener* listener,
- const base::string16& text) {
+MdTextButton* MdTextButton::Create(ButtonListener* listener,
+ const base::string16& text) {
MdTextButton* button = new MdTextButton(listener);
button->SetText(text);
button->SetFocusForPlatform();
return button;
}
-// static
-void MdTextButton::PaintMdFocusRing(gfx::Canvas* canvas,
- views::View* view,
- int thickness,
- SkAlpha alpha) {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SkColorSetA(view->GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_CallToActionColor),
- alpha));
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(thickness);
- gfx::RectF rect(view->GetLocalBounds());
- rect.Inset(gfx::InsetsF(thickness / 2.f));
- canvas->DrawRoundRect(rect, kFocusBorderCornerRadius, paint);
-}
+MdTextButton::~MdTextButton() {}
-void MdTextButton::SetCallToAction(bool cta) {
- if (is_cta_ == cta)
+void MdTextButton::SetProminent(bool is_prominent) {
+ if (is_prominent_ == is_prominent)
return;
- is_cta_ = cta;
- focus_ring_->set_thickness(cta ? kFocusBorderThicknessCta
- : kFocusBorderThickness);
+ is_prominent_ = is_prominent;
UpdateColors();
}
-void MdTextButton::Layout() {
- LabelButton::Layout();
- gfx::Rect focus_bounds = GetLocalBounds();
- focus_bounds.Inset(gfx::Insets(-focus_ring_->thickness()));
- focus_ring_->SetBoundsRect(focus_bounds);
+void MdTextButton::SetBgColorOverride(const base::Optional<SkColor>& color) {
+ bg_color_override_ = color;
+ UpdateColors();
}
void MdTextButton::OnFocus() {
LabelButton::OnFocus();
- focus_ring_->SetVisible(true);
+ FocusRing::Install(this);
}
void MdTextButton::OnBlur() {
LabelButton::OnBlur();
- focus_ring_->SetVisible(false);
+ FocusRing::Uninstall(this);
}
void MdTextButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
@@ -172,16 +112,28 @@ SkColor MdTextButton::GetInkDropBaseColor() const {
return color_utils::DeriveDefaultIconColor(label()->enabled_color());
}
+std::unique_ptr<views::InkDropRipple> MdTextButton::CreateInkDropRipple()
+ const {
+ return std::unique_ptr<views::InkDropRipple>(
+ new views::FloodFillInkDropRipple(
+ GetLocalBounds(), GetInkDropCenterBasedOnLastEvent(),
+ GetInkDropBaseColor(), ink_drop_visible_opacity()));
+}
+
+void MdTextButton::StateChanged() {
+ LabelButton::StateChanged();
+ UpdateColors();
+}
+
std::unique_ptr<views::InkDropHighlight> MdTextButton::CreateInkDropHighlight()
const {
if (!ShouldShowInkDropHighlight())
return nullptr;
- if (!is_cta_)
- return LabelButton::CreateInkDropHighlight();
- // The call to action hover effect is a shadow.
+ // The prominent button hover effect is a shadow.
const int kYOffset = 1;
- const int kSkiaBlurRadius = 1;
+ const int kSkiaBlurRadius = 2;
+ const int shadow_alpha = is_prominent_ ? 0x3D : 0x1A;
std::vector<gfx::ShadowValue> shadows;
// The notion of blur that gfx::ShadowValue uses is twice the Skia/CSS value.
// Skia counts the number of pixels outside the mask area whereas
@@ -189,15 +141,17 @@ std::unique_ptr<views::InkDropHighlight> MdTextButton::CreateInkDropHighlight()
// the mask bounds.
shadows.push_back(gfx::ShadowValue(gfx::Vector2d(0, kYOffset),
2 * kSkiaBlurRadius,
- SkColorSetA(SK_ColorBLACK, 0x3D)));
- return base::WrapUnique(new InkDropHighlight(
+ SkColorSetA(SK_ColorBLACK, shadow_alpha)));
+ const SkColor fill_color =
+ SkColorSetA(SK_ColorWHITE, is_prominent_ ? 0x0D : 0x05);
+ return base::MakeUnique<InkDropHighlight>(
gfx::RectF(GetLocalBounds()).CenterPoint(),
base::WrapUnique(new BorderShadowLayerDelegate(
- shadows, GetLocalBounds(), kInkDropSmallCornerRadius))));
+ shadows, GetLocalBounds(), fill_color, kInkDropSmallCornerRadius)));
}
bool MdTextButton::ShouldShowInkDropForFocus() const {
- // These types of button use |focus_ring_|.
+ // These types of button use FocusRing.
return false;
}
@@ -206,74 +160,119 @@ void MdTextButton::SetEnabledTextColors(SkColor color) {
UpdateColors();
}
+void MdTextButton::SetText(const base::string16& text) {
+ LabelButton::SetText(text);
+ UpdatePadding();
+}
+
+void MdTextButton::AdjustFontSize(int size_delta) {
+ LabelButton::AdjustFontSize(size_delta);
+ UpdatePadding();
+}
+
void MdTextButton::UpdateStyleToIndicateDefaultStatus() {
+ is_prominent_ = is_prominent_ || is_default();
UpdateColors();
}
+void MdTextButton::SetFontList(const gfx::FontList& font_list) {
+ NOTREACHED()
+ << "Don't call MdTextButton::SetFontList (it will soon be protected)";
+}
+
MdTextButton::MdTextButton(ButtonListener* listener)
: LabelButton(listener, base::string16()),
- focus_ring_(new internal::MdFocusRing()),
- is_cta_(false) {
- SetHasInkDrop(true);
+ is_prominent_(false) {
+ SetInkDropMode(PlatformStyle::kUseRipples ? InkDropMode::ON
+ : InkDropMode::OFF);
set_has_ink_drop_action_on_click(true);
SetHorizontalAlignment(gfx::ALIGN_CENTER);
SetFocusForPlatform();
SetMinSize(gfx::Size(kMinWidth, 0));
SetFocusPainter(nullptr);
label()->SetAutoColorReadabilityEnabled(false);
- SetFontList(GetMdFontList());
-
- AddChildView(focus_ring_);
- focus_ring_->SetVisible(false);
set_request_focus_on_press(false);
+ LabelButton::SetFontList(GetMdFontList());
+
+ // Paint to a layer so that the canvas is snapped to pixel boundaries (useful
+ // for fractional DSF).
+ SetPaintToLayer(true);
+ layer()->SetFillsBoundsOpaquely(false);
+}
- // Top and bottom padding depend on the font. Example: if font cap height is
- // 9dp, use 8dp bottom padding and 7dp top padding to total 24dp.
- const gfx::FontList& font = label()->font_list();
- int text_height = font.GetCapHeight();
- int even_text_height = text_height - (text_height % 2);
- const int top_padding = even_text_height - (text_height - even_text_height);
- const int bottom_padding = even_text_height;
- DCHECK_EQ(3 * even_text_height, top_padding + text_height + bottom_padding);
+void MdTextButton::UpdatePadding() {
+ // Don't use font-based padding when there's no text visible.
+ if (GetText().empty()) {
+ SetBorder(Border::NullBorder());
+ return;
+ }
- const int inbuilt_top_padding = font.GetBaseline() - font.GetCapHeight();
- const int inbuilt_bottom_padding =
- font.GetHeight() - label()->font_list().GetBaseline();
+ // Text buttons default to 28dp in height on all platforms when the base font
+ // is in use, but should grow or shrink if the font size is adjusted up or
+ // down. When the system font size has been adjusted, the base font will be
+ // larger than normal such that 28dp might not be enough, so also enforce a
+ // minimum height of twice the font size.
+ // Example 1:
+ // * Normal button on ChromeOS, 12pt Roboto. Button height of 28dp.
+ // * Button on ChromeOS that has been adjusted to 14pt Roboto. Button height
+ // of 28 + 2 * 2 = 32dp.
+ // * Linux user sets base system font size to 17dp. For a normal button, the
+ // |size_delta| will be zero, so to adjust upwards we double 17 to get 34.
+ int size_delta =
+ label()->font_list().GetFontSize() - GetMdFontList().GetFontSize();
+ const int kBaseHeight = 28;
+ int target_height = std::max(kBaseHeight + size_delta * 2,
+ label()->font_list().GetFontSize() * 2);
+
+ int label_height = label()->GetPreferredSize().height();
+ int top_padding = (target_height - label_height) / 2;
+ int bottom_padding = (target_height - label_height + 1) / 2;
+ DCHECK_EQ(target_height, label_height + top_padding + bottom_padding);
// TODO(estade): can we get rid of the platform style border hoopla if
// we apply the MD treatment to all buttons, even GTK buttons?
- SetBorder(Border::CreateEmptyBorder(
- top_padding - inbuilt_top_padding, kHorizontalPadding,
- bottom_padding - inbuilt_bottom_padding, kHorizontalPadding));
+ const int kHorizontalPadding = 16;
+ SetBorder(Border::CreateEmptyBorder(top_padding, kHorizontalPadding,
+ bottom_padding, kHorizontalPadding));
}
-MdTextButton::~MdTextButton() {}
-
void MdTextButton::UpdateColors() {
ui::NativeTheme::ColorId fg_color_id =
- is_cta_ ? ui::NativeTheme::kColorId_TextOnCallToActionColor
- : ui::NativeTheme::kColorId_ButtonEnabledColor;
+ is_prominent_ ? ui::NativeTheme::kColorId_TextOnProminentButtonColor
+ : ui::NativeTheme::kColorId_ButtonEnabledColor;
- // When there's no call to action, respect a color override if one has
- // been set. For call to action styling, don't let individual buttons
- // specify a color.
ui::NativeTheme* theme = GetNativeTheme();
- if (is_cta_ || !explicitly_set_normal_color())
+ if (!explicitly_set_normal_color())
LabelButton::SetEnabledTextColors(theme->GetSystemColor(fg_color_id));
+ // Prominent buttons keep their enabled text color; disabled state is conveyed
+ // by shading the background instead.
+ if (is_prominent_)
+ SetTextColor(STATE_DISABLED, theme->GetSystemColor(fg_color_id));
+
SkColor text_color = label()->enabled_color();
SkColor bg_color =
- is_cta_
- ? theme->GetSystemColor(ui::NativeTheme::kColorId_CallToActionColor)
- : is_default()
- ? color_utils::BlendTowardOppositeLuma(text_color, 0xD8)
- : SK_ColorTRANSPARENT;
+ theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
+
+ if (bg_color_override_) {
+ bg_color = *bg_color_override_;
+ } else if (is_prominent_) {
+ bg_color = theme->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor);
+ if (state() == STATE_DISABLED)
+ bg_color = color_utils::BlendTowardOppositeLuma(
+ bg_color, gfx::kDisabledControlAlpha);
+ }
- const SkAlpha kStrokeOpacity = 0x1A;
- SkColor stroke_color = (is_cta_ || color_utils::IsDark(text_color))
- ? SkColorSetA(SK_ColorBLACK, kStrokeOpacity)
- : SkColorSetA(SK_ColorWHITE, 2 * kStrokeOpacity);
+ if (state() == STATE_PRESSED) {
+ SkColor shade =
+ theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonPressedShade);
+ bg_color = color_utils::GetResultingPaintColor(shade, bg_color);
+ }
+ SkColor stroke_color =
+ is_prominent_ ? SK_ColorTRANSPARENT : SkColorSetA(text_color, 0x33);
+ DCHECK_EQ(SK_AlphaOPAQUE, static_cast<int>(SkColorGetA(bg_color)));
set_background(Background::CreateBackgroundPainter(
true, Painter::CreateRoundRectWith1PxBorderPainter(
bg_color, stroke_color, kInkDropSmallCornerRadius)));
diff --git a/chromium/ui/views/controls/button/md_text_button.h b/chromium/ui/views/controls/button/md_text_button.h
index 687de5e43f5..0da68d4bfca 100644
--- a/chromium/ui/views/controls/button/md_text_button.h
+++ b/chromium/ui/views/controls/button/md_text_button.h
@@ -7,63 +7,61 @@
#include <memory>
+#include "base/optional.h"
#include "ui/views/controls/button/label_button.h"
namespace views {
-namespace internal {
-class MdFocusRing;
-} // namespace internal
-
// A button class that implements the Material Design text button spec.
class VIEWS_EXPORT MdTextButton : public LabelButton {
public:
- // Creates a normal STYLE_BUTTON LabelButton in pre-MD, or an MdTextButton
- // in MD mode.
- static LabelButton* CreateStandardButton(ButtonListener* listener,
- const base::string16& text);
// As above, but only creates an MdTextButton if MD is enabled in the
// secondary UI (as opposed to just "top chrome"/"primary" UI).
static LabelButton* CreateSecondaryUiButton(ButtonListener* listener,
const base::string16& text);
static LabelButton* CreateSecondaryUiBlueButton(ButtonListener* listener,
const base::string16& text);
- static MdTextButton* CreateMdButton(ButtonListener* listener,
- const base::string16& text);
+ static MdTextButton* Create(ButtonListener* listener,
+ const base::string16& text);
+
+ ~MdTextButton() override;
- // Paint an MD-style focus ring on the given canvas at the given bounds.
- static void PaintMdFocusRing(gfx::Canvas* canvas,
- View* view,
- int thickness,
- SkAlpha alpha);
+ // See |is_prominent_|.
+ void SetProminent(bool is_prominent);
- void SetCallToAction(bool cta);
+ // See |bg_color_override_|.
+ void SetBgColorOverride(const base::Optional<SkColor>& color);
// LabelButton:
- void Layout() override;
void OnFocus() override;
void OnBlur() override;
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
+ std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
const override;
SkColor GetInkDropBaseColor() const override;
bool ShouldShowInkDropForFocus() const override;
void SetEnabledTextColors(SkColor color) override;
+ void SetText(const base::string16& text) override;
+ void AdjustFontSize(int size_delta) override;
void UpdateStyleToIndicateDefaultStatus() override;
+ void StateChanged() override;
+
+ protected:
+ // LabelButton:
+ void SetFontList(const gfx::FontList& font_list) override;
private:
- MdTextButton(ButtonListener* listener);
- ~MdTextButton() override;
+ explicit MdTextButton(ButtonListener* listener);
+ void UpdatePadding();
void UpdateColors();
- // The MD-style focus ring. This is not done via a FocusPainter
- // because it needs to paint to a layer so it can extend beyond the bounds of
- // |this|.
- internal::MdFocusRing* focus_ring_;
+ // True if this button uses prominent styling (blue fill, etc.).
+ bool is_prominent_;
- // True if this button uses call-to-action styling.
- bool is_cta_;
+ // When set, this provides the background color.
+ base::Optional<SkColor> bg_color_override_;
DISALLOW_COPY_AND_ASSIGN(MdTextButton);
};
diff --git a/chromium/ui/views/controls/button/menu_button.cc b/chromium/ui/views/controls/button/menu_button.cc
index b89184916bd..38fc310aa62 100644
--- a/chromium/ui/views/controls/button/menu_button.cc
+++ b/chromium/ui/views/controls/button/menu_button.cc
@@ -9,7 +9,6 @@
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_switches_util.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
@@ -146,8 +145,6 @@ bool MenuButton::Activate(const ui::Event* event) {
increment_pressed_lock_called_ = nullptr;
destroyed_flag_ = nullptr;
- menu_closed_time_ = TimeTicks::Now();
-
if (!increment_pressed_lock_called && pressed_lock_count_ == 0) {
AnimateInkDrop(InkDropState::ACTION_TRIGGERED,
ui::LocatedEvent::FromIfValid(event));
@@ -256,17 +253,15 @@ void MenuButton::OnGestureEvent(ui::GestureEvent* event) {
SetState(Button::STATE_NORMAL);
return;
}
- if (switches::IsTouchFeedbackEnabled()) {
- if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
- event->SetHandled();
- if (pressed_lock_count_ == 0)
- SetState(Button::STATE_HOVERED);
- } else if (state() == Button::STATE_HOVERED &&
- (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
- event->type() == ui::ET_GESTURE_END) &&
- pressed_lock_count_ == 0) {
- SetState(Button::STATE_NORMAL);
- }
+ if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
+ event->SetHandled();
+ if (pressed_lock_count_ == 0)
+ SetState(Button::STATE_HOVERED);
+ } else if (state() == Button::STATE_HOVERED &&
+ (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
+ event->type() == ui::ET_GESTURE_END) &&
+ pressed_lock_count_ == 0) {
+ SetState(Button::STATE_NORMAL);
}
}
LabelButton::OnGestureEvent(event);
@@ -390,6 +385,7 @@ void MenuButton::DecrementPressedLocked() {
// If this was the last lock, manually reset state to the desired state.
if (pressed_lock_count_ == 0) {
+ menu_closed_time_ = TimeTicks::Now();
ButtonState desired_state = STATE_NORMAL;
if (should_disable_after_press_) {
desired_state = STATE_DISABLED;
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index cf1008020ac..451df585bb2 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -67,40 +67,6 @@ RadioButton::RadioButton(const base::string16& label, int group_id)
RadioButton::~RadioButton() {
}
-void RadioButton::SetChecked(bool checked) {
- if (checked == RadioButton::checked())
- return;
- if (checked) {
- // We can't just get the root view here because sometimes the radio
- // button isn't attached to a root view (e.g., if it's part of a tab page
- // that is currently not active).
- View* container = parent();
- while (container && container->parent())
- container = container->parent();
- if (container) {
- Views other;
- container->GetViewsInGroup(GetGroup(), &other);
- for (Views::iterator i(other.begin()); i != other.end(); ++i) {
- if (*i != this) {
- if (strcmp((*i)->GetClassName(), kViewClassName)) {
- NOTREACHED() << "radio-button-nt has same group as other non "
- "radio-button-nt views.";
- continue;
- }
- RadioButton* peer = static_cast<RadioButton*>(*i);
- peer->SetChecked(false);
- }
- }
- }
- }
- Checkbox::SetChecked(checked);
-}
-
-void RadioButton::PaintFocusRing(gfx::Canvas* canvas, const SkPaint& paint) {
- canvas->DrawCircle(gfx::PointF(image()->bounds().CenterPoint()),
- image()->width() / 2 + .5f, paint);
-}
-
const char* RadioButton::GetClassName() const {
return kViewClassName;
}
@@ -152,16 +118,43 @@ ui::NativeTheme::Part RadioButton::GetThemePart() const {
return ui::NativeTheme::kRadio;
}
-gfx::ImageSkia RadioButton::GetImage(ButtonState for_state) const {
- if (!UseMd())
- return Checkbox::GetImage(for_state);
+void RadioButton::SetChecked(bool checked) {
+ if (checked == RadioButton::checked())
+ return;
+ if (checked) {
+ // We can't just get the root view here because sometimes the radio
+ // button isn't attached to a root view (e.g., if it's part of a tab page
+ // that is currently not active).
+ View* container = parent();
+ while (container && container->parent())
+ container = container->parent();
+ if (container) {
+ Views other;
+ container->GetViewsInGroup(GetGroup(), &other);
+ for (Views::iterator i(other.begin()); i != other.end(); ++i) {
+ if (*i != this) {
+ if (strcmp((*i)->GetClassName(), kViewClassName)) {
+ NOTREACHED() << "radio-button-nt has same group as other non "
+ "radio-button-nt views.";
+ continue;
+ }
+ RadioButton* peer = static_cast<RadioButton*>(*i);
+ peer->SetChecked(false);
+ }
+ }
+ }
+ }
+ Checkbox::SetChecked(checked);
+}
+
+void RadioButton::PaintFocusRing(gfx::Canvas* canvas, const SkPaint& paint) {
+ canvas->DrawCircle(gfx::RectF(image()->bounds()).CenterPoint(),
+ image()->width() / 2, paint);
+}
- return gfx::CreateVectorIcon(
- checked() ? gfx::VectorIconId::RADIO_BUTTON_ACTIVE
- : gfx::VectorIconId::RADIO_BUTTON_NORMAL,
- 16, GetNativeTheme()->GetSystemColor(
- checked() ? ui::NativeTheme::kColorId_FocusedBorderColor
- : ui::NativeTheme::kColorId_UnfocusedBorderColor));
+gfx::VectorIconId RadioButton::GetVectorIconId() const {
+ return checked() ? gfx::VectorIconId::RADIO_BUTTON_ACTIVE
+ : gfx::VectorIconId::RADIO_BUTTON_NORMAL;
}
} // namespace views
diff --git a/chromium/ui/views/controls/button/radio_button.h b/chromium/ui/views/controls/button/radio_button.h
index e2858d37783..f28968abd5b 100644
--- a/chromium/ui/views/controls/button/radio_button.h
+++ b/chromium/ui/views/controls/button/radio_button.h
@@ -33,11 +33,11 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
// Overridden from LabelButton:
ui::NativeTheme::Part GetThemePart() const override;
- gfx::ImageSkia GetImage(ButtonState for_state) const override;
// Overridden from Checkbox:
void SetChecked(bool checked) override;
void PaintFocusRing(gfx::Canvas* canvas, const SkPaint& paint) override;
+ gfx::VectorIconId GetVectorIconId() const override;
private:
DISALLOW_COPY_AND_ASSIGN(RadioButton);
diff --git a/chromium/ui/views/controls/button/toggle_button.cc b/chromium/ui/views/controls/button/toggle_button.cc
new file mode 100644
index 00000000000..30bf562a548
--- /dev/null
+++ b/chromium/ui/views/controls/button/toggle_button.cc
@@ -0,0 +1,147 @@
+// Copyright 2016 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/controls/button/toggle_button.h"
+
+#include "third_party/skia/include/core/SkDrawLooper.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/views/animation/ink_drop_ripple.h"
+#include "ui/views/border.h"
+
+namespace views {
+
+namespace {
+
+// Constants are measured in dip.
+const int kTrackHeight = 12;
+const int kTrackWidth = 28;
+// Margins from edge of track to edge of view.
+const int kTrackVerticalMargin = 5;
+const int kTrackHorizontalMargin = 6;
+// Margin from edge of thumb to closest edge of view. Note that the thumb
+// margins must be sufficiently large to allow space for the shadow.
+const int kThumbHorizontalMargin = 4;
+// Margin from top/bottom edge of thumb to top/bottom edge of view.
+const int kThumbVerticalMargin = 3;
+
+// TODO(estade): get the base color (black) from the theme?
+const SkColor kTrackOffColor =
+ SkColorSetA(SK_ColorBLACK, gfx::kDisabledControlAlpha);
+
+} // namespace
+
+ToggleButton::ToggleButton(ButtonListener* listener)
+ : CustomButton(listener), is_on_(false), slide_animation_(this) {
+ slide_animation_.SetSlideDuration(80 /* ms */);
+ slide_animation_.SetTweenType(gfx::Tween::LINEAR);
+ SetBorder(Border::CreateEmptyBorder(
+ gfx::Insets(kTrackVerticalMargin, kTrackHorizontalMargin)));
+ SetInkDropMode(InkDropMode::ON);
+ set_has_ink_drop_action_on_click(true);
+}
+
+ToggleButton::~ToggleButton() {}
+
+void ToggleButton::SetIsOn(bool is_on, bool animate) {
+ if (is_on_ == is_on)
+ return;
+
+ is_on_ = is_on;
+ if (!animate)
+ slide_animation_.Reset(is_on_ ? 1.0 : 0.0);
+ else if (is_on_)
+ slide_animation_.Show();
+ else
+ slide_animation_.Hide();
+}
+
+gfx::Size ToggleButton::GetPreferredSize() const {
+ gfx::Rect rect(0, 0, kTrackWidth, kTrackHeight);
+ if (border())
+ rect.Inset(-border()->GetInsets());
+ return rect.size();
+}
+
+void ToggleButton::OnPaint(gfx::Canvas* canvas) {
+ SkAlpha blend =
+ static_cast<SkAlpha>(SK_AlphaOPAQUE * slide_animation_.GetCurrentValue());
+
+ // Track.
+ gfx::RectF track_rect(GetContentsBounds());
+ SkPaint track_paint;
+ track_paint.setAntiAlias(true);
+ const SkColor track_on_color =
+ SkColorSetA(GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor),
+ 0xFF / 2);
+ track_paint.setColor(
+ color_utils::AlphaBlend(track_on_color, kTrackOffColor, blend));
+ canvas->DrawRoundRect(track_rect, track_rect.height() / 2, track_paint);
+
+ // Thumb.
+ gfx::Rect thumb_bounds = GetThumbBounds();
+ SkPaint thumb_paint;
+ std::vector<gfx::ShadowValue> shadows;
+ shadows.emplace_back(gfx::Vector2d(0, 1), 4.f,
+ SkColorSetA(SK_ColorBLACK, 0x99));
+ thumb_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows));
+ thumb_paint.setStyle(SkPaint::kFill_Style);
+ thumb_paint.setAntiAlias(true);
+ const SkColor thumb_on_color = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor);
+ // TODO(estade): get this color from the theme?
+ const SkColor thumb_off_color = SK_ColorWHITE;
+ thumb_paint.setColor(
+ color_utils::AlphaBlend(thumb_on_color, thumb_off_color, blend));
+ canvas->DrawCircle(gfx::RectF(thumb_bounds).CenterPoint(),
+ thumb_bounds.height() / 2.f, thumb_paint);
+}
+
+void ToggleButton::NotifyClick(const ui::Event& event) {
+ SetIsOn(!is_on(), true);
+ CustomButton::NotifyClick(event);
+}
+
+void ToggleButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ SchedulePaint();
+}
+
+std::unique_ptr<InkDropRipple> ToggleButton::CreateInkDropRipple() const {
+ return CreateDefaultInkDropRipple(GetThumbBounds().CenterPoint());
+}
+
+SkColor ToggleButton::GetInkDropBaseColor() const {
+ return is_on()
+ ? GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor)
+ : kTrackOffColor;
+}
+
+bool ToggleButton::ShouldShowInkDropHighlight() const {
+ return false;
+}
+
+void ToggleButton::AnimationProgressed(const gfx::Animation* animation) {
+ if (animation == &slide_animation_)
+ SchedulePaint();
+ else
+ CustomButton::AnimationProgressed(animation);
+}
+
+gfx::Rect ToggleButton::GetThumbBounds() const {
+ gfx::Rect thumb_bounds = GetLocalBounds();
+ thumb_bounds.Inset(gfx::Insets(kThumbVerticalMargin, kThumbHorizontalMargin));
+ thumb_bounds.set_x(thumb_bounds.x() +
+ slide_animation_.GetCurrentValue() *
+ (thumb_bounds.width() - thumb_bounds.height()));
+ // The thumb is a circle, so the width should match the height.
+ thumb_bounds.set_width(thumb_bounds.height());
+ thumb_bounds.set_x(GetMirroredXForRect(thumb_bounds));
+ return thumb_bounds;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/toggle_button.h b/chromium/ui/views/controls/button/toggle_button.h
new file mode 100644
index 00000000000..347d1d050a3
--- /dev/null
+++ b/chromium/ui/views/controls/button/toggle_button.h
@@ -0,0 +1,48 @@
+// Copyright 2016 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_CONTROLS_BUTTON_TOGGLE_BUTTON_H_
+#define UI_VIEWS_CONTROLS_BUTTON_TOGGLE_BUTTON_H_
+
+#include "ui/gfx/animation/slide_animation.h"
+#include "ui/views/controls/button/custom_button.h"
+
+namespace views {
+
+// This view presents a button that has two states: on and off. This is similar
+// to a checkbox but has no text and looks more like a two-state horizontal
+// slider.
+class VIEWS_EXPORT ToggleButton : public CustomButton {
+ public:
+ explicit ToggleButton(ButtonListener* listener);
+ ~ToggleButton() override;
+
+ void SetIsOn(bool is_on, bool animate);
+ bool is_on() const { return is_on_; }
+
+ private:
+ // CustomButton:
+ gfx::Size GetPreferredSize() const override;
+ void OnPaint(gfx::Canvas* canvas) override;
+ void NotifyClick(const ui::Event& event) override;
+ void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
+ std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
+ SkColor GetInkDropBaseColor() const override;
+ bool ShouldShowInkDropHighlight() const override;
+
+ // gfx::AnimationDelegate:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+
+ // Calculates the bounding box for the thumb (the circle).
+ gfx::Rect GetThumbBounds() const;
+
+ bool is_on_;
+ gfx::SlideAnimation slide_animation_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToggleButton);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_BUTTON_TOGGLE_BUTTON_H_
diff --git a/chromium/ui/views/controls/button/vector_icon_button.cc b/chromium/ui/views/controls/button/vector_icon_button.cc
new file mode 100644
index 00000000000..6fc94971e63
--- /dev/null
+++ b/chromium/ui/views/controls/button/vector_icon_button.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 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/controls/button/vector_icon_button.h"
+
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/vector_icons_public.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/vector_icon_button_delegate.h"
+#include "ui/views/painter.h"
+
+namespace views {
+
+namespace {
+
+// Extra space around the buttons to increase their event target size.
+const int kButtonExtraTouchSize = 4;
+
+} // namespace
+
+VectorIconButton::VectorIconButton(VectorIconButtonDelegate* delegate)
+ : views::ImageButton(delegate),
+ delegate_(delegate),
+ id_(gfx::VectorIconId::VECTOR_ICON_NONE) {
+ SetInkDropMode(InkDropMode::ON);
+ set_has_ink_drop_action_on_click(true);
+ SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+ views::ImageButton::ALIGN_MIDDLE);
+ SetFocusPainter(nullptr);
+}
+
+VectorIconButton::~VectorIconButton() {}
+
+void VectorIconButton::SetIcon(gfx::VectorIconId id) {
+ id_ = id;
+
+ if (!border()) {
+ SetBorder(views::Border::CreateEmptyBorder(
+ kButtonExtraTouchSize, kButtonExtraTouchSize, kButtonExtraTouchSize,
+ kButtonExtraTouchSize));
+ }
+}
+
+void VectorIconButton::OnThemeChanged() {
+ SkColor icon_color =
+ color_utils::DeriveDefaultIconColor(delegate_->GetVectorIconBaseColor());
+ gfx::ImageSkia image = gfx::CreateVectorIcon(id_, icon_color);
+ SetImage(views::CustomButton::STATE_NORMAL, &image);
+ image = gfx::CreateVectorIcon(id_, SkColorSetA(icon_color, 0xff / 2));
+ SetImage(views::CustomButton::STATE_DISABLED, &image);
+ set_ink_drop_base_color(icon_color);
+}
+
+void VectorIconButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ OnThemeChanged();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/vector_icon_button.h b/chromium/ui/views/controls/button/vector_icon_button.h
new file mode 100644
index 00000000000..dd994051a50
--- /dev/null
+++ b/chromium/ui/views/controls/button/vector_icon_button.h
@@ -0,0 +1,43 @@
+// Copyright 2015 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_CONTROLS_BUTTON_VECTOR_ICON_BUTTON_H_
+#define UI_VIEWS_CONTROLS_BUTTON_VECTOR_ICON_BUTTON_H_
+
+#include "base/macros.h"
+#include "ui/views/controls/button/image_button.h"
+
+namespace gfx {
+enum class VectorIconId;
+}
+
+namespace views {
+
+class VectorIconButtonDelegate;
+
+// A button that has an image and no text, with the image defined by a vector
+// icon identifier.
+class VIEWS_EXPORT VectorIconButton : public views::ImageButton {
+ public:
+ explicit VectorIconButton(VectorIconButtonDelegate* delegate);
+ ~VectorIconButton() override;
+
+ // Sets the icon to display and provides a callback which should return the
+ // text color from which to derive this icon's color.
+ void SetIcon(gfx::VectorIconId id);
+
+ // views::ImageButton:
+ void OnThemeChanged() override;
+ void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
+
+ private:
+ VectorIconButtonDelegate* delegate_;
+ gfx::VectorIconId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(VectorIconButton);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_BUTTON_VECTOR_ICON_BUTTON_H_
diff --git a/chromium/ui/views/controls/button/vector_icon_button_delegate.cc b/chromium/ui/views/controls/button/vector_icon_button_delegate.cc
new file mode 100644
index 00000000000..f2240cc4cd7
--- /dev/null
+++ b/chromium/ui/views/controls/button/vector_icon_button_delegate.cc
@@ -0,0 +1,13 @@
+// Copyright 2016 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/controls/button/vector_icon_button_delegate.h"
+
+namespace views {
+
+SkColor VectorIconButtonDelegate::GetVectorIconBaseColor() const {
+ return SK_ColorBLACK;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/vector_icon_button_delegate.h b/chromium/ui/views/controls/button/vector_icon_button_delegate.h
new file mode 100644
index 00000000000..e4cccaa6790
--- /dev/null
+++ b/chromium/ui/views/controls/button/vector_icon_button_delegate.h
@@ -0,0 +1,25 @@
+// Copyright 2016 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_CONTROLS_BUTTON_VECTOR_ICON_DELEGATE_BUTTON_H_
+#define UI_VIEWS_CONTROLS_BUTTON_VECTOR_ICON_DELEGATE_BUTTON_H_
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// A ButtonListener that also provides a color to use for drawing an icon.
+class VIEWS_EXPORT VectorIconButtonDelegate : public ButtonListener {
+ public:
+ virtual SkColor GetVectorIconBaseColor() const;
+
+ protected:
+ ~VectorIconButtonDelegate() override {}
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_BUTTON_VECTOR_ICON_BUTTON_DELEGATE_H_
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index e888c4dec06..cc474726ba9 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -14,6 +14,7 @@
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/default_style.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/models/combobox_model_observer.h"
#include "ui/base/resource/resource_bundle.h"
@@ -27,12 +28,16 @@
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_aura.h"
#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
+#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox_listener.h"
+#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/focusable_border.h"
#include "ui/views/controls/menu/menu_config.h"
+#include "ui/views/controls/menu/menu_model_adapter.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/prefix_selector.h"
#include "ui/views/controls/textfield/textfield.h"
@@ -87,6 +92,10 @@ const int kFocusedPressedMenuButtonImages[] =
#undef MENU_IMAGE_GRID
+bool UseMd() {
+ return ui::MaterialDesignController::IsSecondaryUiMaterial();
+}
+
gfx::Rect PositionArrowWithinContainer(const gfx::Rect& container_bounds,
const gfx::Size& arrow_size,
Combobox::Style style) {
@@ -106,22 +115,46 @@ gfx::Rect PositionArrowWithinContainer(const gfx::Rect& container_bounds,
// The transparent button which holds a button state but is not rendered.
class TransparentButton : public CustomButton {
public:
- TransparentButton(ButtonListener* listener)
+ TransparentButton(ButtonListener* listener, bool animate_state_change)
: CustomButton(listener) {
- SetAnimationDuration(LabelButton::kHoverAnimationDurationMs);
+ set_animate_on_state_change(animate_state_change);
+ if (animate_state_change)
+ SetAnimationDuration(LabelButton::kHoverAnimationDurationMs);
SetFocusBehavior(FocusBehavior::NEVER);
+ set_notify_action(PlatformStyle::kMenuNotifyActivationAction);
+
+ if (UseMd()) {
+ SetInkDropMode(PlatformStyle::kUseRipples ? InkDropMode::ON
+ : InkDropMode::OFF);
+ set_has_ink_drop_action_on_click(true);
+ }
}
~TransparentButton() override {}
bool OnMousePressed(const ui::MouseEvent& mouse_event) override {
- parent()->RequestFocus();
- return true;
+ if (!UseMd())
+ parent()->RequestFocus();
+ return CustomButton::OnMousePressed(mouse_event);
}
double GetAnimationValue() const {
return hover_animation().GetCurrentValue();
}
+ // Overridden from InkDropHost:
+ std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override {
+ return std::unique_ptr<views::InkDropRipple>(
+ new views::FloodFillInkDropRipple(
+ GetLocalBounds(), GetInkDropCenterBasedOnLastEvent(),
+ GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_LabelEnabledColor),
+ ink_drop_visible_opacity()));
+ }
+
+ std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const override {
+ return nullptr;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(TransparentButton);
};
@@ -244,15 +277,15 @@ void PaintArrowButton(
const char Combobox::kViewClassName[] = "views/Combobox";
// Adapts a ui::ComboboxModel to a ui::MenuModel.
-class Combobox::ComboboxMenuModelAdapter : public ui::MenuModel,
- public ui::ComboboxModelObserver {
+class Combobox::ComboboxMenuModel : public ui::MenuModel,
+ public ui::ComboboxModelObserver {
public:
- ComboboxMenuModelAdapter(Combobox* owner, ui::ComboboxModel* model)
+ ComboboxMenuModel(Combobox* owner, ui::ComboboxModel* model)
: owner_(owner), model_(model) {
model_->AddObserver(this);
}
- ~ComboboxMenuModelAdapter() override { model_->RemoveObserver(this); }
+ ~ComboboxMenuModel() override { model_->RemoveObserver(this); }
private:
bool UseCheckmarks() const {
@@ -351,7 +384,7 @@ class Combobox::ComboboxMenuModelAdapter : public ui::MenuModel,
Combobox* owner_; // Weak. Owns this.
ui::ComboboxModel* model_; // Weak.
- DISALLOW_COPY_AND_ASSIGN(ComboboxMenuModelAdapter);
+ DISALLOW_COPY_AND_ASSIGN(ComboboxMenuModel);
};
////////////////////////////////////////////////////////////////////////////////
@@ -360,12 +393,12 @@ class Combobox::ComboboxMenuModelAdapter : public ui::MenuModel,
Combobox::Combobox(ui::ComboboxModel* model, Style style)
: model_(model),
style_(style),
- listener_(NULL),
+ listener_(nullptr),
selected_index_(style == STYLE_ACTION ? 0 : model_->GetDefaultIndex()),
invalid_(false),
- menu_model_adapter_(new ComboboxMenuModelAdapter(this, model)),
- text_button_(new TransparentButton(this)),
- arrow_button_(new TransparentButton(this)),
+ menu_model_(new ComboboxMenuModel(this, model)),
+ text_button_(new TransparentButton(this, style_ == STYLE_ACTION)),
+ arrow_button_(new TransparentButton(this, style_ == STYLE_ACTION)),
size_to_largest_label_(style_ == STYLE_NORMAL),
weak_ptr_factory_(this) {
ModelChanged();
@@ -376,11 +409,12 @@ Combobox::Combobox(ui::ComboboxModel* model, Style style)
#endif
UpdateBorder();
- arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style);
- // set_background() takes ownership but takes a raw pointer.
- std::unique_ptr<Background> b =
- PlatformStyle::CreateComboboxBackground(GetArrowContainerWidth());
- set_background(b.release());
+ if (UseMd()) {
+ // set_background() takes ownership but takes a raw pointer.
+ std::unique_ptr<Background> b =
+ PlatformStyle::CreateComboboxBackground(GetArrowContainerWidth());
+ set_background(b.release());
+ }
// Initialize the button images.
Button::ButtonState button_states[] = {
@@ -406,6 +440,15 @@ Combobox::Combobox(ui::ComboboxModel* model, Style style)
arrow_button_->SetVisible(true);
AddChildView(text_button_);
AddChildView(arrow_button_);
+
+ // A layer is applied to make sure that canvas bounds are snapped to pixel
+ // boundaries (for the sake of drawing the arrow).
+ if (UseMd()) {
+ SetPaintToLayer(true);
+ layer()->SetFillsBoundsOpaquely(false);
+ } else {
+ arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style);
+ }
}
Combobox::~Combobox() {
@@ -475,7 +518,7 @@ void Combobox::SetInvalid(bool invalid) {
}
void Combobox::Layout() {
- PrefixDelegate::Layout();
+ View::Layout();
int text_button_width = 0;
int arrow_button_width = 0;
@@ -498,8 +541,20 @@ void Combobox::Layout() {
}
void Combobox::OnEnabledChanged() {
- PrefixDelegate::OnEnabledChanged();
- arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style_);
+ View::OnEnabledChanged();
+ if (!UseMd())
+ arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style_);
+}
+
+void Combobox::OnNativeThemeChanged(const ui::NativeTheme* theme) {
+ if (!UseMd())
+ return;
+
+ set_background(Background::CreateBackgroundPainter(
+ true, Painter::CreateSolidRoundRectPainter(
+ theme->GetSystemColor(
+ ui::NativeTheme::kColorId_TextfieldDefaultBackground),
+ FocusableBorder::kCornerRadiusDp)));
}
int Combobox::GetRowCount() {
@@ -595,22 +650,21 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
new_index = GetAdjacentIndex(model(), -1, selected_index_);
break;
- // Click the button only when the button style mode.
case ui::VKEY_SPACE:
if (style_ == STYLE_ACTION) {
// When pressing space, the click event will be raised after the key is
// released.
text_button_->SetState(Button::STATE_PRESSED);
} else {
- return false;
+ show_menu = true;
}
break;
- // Click the button only when the button style mode.
case ui::VKEY_RETURN:
- if (style_ != STYLE_ACTION)
- return false;
- OnPerformAction();
+ if (style_ == STYLE_ACTION)
+ OnPerformAction();
+ else
+ show_menu = true;
break;
default:
@@ -662,6 +716,8 @@ void Combobox::OnFocus() {
View::OnFocus();
// Border renders differently when focused.
SchedulePaint();
+ if (UseMd())
+ FocusRing::Install(this);
}
void Combobox::OnBlur() {
@@ -672,6 +728,8 @@ void Combobox::OnBlur() {
selector_->OnViewBlur();
// Border renders differently when focused.
SchedulePaint();
+ if (UseMd())
+ FocusRing::Uninstall(this);
}
void Combobox::GetAccessibleState(ui::AXViewState* state) {
@@ -686,7 +744,8 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
if (!enabled())
return;
- RequestFocus();
+ if (!UseMd())
+ RequestFocus();
if (sender == text_button_) {
OnPerformAction();
@@ -732,8 +791,10 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
int y = insets.top();
int text_height = height() - insets.height();
SkColor text_color = GetNativeTheme()->GetSystemColor(
- enabled() ? ui::NativeTheme::kColorId_LabelEnabledColor :
- ui::NativeTheme::kColorId_LabelDisabledColor);
+ UseMd() ? (enabled() ? ui::NativeTheme::kColorId_TextfieldDefaultColor
+ : ui::NativeTheme::kColorId_TextfieldReadOnlyColor)
+ : (enabled() ? ui::NativeTheme::kColorId_LabelEnabledColor
+ : ui::NativeTheme::kColorId_LabelDisabledColor));
DCHECK_GE(selected_index_, 0);
DCHECK_LT(selected_index_, model()->GetItemCount());
@@ -758,13 +819,41 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
PositionArrowWithinContainer(arrow_bounds, ArrowSize(), style_);
AdjustBoundsForRTLUI(&arrow_bounds);
- canvas->DrawImageInt(arrow_image_, arrow_bounds.x(), arrow_bounds.y());
+ if (UseMd()) {
+ // Since this is a core piece of UI and vector icons don't handle fractional
+ // scale factors particularly well, manually draw an arrow and make sure it
+ // looks good at all scale factors.
+ float dsf = canvas->UndoDeviceScaleFactor();
+ SkScalar x = std::ceil(arrow_bounds.x() * dsf);
+ SkScalar y = std::ceil(arrow_bounds.y() * dsf);
+ SkScalar height = std::floor(arrow_bounds.height() * dsf);
+ SkPath path;
+ // This epsilon makes sure that all the aliasing pixels are slightly more
+ // than half full. Otherwise, rounding issues cause some to be considered
+ // slightly less than half full and come out a little lighter.
+ const SkScalar kEpsilon = 0.0001f;
+ path.moveTo(x - kEpsilon, y);
+ path.rLineTo(height, height);
+ path.rLineTo(2 * kEpsilon, 0);
+ path.rLineTo(height, -height);
+ path.close();
+ SkPaint paint;
+ SkColor arrow_color = GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ButtonEnabledColor);
+ if (!enabled())
+ arrow_color = SkColorSetA(arrow_color, gfx::kDisabledControlAlpha);
+ paint.setColor(arrow_color);
+ paint.setAntiAlias(true);
+ canvas->DrawPath(path, paint);
+ } else {
+ canvas->DrawImageInt(arrow_image_, arrow_bounds.x(), arrow_bounds.y());
+ }
}
void Combobox::PaintButtons(gfx::Canvas* canvas) {
DCHECK(style_ == STYLE_ACTION);
- gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, bounds());
+ gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, width());
bool focused = HasFocus();
const std::vector<const gfx::ImageSkia*>& arrow_button_images =
@@ -841,16 +930,22 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
// Allow |menu_runner_| to be set by the testing API, but if this method is
// ever invoked recursively, ensure the old menu is closed.
if (!menu_runner_ || menu_runner_->IsRunning()) {
+ menu_model_adapter_.reset(new MenuModelAdapter(
+ menu_model_.get(), base::Bind(&Combobox::OnMenuClosed,
+ base::Unretained(this), original_state)));
menu_runner_.reset(
- new MenuRunner(menu_model_adapter_.get(), MenuRunner::COMBOBOX));
- }
- if (menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, anchor_position,
- source_type) == MenuRunner::MENU_DELETED) {
- return;
+ new MenuRunner(menu_model_adapter_->CreateMenu(),
+ MenuRunner::COMBOBOX | MenuRunner::ASYNC));
}
+ menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, anchor_position,
+ source_type);
+}
+
+void Combobox::OnMenuClosed(Button::ButtonState original_button_state) {
menu_runner_.reset();
+ menu_model_adapter_.reset();
if (arrow_button_)
- arrow_button_->SetState(original_state);
+ arrow_button_->SetState(original_button_state);
closed_time_ = base::Time::Now();
// Need to explicitly clear mouse handler so that events get sent
@@ -873,7 +968,7 @@ void Combobox::OnPerformAction() {
}
gfx::Size Combobox::ArrowSize() const {
- return arrow_image_.size();
+ return UseMd() ? gfx::Size(8, 4) : arrow_image_.size();
}
gfx::Size Combobox::GetContentSize() const {
@@ -886,8 +981,7 @@ gfx::Size Combobox::GetContentSize() const {
if (size_to_largest_label_ || i == selected_index_) {
width = std::max(
- width,
- gfx::GetStringWidth(menu_model_adapter_->GetLabelAt(i), font_list));
+ width, gfx::GetStringWidth(menu_model_->GetLabelAt(i), font_list));
}
}
return gfx::Size(width, font_list.GetHeight());
@@ -895,13 +989,16 @@ gfx::Size Combobox::GetContentSize() const {
PrefixSelector* Combobox::GetPrefixSelector() {
if (!selector_)
- selector_.reset(new PrefixSelector(this));
+ selector_.reset(new PrefixSelector(this, this));
return selector_.get();
}
int Combobox::GetArrowContainerWidth() const {
+ const int kMdPaddingWidth = 8;
+ int arrow_pad = UseMd() ? kMdPaddingWidth
+ : PlatformStyle::kComboboxNormalArrowPadding;
int padding = style_ == STYLE_NORMAL
- ? PlatformStyle::kComboboxNormalArrowPadding * 2
+ ? arrow_pad * 2
: kActionLeftPadding + kActionRightPadding;
return ArrowSize().width() + padding;
}
diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h
index 5cd44549de0..12c0bec723f 100644
--- a/chromium/ui/views/controls/combobox/combobox.h
+++ b/chromium/ui/views/controls/combobox/combobox.h
@@ -28,6 +28,7 @@ class ComboboxTestApi;
class ComboboxListener;
class CustomButton;
+class MenuModelAdapter;
class MenuRunner;
class Painter;
class PrefixSelector;
@@ -41,7 +42,9 @@ class PrefixSelector;
// * STYLE_ACTION: clicking on the text notifies the listener. The menu can be
// shown only by clicking on the arrow. The selected index is always reverted to
// 0 after the listener is notified.
-class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener {
+class VIEWS_EXPORT Combobox : public View,
+ public PrefixDelegate,
+ public ButtonListener {
public:
// The style of the combobox.
enum Style {
@@ -95,6 +98,7 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener {
void GetAccessibleState(ui::AXViewState* state) override;
void Layout() override;
void OnEnabledChanged() override;
+ void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
// Overridden from PrefixDelegate:
int GetRowCount() override;
@@ -113,7 +117,7 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener {
private:
friend class test::ComboboxTestApi;
- class ComboboxMenuModelAdapter;
+ class ComboboxMenuModel;
// Updates the border according to the current state.
void UpdateBorder();
@@ -130,6 +134,9 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener {
// Show the drop down list
void ShowDropDownMenu(ui::MenuSourceType source_type);
+ // Cleans up after the menu as closed
+ void OnMenuClosed(Button::ButtonState original_button_state);
+
// Called when the selection is changed by the user.
void OnPerformAction();
@@ -172,8 +179,8 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener {
// A helper used to select entries by keyboard input.
std::unique_ptr<PrefixSelector> selector_;
- // Adapts a ComboboxModel for use by a views MenuRunner.
- std::unique_ptr<ui::MenuModel> menu_model_adapter_;
+ // The ComboboxModel for use by |menu_runner_|.
+ std::unique_ptr<ui::MenuModel> menu_model_;
// Like MenuButton, we use a time object in order to keep track of when the
// combobox was closed. The time is used for simulating menu behavior; that
@@ -204,7 +211,8 @@ class VIEWS_EXPORT Combobox : public PrefixDelegate, public ButtonListener {
// Set while the dropdown is showing. Ensures the menu is closed if |this| is
// destroyed.
- std::unique_ptr<views::MenuRunner> menu_runner_;
+ std::unique_ptr<MenuModelAdapter> menu_model_adapter_;
+ std::unique_ptr<MenuRunner> menu_runner_;
// The image to be drawn for this combobox's arrow.
gfx::ImageSkia arrow_image_;
diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc
index 8d585c63a94..ec9ade9b90c 100644
--- a/chromium/ui/views/controls/combobox/combobox_unittest.cc
+++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc
@@ -233,17 +233,25 @@ class ComboboxTest : public ViewsTestBase {
return widget_->GetFocusManager()->GetFocusedView();
}
- void PerformClick(const gfx::Point& point) {
+ void PerformMousePress(const gfx::Point& point) {
ui::MouseEvent pressed_event = ui::MouseEvent(
ui::ET_MOUSE_PRESSED, point, point, ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
widget_->OnMouseEvent(&pressed_event);
+ }
+
+ void PerformMouseRelease(const gfx::Point& point) {
ui::MouseEvent released_event = ui::MouseEvent(
ui::ET_MOUSE_RELEASED, point, point, ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
widget_->OnMouseEvent(&released_event);
}
+ void PerformClick(const gfx::Point& point) {
+ PerformMousePress(point);
+ PerformMouseRelease(point);
+ }
+
// We need widget to populate wrapper class.
Widget* widget_;
@@ -586,17 +594,31 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
// Click the right side (arrow button). The menu is shown.
int menu_show_count = 0;
test_api_->InstallTestMenuRunner(&menu_show_count);
+ const gfx::Point right_point(combobox_->x() + combobox_->width() - 1,
+ combobox_->y() + combobox_->height() / 2);
+
EXPECT_EQ(0, menu_show_count);
- PerformClick(gfx::Point(combobox_->x() + combobox_->width() - 1,
- combobox_->y() + combobox_->height() / 2));
- EXPECT_FALSE(listener.on_perform_action_called());
+
+// On Mac, actions occur on mouse down. Otherwise mouse up.
+#if defined(OS_MACOSX)
+ const int kActOnMouseDown = 1;
+#else
+ const int kActOnMouseDown = 0;
+#endif
+
+ PerformMousePress(right_point);
+ EXPECT_EQ(kActOnMouseDown, menu_show_count);
+ PerformMouseRelease(right_point);
EXPECT_EQ(1, menu_show_count);
// Click the left side (text button). The click event is notified.
+ const gfx::Point left_point(
+ gfx::Point(combobox_->x() + 1, combobox_->y() + combobox_->height() / 2));
test_api_->InstallTestMenuRunner(&menu_show_count);
- PerformClick(gfx::Point(combobox_->x() + 1,
- combobox_->y() + combobox_->height() / 2));
- EXPECT_TRUE(listener.on_perform_action_called());
+
+ PerformMousePress(left_point);
+ PerformMouseRelease(left_point);
+
EXPECT_EQ(1, menu_show_count); // Unchanged.
EXPECT_EQ(0, listener.perform_action_index());
}
@@ -604,10 +626,14 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
InitCombobox(nullptr, Combobox::STYLE_NORMAL);
- EXPECT_FALSE(combobox_->OnKeyPressed(
+ int menu_show_count = 0;
+ test_api_->InstallTestMenuRunner(&menu_show_count);
+ EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE)));
- EXPECT_FALSE(combobox_->OnKeyPressed(
+ EXPECT_EQ(1, menu_show_count);
+ EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, ui::EF_NONE)));
+ EXPECT_EQ(2, menu_show_count);
}
TEST_F(ComboboxTest, ConsumingKeyPressEventsActionStyle) {
diff --git a/chromium/ui/views/controls/focus_ring.cc b/chromium/ui/views/controls/focus_ring.cc
new file mode 100644
index 00000000000..8e1702b3788
--- /dev/null
+++ b/chromium/ui/views/controls/focus_ring.cc
@@ -0,0 +1,84 @@
+// Copyright 2016 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/controls/focus_ring.h"
+
+#include "ui/gfx/canvas.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/controls/focusable_border.h"
+
+namespace views {
+
+namespace {
+
+// The stroke width of the focus border in dp.
+constexpr float kFocusHaloThicknessDp = 2.f;
+
+// The focus indicator should hug the normal border, when present (as in the
+// case of text buttons). Since it's drawn outside the parent view, we have to
+// increase the rounding slightly.
+constexpr float kFocusHaloCornerRadiusDp =
+ FocusableBorder::kCornerRadiusDp + kFocusHaloThicknessDp / 2.f;
+
+} // namespace
+
+const char FocusRing::kViewClassName[] = "FocusRing";
+
+// static
+void FocusRing::Install(views::View* parent) {
+ DCHECK(parent->HasFocus());
+ View* ring = new FocusRing();
+ parent->AddChildView(ring);
+ ring->Layout();
+}
+
+// static
+void FocusRing::Uninstall(views::View* parent) {
+ for (int i = 0; i < parent->child_count(); ++i) {
+ if (parent->child_at(i)->GetClassName() == kViewClassName) {
+ delete parent->child_at(i);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+const char* FocusRing::GetClassName() const {
+ return kViewClassName;
+}
+
+bool FocusRing::CanProcessEventsWithinSubtree() const {
+ return false;
+}
+
+void FocusRing::Layout() {
+ // The focus ring handles its own sizing, which is simply to fill the parent
+ // and extend a little beyond its borders.
+ gfx::Rect focus_bounds = parent()->GetLocalBounds();
+ focus_bounds.Inset(gfx::Insets(-kFocusHaloThicknessDp));
+ SetBoundsRect(focus_bounds);
+}
+
+void FocusRing::OnPaint(gfx::Canvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SkColorSetA(GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_FocusedBorderColor),
+ 0x66));
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(kFocusHaloThicknessDp);
+ gfx::RectF rect(GetLocalBounds());
+ rect.Inset(gfx::InsetsF(kFocusHaloThicknessDp / 2.f));
+ canvas->DrawRoundRect(rect, kFocusHaloCornerRadiusDp, paint);
+}
+
+FocusRing::FocusRing() {
+ // A layer is necessary to paint beyond the parent's bounds.
+ SetPaintToLayer(true);
+ layer()->SetFillsBoundsOpaquely(false);
+}
+
+FocusRing::~FocusRing() {}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/focus_ring.h b/chromium/ui/views/controls/focus_ring.h
new file mode 100644
index 00000000000..2438bc7b9dd
--- /dev/null
+++ b/chromium/ui/views/controls/focus_ring.h
@@ -0,0 +1,40 @@
+// Copyright 2016 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_CONTROLS_FOCUS_RING_H_
+#define UI_VIEWS_CONTROLS_FOCUS_RING_H_
+
+#include "ui/views/view.h"
+
+namespace views {
+
+// FocusRing is a View that is designed to act as an indicator of focus for its
+// parent. It is a stand-alone view that paints to a layer which extends beyond
+// the bounds of its parent view.
+class FocusRing : public View {
+ public:
+ // Create a FocusRing and adds it to |parent|.
+ static void Install(views::View* parent);
+
+ // Removes the FocusRing from |parent|.
+ static void Uninstall(views::View* parent);
+
+ // View:
+ const char* GetClassName() const override;
+ bool CanProcessEventsWithinSubtree() const override;
+ void Layout() override;
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ private:
+ static const char kViewClassName[];
+
+ FocusRing();
+ ~FocusRing() override;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusRing);
+};
+
+} // views
+
+#endif // UI_VIEWS_CONTROLS_FOCUS_RING_H_
diff --git a/chromium/ui/views/controls/focusable_border.cc b/chromium/ui/views/controls/focusable_border.cc
index a4e76ff1ba2..fbe8cb2a4e4 100644
--- a/chromium/ui/views/controls/focusable_border.cc
+++ b/chromium/ui/views/controls/focusable_border.cc
@@ -9,7 +9,9 @@
#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/controls/textfield/textfield.h"
@@ -41,22 +43,35 @@ void FocusableBorder::UseDefaultColor() {
}
void FocusableBorder::Paint(const View& view, gfx::Canvas* canvas) {
+ // In harmony, the focus indicator is a FocusRing.
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial() && view.HasFocus())
+ return;
+
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setColor(GetCurrentColor(view));
- SkPath path;
if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- path.moveTo(Textfield::kTextPadding, view.height() - 1);
- path.rLineTo(view.width() - Textfield::kTextPadding * 2, 0);
- path.offset(0.5f, 0.5f);
- paint.setStrokeWidth(SkIntToScalar(1));
+ gfx::ScopedCanvas scoped(canvas);
+ float dsf = canvas->UndoDeviceScaleFactor();
+ // Scale the rect and snap to pixel boundaries.
+ gfx::RectF rect(gfx::ScaleToEnclosingRect(view.GetLocalBounds(), dsf));
+ rect.Inset(gfx::InsetsF(0.5f));
+ SkPath path;
+ float corner_radius_px = kCornerRadiusDp * dsf;
+ path.addRoundRect(gfx::RectFToSkRect(rect), corner_radius_px,
+ corner_radius_px);
+ const int kStrokeWidthPx = 1;
+ paint.setStrokeWidth(SkIntToScalar(kStrokeWidthPx));
+ paint.setAntiAlias(true);
+ canvas->DrawPath(path, paint);
} else {
+ SkPath path;
path.addRect(gfx::RectToSkRect(view.GetLocalBounds()),
SkPath::kCW_Direction);
paint.setStrokeWidth(SkIntToScalar(2));
+ canvas->DrawPath(path, paint);
}
- canvas->DrawPath(path, paint);
}
gfx::Insets FocusableBorder::GetInsets() const {
@@ -74,9 +89,17 @@ void FocusableBorder::SetInsets(int top, int left, int bottom, int right) {
SkColor FocusableBorder::GetCurrentColor(const View& view) const {
if (!use_default_color_)
return override_color_;
- return view.GetNativeTheme()->GetSystemColor(
+
+ SkColor color = view.GetNativeTheme()->GetSystemColor(
view.HasFocus() ? ui::NativeTheme::kColorId_FocusedBorderColor :
ui::NativeTheme::kColorId_UnfocusedBorderColor);
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial() &&
+ !view.enabled()) {
+ return color_utils::BlendTowardOppositeLuma(color,
+ gfx::kDisabledControlAlpha);
+ }
+
+ return color;
}
} // namespace views
diff --git a/chromium/ui/views/controls/focusable_border.h b/chromium/ui/views/controls/focusable_border.h
index 862049ab185..fd5084601d9 100644
--- a/chromium/ui/views/controls/focusable_border.h
+++ b/chromium/ui/views/controls/focusable_border.h
@@ -20,6 +20,8 @@ namespace views {
// A Border class to draw a focused border around a field (e.g textfield).
class VIEWS_EXPORT FocusableBorder : public Border {
public:
+ static constexpr float kCornerRadiusDp = 2.f;
+
FocusableBorder();
~FocusableBorder() override;
diff --git a/chromium/ui/views/controls/label.cc b/chromium/ui/views/controls/label.cc
index f03084ae6bd..0c4667dad17 100644
--- a/chromium/ui/views/controls/label.cc
+++ b/chromium/ui/views/controls/label.cc
@@ -28,15 +28,6 @@
#include "ui/native_theme/native_theme.h"
namespace views {
-namespace {
-
-const gfx::FontList& GetDefaultFontList() {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
-}
-
-} // namespace
-
// static
const char Label::kViewClassName[] = "Label";
const int Label::kFocusBorderPadding = 1;
@@ -54,6 +45,12 @@ Label::Label(const base::string16& text, const gfx::FontList& font_list) {
Label::~Label() {
}
+// static
+const gfx::FontList& Label::GetDefaultFontList() {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
+}
+
void Label::SetFontList(const gfx::FontList& font_list) {
is_first_paint_text_ = true;
render_text_->SetFontList(font_list);
@@ -599,8 +596,8 @@ void Label::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
ui::NativeTheme::kColorId_LabelDisabledColor);
}
if (!background_color_set_) {
- background_color_ = theme->GetSystemColor(
- ui::NativeTheme::kColorId_LabelBackgroundColor);
+ background_color_ =
+ theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
}
RecalculateColors();
}
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 1663256bc8e..9421d1dc68f 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -27,6 +27,8 @@ class VIEWS_EXPORT Label : public View {
Label(const base::string16& text, const gfx::FontList& font_list);
~Label() override;
+ static const gfx::FontList& GetDefaultFontList();
+
// Gets or sets the fonts used by this label.
const gfx::FontList& font_list() const { return render_text_->font_list(); }
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index 405625b6637..176330bf30d 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -30,9 +30,7 @@ Link::Link() : Link(base::string16()) {}
Link::Link(const base::string16& title)
: Label(title),
requested_enabled_color_(gfx::kPlaceholderColor),
- requested_enabled_color_set_(false),
- requested_pressed_color_(gfx::kPlaceholderColor),
- requested_pressed_color_set_(false) {
+ requested_enabled_color_set_(false) {
Init();
}
@@ -176,12 +174,6 @@ void Link::SetEnabledColor(SkColor color) {
Label::SetEnabledColor(GetEnabledColor());
}
-void Link::SetPressedColor(SkColor color) {
- requested_pressed_color_set_ = true;
- requested_pressed_color_ = color;
- Label::SetEnabledColor(GetEnabledColor());
-}
-
void Link::SetUnderline(bool underline) {
if (underline_ == underline)
return;
@@ -241,21 +233,16 @@ void Link::ConfigureFocus() {
}
SkColor Link::GetEnabledColor() {
- // In material mode, there is no pressed effect, so always use the unpressed
- // color.
- if (!pressed_ || ui::MaterialDesignController::IsModeMaterial()) {
- if (!requested_enabled_color_set_ && GetNativeTheme())
- return GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_LinkEnabled);
-
+ if (requested_enabled_color_set_)
return requested_enabled_color_;
- }
- if (!requested_pressed_color_set_ && GetNativeTheme())
+ if (GetNativeTheme()) {
return GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_LinkPressed);
+ pressed_ ? ui::NativeTheme::kColorId_LinkPressed
+ : ui::NativeTheme::kColorId_LinkEnabled);
+ }
- return requested_pressed_color_;
+ return gfx::kPlaceholderColor;
}
} // namespace views
diff --git a/chromium/ui/views/controls/link.h b/chromium/ui/views/controls/link.h
index 58cdc08b92a..692c29e34fd 100644
--- a/chromium/ui/views/controls/link.h
+++ b/chromium/ui/views/controls/link.h
@@ -52,9 +52,8 @@ class VIEWS_EXPORT Link : public Label {
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
void SetEnabledColor(SkColor color) override;
- void SetPressedColor(SkColor color);
- // TODO(estade): almost all the places that call this pass false. With MD,
- // false is already the default so those callsites can be removed.
+ // TODO(estade): almost all the places that call this pass false. With
+ // Harmony, false is already the default so those callsites can be removed.
void SetUnderline(bool underline);
static const char kViewClassName[];
diff --git a/chromium/ui/views/controls/md_slider.cc b/chromium/ui/views/controls/md_slider.cc
new file mode 100644
index 00000000000..cb6f75f4c0b
--- /dev/null
+++ b/chromium/ui/views/controls/md_slider.cc
@@ -0,0 +1,133 @@
+// Copyright 2016 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/controls/md_slider.h"
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "ui/gfx/animation/slide_animation.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/controls/slider.h"
+
+namespace views {
+
+// Color of slider at the active and the disabled state, respectively.
+const SkColor kActiveColor = SkColorSetARGB(0xFF, 0x42, 0x85, 0xF4);
+const SkColor kDisabledColor = SkColorSetARGB(0x42, 0x00, 0x00, 0x00);
+const uint8_t kHighlightColorAlpha = 0x4D;
+
+// The thickness of the slider.
+const int kLineThickness = 2;
+
+// The radius of the thumb and the highlighted thumb of the slider,
+// respectively.
+const float kThumbRadius = 6.f;
+const float kThumbHighlightRadius = 10.f;
+
+// The stroke of the thumb when the slider is disabled.
+const int kThumbStroke = 2;
+
+// Duration of the thumb highlight growing effect animation.
+const int kSlideHighlightChangeDurationMs = 150;
+
+MdSlider::MdSlider(SliderListener* listener)
+ : Slider(listener), is_active_(true), thumb_highlight_radius_(0.f) {
+ SchedulePaint();
+}
+
+MdSlider::~MdSlider() {}
+
+void MdSlider::OnPaint(gfx::Canvas* canvas) {
+ Slider::OnPaint(canvas);
+
+ // Paint the slider.
+ const gfx::Rect content = GetContentsBounds();
+ const int width = content.width() - kThumbRadius * 2;
+ const int full = GetAnimatingValue() * width;
+ const int empty = width - full;
+ const int y = content.height() / 2 - kLineThickness / 2;
+ const int x = content.x() + full + kThumbRadius;
+ const SkColor current_thumb_color =
+ is_active_ ? kActiveColor : kDisabledColor;
+ canvas->FillRect(gfx::Rect(content.x(), y, full, kLineThickness),
+ current_thumb_color);
+ canvas->FillRect(gfx::Rect(x + kThumbRadius, y, empty, kLineThickness),
+ kDisabledColor);
+
+ gfx::Point thumb_center(x, content.height() / 2);
+
+ // Paint the thumb highlight if it exists.
+ if (is_active_ && thumb_highlight_radius_ > kThumbRadius) {
+ SkPaint highlight;
+ SkColor kHighlightColor = SkColorSetA(kActiveColor, kHighlightColorAlpha);
+ highlight.setColor(kHighlightColor);
+ highlight.setFlags(SkPaint::kAntiAlias_Flag);
+ canvas->DrawCircle(thumb_center, thumb_highlight_radius_, highlight);
+ }
+
+ // Paint the thumb of the slider.
+ SkPaint paint;
+ paint.setColor(current_thumb_color);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+
+ if (!is_active_) {
+ paint.setStrokeWidth(kThumbStroke);
+ paint.setStyle(SkPaint::kStroke_Style);
+ }
+ canvas->DrawCircle(
+ thumb_center,
+ is_active_ ? kThumbRadius : (kThumbRadius - kThumbStroke / 2), paint);
+}
+
+const char* MdSlider::GetClassName() const {
+ return "MdSlider";
+}
+
+void MdSlider::UpdateState(bool control_on) {
+ is_active_ = control_on;
+ SchedulePaint();
+}
+
+int MdSlider::GetThumbWidth() {
+ return kThumbRadius * 2;
+}
+
+void MdSlider::SetHighlighted(bool is_highlighted) {
+ if (!highlight_animation_) {
+ if (!is_highlighted)
+ return;
+
+ highlight_animation_.reset(new gfx::SlideAnimation(this));
+ highlight_animation_->SetSlideDuration(kSlideHighlightChangeDurationMs);
+ }
+ if (is_highlighted)
+ highlight_animation_->Show();
+ else
+ highlight_animation_->Hide();
+}
+
+void MdSlider::AnimationProgressed(const gfx::Animation* animation) {
+ if (animation != highlight_animation_.get()) {
+ Slider::AnimationProgressed(animation);
+ return;
+ }
+ thumb_highlight_radius_ =
+ animation->CurrentValueBetween(kThumbRadius, kThumbHighlightRadius);
+ SchedulePaint();
+}
+
+void MdSlider::AnimationEnded(const gfx::Animation* animation) {
+ if (animation != highlight_animation_.get()) {
+ Slider::AnimationEnded(animation);
+ return;
+ }
+ if (animation == highlight_animation_.get() &&
+ !highlight_animation_->IsShowing()) {
+ highlight_animation_.reset();
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/md_slider.h b/chromium/ui/views/controls/md_slider.h
new file mode 100644
index 00000000000..9a534f5736f
--- /dev/null
+++ b/chromium/ui/views/controls/md_slider.h
@@ -0,0 +1,56 @@
+// Copyright 2016 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_CONTROLS_MD_SLIDER_H_
+#define UI_VIEWS_CONTROLS_MD_SLIDER_H_
+
+#include "base/macros.h"
+#include "ui/views/controls/slider.h"
+#include "ui/views/view.h"
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class SlideAnimation;
+}
+
+namespace views {
+
+// TODO(yiyix): When material design is enabled by default, use
+// MdSlider as the default slider implementation. (crbug.com/614453)
+class VIEWS_EXPORT MdSlider : public Slider {
+ public:
+ explicit MdSlider(SliderListener* listener);
+ ~MdSlider() override;
+
+ // ui::Slider:
+ void UpdateState(bool control_on) override;
+
+ // views::View:
+ void OnPaint(gfx::Canvas* canvas) override;
+ const char* GetClassName() const override;
+
+ protected:
+ // ui::Slider:
+ int GetThumbWidth() override;
+ void SetHighlighted(bool is_highlighted) override;
+
+ private:
+ // gfx::AnimationDelegate:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+ void AnimationEnded(const gfx::Animation* animation) override;
+
+ // Record whether the slider is in the active state or the disabled state.
+ bool is_active_;
+
+ // Animating value of the current radius of the thumb's highlight.
+ float thumb_highlight_radius_;
+
+ std::unique_ptr<gfx::SlideAnimation> highlight_animation_;
+
+ DISALLOW_COPY_AND_ASSIGN(MdSlider);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MD_SLIDER_H_
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index 720a69aa707..001179c5198 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -6,13 +6,14 @@
#include "base/macros.h"
#include "ui/views/controls/menu/menu_image_util.h"
+#include "ui/views/round_rect_painter.h"
namespace views {
MenuConfig::MenuConfig()
: arrow_color(SK_ColorBLACK),
menu_vertical_border_size(3),
- menu_horizontal_border_size(0),
+ menu_horizontal_border_size(views::RoundRectPainter::kBorderWidth),
submenu_horizontal_inset(3),
item_top_margin(4),
item_bottom_margin(3),
diff --git a/chromium/ui/views/controls/menu/menu_config_mac.mm b/chromium/ui/views/controls/menu/menu_config_mac.mm
index 2e00665c377..fc66f894436 100644
--- a/chromium/ui/views/controls/menu/menu_config_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_config_mac.mm
@@ -31,9 +31,8 @@ void MenuConfig::Init() {
separator_height = 13;
separator_upper_height = 7;
separator_lower_height = 6;
- separator_thickness = base::mac::IsOSMavericks()
- ? kMenuSeparatorHeightMavericks
- : kMenuSeparatorHeight;
+ separator_thickness = base::mac::IsOS10_9() ? kMenuSeparatorHeightMavericks
+ : kMenuSeparatorHeight;
align_arrow_and_shortcut = true;
icons_in_label = true;
check_selected_combobox_item = true;
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index 13d3d3510a4..7281b18a38c 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -46,7 +46,7 @@
#endif
#if defined(USE_AURA)
-#include "ui/views/controls/menu/menu_key_event_handler.h"
+#include "ui/views/controls/menu/menu_pre_target_handler.h"
#endif
using base::Time;
@@ -420,7 +420,8 @@ MenuItemView* MenuController::Run(Widget* parent,
}
}
- bool nested_menu = showing_;
+ // If we are already showing, this new menu is being nested. Such as context
+ // menus on top of normal menus.
if (showing_) {
// Only support nesting of blocking_run menus, nesting of
// blocking/non-blocking shouldn't be needed.
@@ -437,10 +438,16 @@ MenuItemView* MenuController::Run(Widget* parent,
} else {
showing_ = true;
+ if (owner_)
+ owner_->RemoveObserver(this);
+ owner_ = parent;
+ if (owner_)
+ owner_->AddObserver(this);
+
#if defined(USE_AURA)
- // Only create a MenuKeyEventHandler for non-nested menus. Nested menus will
- // use the existing one.
- key_event_handler_.reset(new MenuKeyEventHandler);
+ // Only create a MenuPreTargetHandler for non-nested menus. Nested menus
+ // will use the existing one.
+ menu_pre_target_handler_.reset(new MenuPreTargetHandler(this, owner_));
#endif
}
@@ -449,12 +456,6 @@ MenuItemView* MenuController::Run(Widget* parent,
state_ = State();
UpdateInitialLocation(bounds, position, context_menu);
- if (owner_)
- owner_->RemoveObserver(this);
- owner_ = parent;
- if (owner_)
- owner_->AddObserver(this);
-
// Set the selection, which opens the initial menu.
SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
@@ -483,7 +484,7 @@ MenuItemView* MenuController::Run(Widget* parent,
// appears totally broken.
message_loop_depth_++;
DCHECK_LE(message_loop_depth_, 2);
- RunMessageLoop(nested_menu);
+ RunMessageLoop();
message_loop_depth_--;
if (ViewsDelegate::GetInstance())
@@ -531,7 +532,19 @@ void MenuController::Cancel(ExitType type) {
// WARNING: the call to MenuClosed deletes us.
return;
}
- ExitAsyncRun();
+
+ // On Windows and Linux the destruction of this menu's Widget leads to the
+ // teardown of the platform specific drag-and-drop Widget. Do not shutdown
+ // while dragging, leave the Widget hidden until drag-and-drop has completed,
+ // at which point all menus will be destroyed.
+ //
+ // If |type| is EXIT_ALL we update the state of the menu to not showing. So
+ // that during the completion of a drag we are not incorrectly reporting the
+ // visual state.
+ if (!drag_in_progress_)
+ ExitAsyncRun();
+ else if (type == EXIT_ALL)
+ showing_ = false;
}
void MenuController::AddNestedDelegate(
@@ -1014,11 +1027,23 @@ void MenuController::OnDragComplete(bool should_close) {
// the event target.
current_mouse_pressed_state_ = 0;
current_mouse_event_target_ = nullptr;
- if (showing_ && should_close && GetActiveInstance() == this) {
- CloseAllNestedMenus();
- Cancel(EXIT_ALL);
- } else if (async_run_) {
- ExitAsyncRun();
+
+ // Only attempt to close if the MenuHost said to.
+ if (should_close) {
+ if (showing_) {
+ // Close showing widgets.
+ if (GetActiveInstance() == this) {
+ CloseAllNestedMenus();
+ Cancel(EXIT_ALL);
+ }
+ // The above may have deleted us. If not perform a full shutdown.
+ if (GetActiveInstance() == this)
+ ExitAsyncRun();
+ } else if (exit_type_ == EXIT_ALL) {
+ // We may have been canceled during the drag. If so we still need to fully
+ // shutdown.
+ ExitAsyncRun();
+ }
}
}
@@ -1086,7 +1111,6 @@ void MenuController::OnWidgetDestroying(Widget* widget) {
DCHECK_EQ(owner_, widget);
owner_->RemoveObserver(this);
owner_ = NULL;
- message_loop_->ClearOwner();
}
bool MenuController::IsCancelAllTimerRunningForTest() {
@@ -1235,7 +1259,7 @@ void MenuController::StartDrag(SubmenuView* source,
ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
// MenuController may have been deleted if |async_run_| so check for an active
// instance before accessing member variables.
- if (GetActiveInstance())
+ if (GetActiveInstance() == this)
did_initiate_drag_ = false;
}
@@ -1387,8 +1411,8 @@ MenuController::~MenuController() {
StopCancelAllTimer();
}
-void MenuController::RunMessageLoop(bool nested_menu) {
- message_loop_->Run(this, owner_, nested_menu);
+void MenuController::RunMessageLoop() {
+ message_loop_->Run();
}
bool MenuController::SendAcceleratorToHotTrackedView() {
@@ -1398,8 +1422,11 @@ bool MenuController::SendAcceleratorToHotTrackedView() {
ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE);
hot_view->AcceleratorPressed(accelerator);
- CustomButton* button = static_cast<CustomButton*>(hot_view);
- SetHotTrackedButton(button);
+ // An accelerator may have canceled the menu after activation.
+ if (GetActiveInstance()) {
+ CustomButton* button = static_cast<CustomButton*>(hot_view);
+ SetHotTrackedButton(button);
+ }
return true;
}
@@ -2610,7 +2637,7 @@ MenuItemView* MenuController::ExitMenuRun() {
}
} else {
#if defined(USE_AURA)
- key_event_handler_.reset();
+ menu_pre_target_handler_.reset();
#endif
showing_ = false;
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 5e34416f838..0434683e8b5 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -40,7 +40,7 @@ class SubmenuView;
class View;
#if defined(USE_AURA)
-class MenuKeyEventHandler;
+class MenuPreTargetHandler;
#endif
namespace internal {
@@ -195,7 +195,6 @@ class VIEWS_EXPORT MenuController : public WidgetObserver {
friend class internal::MenuRunnerImpl;
friend class test::MenuControllerTest;
friend class test::MenuControllerTestApi;
- friend class MenuKeyEventHandler;
friend class MenuHostRootView;
friend class MenuItemView;
friend class SubmenuView;
@@ -318,10 +317,8 @@ class VIEWS_EXPORT MenuController : public WidgetObserver {
~MenuController() override;
- // Runs the platform specific bits of the message loop. If |nested_menu| is
- // true we're being asked to run a menu from within a menu (eg a context
- // menu).
- void RunMessageLoop(bool nested_menu);
+ // Runs the platform specific bits of the message loop.
+ void RunMessageLoop();
// Invokes AcceleratorPressed() on the hot tracked view if there is one.
// Returns true if AcceleratorPressed() was invoked.
@@ -700,7 +697,7 @@ class VIEWS_EXPORT MenuController : public WidgetObserver {
std::unique_ptr<MenuMessageLoop> message_loop_;
#if defined(USE_AURA)
- std::unique_ptr<MenuKeyEventHandler> key_event_handler_;
+ std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler_;
#endif
DISALLOW_COPY_AND_ASSIGN(MenuController);
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index 42a2a252e08..cc2e943705b 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -5,9 +5,11 @@
#include "ui/views/controls/menu/menu_controller.h"
#include "base/callback.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "ui/aura/scoped_window_targeter.h"
#include "ui/aura/window.h"
@@ -21,6 +23,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/views/controls/menu/menu_controller_delegate.h"
#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/views/controls/menu/menu_host.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_message_loop.h"
#include "ui/views/controls/menu/menu_scroll_view_container.h"
@@ -31,7 +34,8 @@
#if defined(USE_AURA)
#include "ui/aura/scoped_window_targeter.h"
#include "ui/aura/window.h"
-#include "ui/views/controls/menu/menu_key_event_handler.h"
+#include "ui/views/controls/menu/menu_pre_target_handler.h"
+#include "ui/wm/public/drag_drop_client.h"
#endif
#if defined(USE_X11)
@@ -160,10 +164,7 @@ class TestMenuMessageLoop : public MenuMessageLoop {
private:
// MenuMessageLoop:
- void Run(MenuController* controller,
- Widget* owner,
- bool nested_menu) override;
- void ClearOwner() override;
+ void Run() override;
std::unique_ptr<MenuMessageLoop> original_;
bool is_running_;
@@ -179,11 +180,9 @@ TestMenuMessageLoop::TestMenuMessageLoop(
TestMenuMessageLoop::~TestMenuMessageLoop() {}
-void TestMenuMessageLoop::Run(MenuController* controller,
- Widget* owner,
- bool nested_menu) {
+void TestMenuMessageLoop::Run() {
is_running_ = true;
- original_->Run(controller, owner, nested_menu);
+ original_->Run();
}
void TestMenuMessageLoop::QuitNow() {
@@ -191,10 +190,61 @@ void TestMenuMessageLoop::QuitNow() {
original_->QuitNow();
}
-void TestMenuMessageLoop::ClearOwner() {
- original_->ClearOwner();
+#if defined(USE_AURA)
+// A DragDropClient which does not trigger a nested message loop. Instead a
+// callback is triggered during StartDragAndDrop in order to allow testing.
+class TestDragDropClient : public aura::client::DragDropClient {
+ public:
+ explicit TestDragDropClient(const base::Closure& callback)
+ : start_drag_and_drop_callback_(callback), drag_in_progress_(false) {}
+ ~TestDragDropClient() override {}
+
+ // aura::client::DragDropClient:
+ int StartDragAndDrop(const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) override;
+ void DragUpdate(aura::Window* target, const ui::LocatedEvent& event) override;
+ void Drop(aura::Window* target, const ui::LocatedEvent& event) override;
+ void DragCancel() override;
+ bool IsDragDropInProgress() override;
+
+ private:
+ base::Closure start_drag_and_drop_callback_;
+ bool drag_in_progress_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
+};
+
+int TestDragDropClient::StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ drag_in_progress_ = true;
+ start_drag_and_drop_callback_.Run();
+ return 0;
}
+void TestDragDropClient::DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) {}
+void TestDragDropClient::Drop(aura::Window* target,
+ const ui::LocatedEvent& event) {
+ drag_in_progress_ = false;
+}
+void TestDragDropClient::DragCancel() {
+ drag_in_progress_ = false;
+}
+bool TestDragDropClient::IsDragDropInProgress() {
+ return drag_in_progress_;
+}
+
+#endif // defined(USE_AURA)
+
} // namespace
class TestMenuItemViewShown : public MenuItemView {
@@ -223,6 +273,7 @@ class MenuControllerTest : public ViewsTestBase {
void SetUp() override {
ViewsTestBase::SetUp();
Init();
+ ASSERT_TRUE(base::MessageLoopForUI::IsCurrent());
}
void TearDown() override {
@@ -257,6 +308,31 @@ class MenuControllerTest : public ViewsTestBase {
}
#endif // defined(OS_LINUX) && defined(USE_X11)
+#if defined(USE_AURA)
+ // Verifies that an open menu receives a cancel event, and closes.
+ void TestCancelEvent() {
+ EXPECT_EQ(MenuController::EXIT_NONE, menu_controller_->exit_type());
+ ui::CancelModeEvent cancel_event;
+ event_generator_->Dispatch(&cancel_event);
+ EXPECT_EQ(MenuController::EXIT_ALL, menu_controller_->exit_type());
+ }
+#endif // defined(USE_AURA)
+
+ // Verifies the state of the |menu_controller_| before destroying it.
+ void VerifyDragCompleteThenDestroy() {
+ EXPECT_FALSE(menu_controller()->drag_in_progress());
+ EXPECT_EQ(MenuController::EXIT_ALL, menu_controller()->exit_type());
+ DestroyMenuController();
+ }
+
+ // Setups |menu_controller_delegate_| to be destroyed when OnMenuClosed is
+ // called.
+ void TestDragCompleteThenDestroyOnMenuClosed() {
+ menu_controller_delegate_->set_on_menu_closed_callback(
+ base::Bind(&MenuControllerTest::VerifyDragCompleteThenDestroy,
+ base::Unretained(this)));
+ }
+
void TestAsynchronousNestedExitAll() {
ASSERT_TRUE(test_message_loop_->is_running());
@@ -317,6 +393,23 @@ class MenuControllerTest : public ViewsTestBase {
test_message_loop_->QuitNow();
}
+ // Tests destroying the active |menu_controller_| and replacing it with a new
+ // active instance.
+ void TestMenuControllerReplacementDuringDrag() {
+ DestroyMenuController();
+ menu_item()->GetSubmenu()->Close();
+ menu_controller_ =
+ new MenuController(true, menu_controller_delegate_.get());
+ menu_controller_->owner_ = owner_.get();
+ menu_controller_->showing_ = true;
+ }
+
+ // Tests that the menu does not destroy itself when canceled during a drag.
+ void TestCancelAllDuringDrag() {
+ menu_controller_->CancelAll();
+ EXPECT_EQ(0, menu_controller_delegate_->on_menu_closed_called());
+ }
+
protected:
void SetPendingStateItem(MenuItemView* item) {
menu_controller_->pending_state_.item = item;
@@ -378,6 +471,12 @@ class MenuControllerTest : public ViewsTestBase {
bool IsShowing() { return menu_controller_->showing_; }
+ MenuHost* GetMenuHost(SubmenuView* submenu) { return submenu->host_; }
+
+ void MenuHostOnDragWillStart(MenuHost* host) { host->OnDragWillStart(); }
+
+ void MenuHostOnDragComplete(MenuHost* host) { host->OnDragComplete(); }
+
void SelectByChar(base::char16 character) {
menu_controller_->SelectByChar(character);
}
@@ -404,12 +503,12 @@ class MenuControllerTest : public ViewsTestBase {
void RunMenu() {
#if defined(USE_AURA)
- std::unique_ptr<MenuKeyEventHandler> key_event_handler(
- new MenuKeyEventHandler);
+ std::unique_ptr<MenuPreTargetHandler> menu_pre_target_handler(
+ new MenuPreTargetHandler(menu_controller_, owner_.get()));
#endif
menu_controller_->message_loop_depth_++;
- menu_controller_->RunMessageLoop(false);
+ menu_controller_->RunMessageLoop();
menu_controller_->message_loop_depth_--;
}
@@ -423,6 +522,15 @@ class MenuControllerTest : public ViewsTestBase {
menu_controller_->message_loop_.reset(test_message_loop_);
}
+ // Causes the |menu_controller_| to begin dragging. Use TestDragDropClient to
+ // avoid nesting message loops.
+ void StartDrag() {
+ const gfx::Point location;
+ menu_controller_->state_.item = menu_item()->GetSubmenu()->GetMenuItemAt(0);
+ menu_controller_->StartDrag(
+ menu_item()->GetSubmenu()->GetMenuItemAt(0)->CreateSubmenu(), location);
+ }
+
Widget* owner() { return owner_.get(); }
ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
TestMenuItemViewShown* menu_item() { return menu_item_.get(); }
@@ -451,6 +559,8 @@ class MenuControllerTest : public ViewsTestBase {
menu_item()->GetSubmenu()->ShowAt(owner(), menu_item()->bounds(), false);
}
+ void DestroyMenuItem() { menu_item_.reset(); }
+
CustomButton* GetHotButton() {
return menu_controller_->hot_button_;
}
@@ -526,10 +636,9 @@ class MenuControllerTest : public ViewsTestBase {
// Tests that an event targeter which blocks events will be honored by the menu
// event dispatcher.
TEST_F(MenuControllerTest, EventTargeter) {
- base::MessageLoopForUI::current()->PostTask(
- FROM_HERE,
- base::Bind(&MenuControllerTest::TestEventTargeter,
- base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&MenuControllerTest::TestEventTargeter,
+ base::Unretained(this)));
RunMenu();
}
#endif // defined(OS_LINUX) && defined(USE_X11)
@@ -550,17 +659,13 @@ TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
event_generator()->PressTouchId(1);
event_generator()->ReleaseTouchId(0);
- base::MessageLoopForUI::current()->PostTask(
- FROM_HERE,
- base::Bind(&MenuControllerTest::ReleaseTouchId,
- base::Unretained(this),
- 1));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&MenuControllerTest::ReleaseTouchId,
+ base::Unretained(this), 1));
- base::MessageLoopForUI::current()->PostTask(
- FROM_HERE,
- base::Bind(&MenuControllerTest::PressKey,
- base::Unretained(this),
- ui::VKEY_ESCAPE));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&MenuControllerTest::PressKey,
+ base::Unretained(this), ui::VKEY_ESCAPE));
RunMenu();
@@ -1006,17 +1111,49 @@ TEST_F(MenuControllerTest, AsynchronousPerformDrop) {
TEST_F(MenuControllerTest, AsynchronousDragComplete) {
MenuController* controller = menu_controller();
controller->SetAsyncRun(true);
+ TestDragCompleteThenDestroyOnMenuClosed();
controller->OnDragWillStart();
controller->OnDragComplete(true);
- EXPECT_FALSE(controller->drag_in_progress());
TestMenuControllerDelegate* controller_delegate = menu_controller_delegate();
EXPECT_EQ(1, controller_delegate->on_menu_closed_called());
EXPECT_EQ(nullptr, controller_delegate->on_menu_closed_menu());
EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
controller_delegate->on_menu_closed_notify_type());
- EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
+}
+
+// Tests that if Cancel is called during a drag, that OnMenuClosed is still
+// notified when the drag completes.
+TEST_F(MenuControllerTest, AsynchronousCancelDuringDrag) {
+ MenuController* controller = menu_controller();
+ controller->SetAsyncRun(true);
+ TestDragCompleteThenDestroyOnMenuClosed();
+
+ controller->OnDragWillStart();
+ controller->CancelAll();
+ controller->OnDragComplete(true);
+
+ TestMenuControllerDelegate* controller_delegate = menu_controller_delegate();
+ EXPECT_EQ(1, controller_delegate->on_menu_closed_called());
+ EXPECT_EQ(nullptr, controller_delegate->on_menu_closed_menu());
+ EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE,
+ controller_delegate->on_menu_closed_notify_type());
+}
+
+// Tests that if a menu is destroyed while drag operations are occuring, that
+// the MenuHost does not crash as the drag completes.
+TEST_F(MenuControllerTest, AsynchronousDragHostDeleted) {
+ MenuController* controller = menu_controller();
+ controller->SetAsyncRun(true);
+
+ SubmenuView* submenu = menu_item()->GetSubmenu();
+ submenu->ShowAt(owner(), menu_item()->bounds(), false);
+ MenuHost* host = GetMenuHost(submenu);
+ MenuHostOnDragWillStart(host);
+ submenu->Close();
+ DestroyMenuItem();
+ MenuHostOnDragComplete(host);
}
// Tets that an asynchronous menu nested within an asynchronous menu closes both
@@ -1125,7 +1262,7 @@ TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) {
TEST_F(MenuControllerTest, AsynchronousNestedExitAll) {
InstallTestMenuMessageLoop();
- base::MessageLoopForUI::current()->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&MenuControllerTest::TestAsynchronousNestedExitAll,
base::Unretained(this)));
@@ -1138,7 +1275,7 @@ TEST_F(MenuControllerTest, AsynchronousNestedExitAll) {
TEST_F(MenuControllerTest, AsynchronousNestedExitOutermost) {
InstallTestMenuMessageLoop();
- base::MessageLoopForUI::current()->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&MenuControllerTest::TestAsynchronousNestedExitOutermost,
base::Unretained(this)));
@@ -1237,7 +1374,7 @@ TEST_F(MenuControllerTest, NestedMessageLoopDiesWithNestedMenu) {
std::unique_ptr<TestMenuControllerDelegate> nested_delegate(
new TestMenuControllerDelegate());
// This will nest an asynchronous menu, and then kill the nested message loop.
- base::MessageLoopForUI::current()->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&MenuControllerTest::TestNestedMessageLoopKillsItself,
base::Unretained(this), nested_delegate.get()));
@@ -1251,5 +1388,89 @@ TEST_F(MenuControllerTest, NestedMessageLoopDiesWithNestedMenu) {
EXPECT_TRUE(nested_delegate->on_menu_closed_called());
}
+#if defined(USE_AURA)
+// Tests that when a synchronous menu receives a cancel event, that it closes.
+TEST_F(MenuControllerTest, SynchronousCancelEvent) {
+ ExitMenuRun();
+ // Post actual test to run once the menu has created a nested message loop.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&MenuControllerTest::TestCancelEvent, base::Unretained(this)));
+ int mouse_event_flags = 0;
+ MenuItemView* run_result = menu_controller()->Run(
+ owner(), nullptr, menu_item(), gfx::Rect(), MENU_ANCHOR_TOPLEFT, false,
+ false, &mouse_event_flags);
+ EXPECT_EQ(run_result, nullptr);
+}
+
+// Tests that when an asynchronous menu receives a cancel event, that it closes.
+TEST_F(MenuControllerTest, AsynchronousCancelEvent) {
+ ExitMenuRun();
+ MenuController* controller = menu_controller();
+ controller->SetAsyncRun(true);
+
+ int mouse_event_flags = 0;
+ MenuItemView* run_result =
+ controller->Run(owner(), nullptr, menu_item(), gfx::Rect(),
+ MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
+ EXPECT_EQ(run_result, nullptr);
+ TestCancelEvent();
+}
+
+// Tests that if a menu is ran without a widget, that MenuPreTargetHandler does
+// not cause a crash.
+TEST_F(MenuControllerTest, RunWithoutWidgetDoesntCrash) {
+ ExitMenuRun();
+ MenuController* controller = menu_controller();
+ controller->SetAsyncRun(true);
+ int mouse_event_flags = 0;
+ MenuItemView* run_result =
+ controller->Run(nullptr, nullptr, menu_item(), gfx::Rect(),
+ MENU_ANCHOR_TOPLEFT, false, false, &mouse_event_flags);
+ EXPECT_EQ(run_result, nullptr);
+}
+
+// Tests that if a MenuController is destroying during drag/drop, and another
+// MenuController becomes active, that the exiting of drag does not cause a
+// crash.
+TEST_F(MenuControllerTest, MenuControllerReplacedDuringDrag) {
+ // This test creates two native widgets, but expects the child native widget
+ // to be able to reach up and use the parent native widget's aura
+ // objects. https://crbug.com/614037
+ if (IsMus())
+ return;
+
+ TestDragDropClient drag_drop_client(
+ base::Bind(&MenuControllerTest::TestMenuControllerReplacementDuringDrag,
+ base::Unretained(this)));
+ aura::client::SetDragDropClient(owner()->GetNativeWindow()->GetRootWindow(),
+ &drag_drop_client);
+ AddButtonMenuItems();
+ StartDrag();
+}
+
+// Tests that if a CancelAll is called during drag-and-drop that it does not
+// destroy the MenuController. On Windows and Linux this destruction also
+// destroys the Widget used for drag-and-drop, thereby ending the drag.
+TEST_F(MenuControllerTest, CancelAllDuringDrag) {
+ // This test creates two native widgets, but expects the child native widget
+ // to be able to reach up and use the parent native widget's aura
+ // objects. https://crbug.com/614037
+ if (IsMus())
+ return;
+
+ MenuController* controller = menu_controller();
+ controller->SetAsyncRun(true);
+
+ TestDragDropClient drag_drop_client(base::Bind(
+ &MenuControllerTest::TestCancelAllDuringDrag, base::Unretained(this)));
+ aura::client::SetDragDropClient(owner()->GetNativeWindow()->GetRootWindow(),
+ &drag_drop_client);
+ AddButtonMenuItems();
+ StartDrag();
+}
+
+#endif // defined(USE_AURA)
+
} // namespace test
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_delegate.cc b/chromium/ui/views/controls/menu/menu_delegate.cc
index 2e3b838ae5f..42ad8d6b735 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -23,8 +23,7 @@ const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const {
return NULL;
}
-bool MenuDelegate::GetShouldUseDisabledEmphasizedForegroundColor(
- int command_id) const {
+bool MenuDelegate::GetShouldUseNormalForegroundColor(int command_id) const {
return false;
}
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index cca690f2431..3b7cb7f6241 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -73,9 +73,9 @@ class VIEWS_EXPORT MenuDelegate {
// The font for the menu item label.
virtual const gfx::FontList* GetLabelFontList(int id) const;
- // Whether this item should be displayed with a bolder color when disabled.
- virtual bool GetShouldUseDisabledEmphasizedForegroundColor(
- int command_id) const;
+ // Whether this item should be displayed with the normal text color, even if
+ // it's disabled.
+ virtual bool GetShouldUseNormalForegroundColor(int command_id) const;
// Override the text color of a given menu item dependent on the
// |command_id| and its |is_hovered| state. Returns true if it chooses to
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index d07d1efcc75..c6750a6e0cd 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -219,9 +219,13 @@ void MenuHost::OnDragWillStart() {
}
void MenuHost::OnDragComplete() {
+ // If we are being destroyed there is no guarantee that the menu items are
+ // available.
+ if (destroying_)
+ return;
MenuController* menu_controller =
submenu_->GetMenuItem()->GetMenuController();
- if (destroying_ || !menu_controller)
+ if (!menu_controller)
return;
bool should_close = true;
diff --git a/chromium/ui/views/controls/menu/menu_host.h b/chromium/ui/views/controls/menu/menu_host.h
index 1de12373563..06736d3d9fa 100644
--- a/chromium/ui/views/controls/menu/menu_host.h
+++ b/chromium/ui/views/controls/menu/menu_host.h
@@ -26,6 +26,10 @@ class PreMenuEventDispatchHandler;
} // internal
+namespace test {
+class MenuControllerTest;
+} // test
+
// SubmenuView uses a MenuHost to house the SubmenuView.
//
// SubmenuView owns the MenuHost. When SubmenuView is done with the MenuHost
@@ -65,6 +69,8 @@ class MenuHost : public Widget {
void ReleaseMenuHostCapture();
private:
+ friend class test::MenuControllerTest;
+
// Overridden from Widget:
internal::RootView* CreateRootView() override;
void OnMouseCaptureLost() override;
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 8e3013b1197..73fc3039650 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -12,7 +12,6 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
@@ -526,7 +525,7 @@ void MenuItemView::ChildrenChanged() {
}
}
- STLDeleteElements(&removed_items_);
+ base::STLDeleteElements(&removed_items_);
}
void MenuItemView::Layout() {
@@ -599,7 +598,7 @@ MenuItemView::MenuItemView(MenuItemView* parent,
MenuItemView::~MenuItemView() {
delete submenu_;
- STLDeleteElements(&removed_items_);
+ base::STLDeleteElements(&removed_items_);
}
const char* MenuItemView::GetClassName() const {
@@ -784,12 +783,11 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor:
ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor;
} else {
- bool emphasized = delegate &&
- delegate->GetShouldUseDisabledEmphasizedForegroundColor(
- GetCommand());
- color_id = emphasized ?
- ui::NativeTheme::kColorId_DisabledEmphasizedMenuItemForegroundColor :
- ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
+ bool emphasized =
+ delegate && delegate->GetShouldUseNormalForegroundColor(GetCommand());
+ color_id = emphasized
+ ? ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor
+ : ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
}
SkColor fg_color = native_theme->GetSystemColor(color_id);
SkColor override_foreground_color;
@@ -798,10 +796,7 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
&override_foreground_color)) {
fg_color = override_foreground_color;
}
- SkColor icon_color =
- render_selection && !ui::MaterialDesignController::IsModeMaterial()
- ? fg_color
- : color_utils::DeriveDefaultIconColor(fg_color);
+ SkColor icon_color = color_utils::DeriveDefaultIconColor(fg_color);
// Render the check.
if (type_ == CHECKBOX && delegate->IsItemChecked(GetCommand())) {
diff --git a/chromium/ui/views/controls/menu/menu_key_event_handler.cc b/chromium/ui/views/controls/menu/menu_key_event_handler.cc
deleted file mode 100644
index a0073f90395..00000000000
--- a/chromium/ui/views/controls/menu/menu_key_event_handler.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 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/controls/menu/menu_key_event_handler.h"
-
-#include "ui/aura/env.h"
-#include "ui/views/controls/menu/menu_controller.h"
-#include "ui/views/views_delegate.h"
-
-namespace views {
-
-MenuKeyEventHandler::MenuKeyEventHandler() {
- aura::Env::GetInstanceDontCreate()->PrependPreTargetHandler(this);
-}
-
-MenuKeyEventHandler::~MenuKeyEventHandler() {
- aura::Env::GetInstanceDontCreate()->RemovePreTargetHandler(this);
-}
-
-void MenuKeyEventHandler::OnKeyEvent(ui::KeyEvent* event) {
- MenuController* menu_controller = MenuController::GetActiveInstance();
- DCHECK(menu_controller);
- menu_controller->OnWillDispatchKeyEvent(event);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_key_event_handler.h b/chromium/ui/views/controls/menu/menu_key_event_handler.h
deleted file mode 100644
index fd4fd036785..00000000000
--- a/chromium/ui/views/controls/menu/menu_key_event_handler.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2015 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_CONTROLS_MENU_MENU_KEY_EVENT_HANDLER_H_
-#define UI_VIEWS_CONTROLS_MENU_MENU_KEY_EVENT_HANDLER_H_
-
-#include "base/macros.h"
-#include "ui/events/event_handler.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class Accelerator;
-}
-
-namespace views {
-
-// Handles key events while the menu is open.
-class VIEWS_EXPORT MenuKeyEventHandler : public ui::EventHandler {
- public:
- MenuKeyEventHandler();
- ~MenuKeyEventHandler() override;
-
- // ui::EventHandler:
- void OnKeyEvent(ui::KeyEvent* event) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MenuKeyEventHandler);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_MENU_MENU_KEY_EVENT_HANDLER_H_
diff --git a/chromium/ui/views/controls/menu/menu_message_loop.h b/chromium/ui/views/controls/menu/menu_message_loop.h
index c6a02816524..e84b650b765 100644
--- a/chromium/ui/views/controls/menu/menu_message_loop.h
+++ b/chromium/ui/views/controls/menu/menu_message_loop.h
@@ -35,17 +35,11 @@ class MenuMessageLoop {
gfx::NativeWindow window,
const gfx::Point& screen_loc);
- // Runs the platform specific bits of the message loop. If |nested_menu| is
- // true we're being asked to run a menu from within a menu (eg a context
- // menu).
- virtual void Run(MenuController*, Widget* owner, bool nested_menu) = 0;
+ // Runs the platform specific bits of the message loop.
+ virtual void Run() = 0;
// Quit an earlier call to Run().
virtual void QuitNow() = 0;
-
- // Clear any references to the owner widget that was passed into the previous
- // call to Run().
- virtual void ClearOwner() = 0;
};
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.cc b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
index dab58be36c9..3bfdef98a46 100644
--- a/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
+++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.cc
@@ -15,7 +15,6 @@
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/platform/scoped_event_dispatcher.h"
#include "ui/views/controls/menu/menu_controller.h"
-#include "ui/views/controls/menu/menu_key_event_handler.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_client.h"
@@ -26,68 +25,6 @@ using aura::client::ScreenPositionClient;
namespace views {
-namespace {
-
-aura::Window* GetOwnerRootWindow(views::Widget* owner) {
- return owner ? owner->GetNativeWindow()->GetRootWindow() : NULL;
-}
-
-// ActivationChangeObserverImpl is used to observe activation changes and close
-// the menu. Additionally it listens for the root window to be destroyed and
-// cancel the menu as well.
-class ActivationChangeObserverImpl
- : public aura::client::ActivationChangeObserver,
- public aura::WindowObserver,
- public ui::EventHandler {
- public:
- ActivationChangeObserverImpl(MenuController* controller, aura::Window* root)
- : controller_(controller), root_(root) {
- aura::client::GetActivationClient(root_)->AddObserver(this);
- root_->AddObserver(this);
- root_->AddPreTargetHandler(this);
- }
-
- ~ActivationChangeObserverImpl() override { Cleanup(); }
-
- // aura::client::ActivationChangeObserver:
- void OnWindowActivated(
- aura::client::ActivationChangeObserver::ActivationReason reason,
- aura::Window* gained_active,
- aura::Window* lost_active) override {
- if (!controller_->drag_in_progress())
- controller_->CancelAll();
- }
-
- // aura::WindowObserver:
- void OnWindowDestroying(aura::Window* window) override { Cleanup(); }
-
- // ui::EventHandler:
- void OnCancelMode(ui::CancelModeEvent* event) override {
- controller_->CancelAll();
- }
-
- private:
- void Cleanup() {
- if (!root_)
- return;
- // The ActivationClient may have been destroyed by the time we get here.
- aura::client::ActivationClient* client =
- aura::client::GetActivationClient(root_);
- if (client)
- client->RemoveObserver(this);
- root_->RemovePreTargetHandler(this);
- root_->RemoveObserver(this);
- root_ = NULL;
- }
-
- MenuController* controller_;
- aura::Window* root_;
-
- DISALLOW_COPY_AND_ASSIGN(ActivationChangeObserverImpl);
-};
-
-} // namespace
-
// static
MenuMessageLoop* MenuMessageLoop::Create() {
return new MenuMessageLoopAura;
@@ -115,16 +52,11 @@ void MenuMessageLoop::RepostEventToWindow(const ui::LocatedEvent* event,
root->GetHost()->dispatcher()->RepostEvent(located_event.get());
}
-MenuMessageLoopAura::MenuMessageLoopAura() : owner_(nullptr) {}
+MenuMessageLoopAura::MenuMessageLoopAura() {}
MenuMessageLoopAura::~MenuMessageLoopAura() {}
-void MenuMessageLoopAura::Run(MenuController* controller,
- Widget* owner,
- bool nested_menu) {
- // |owner_| may be NULL.
- owner_ = owner;
- aura::Window* root = GetOwnerRootWindow(owner_);
+void MenuMessageLoopAura::Run() {
// It is possible for the same MenuMessageLoopAura to start a nested
// message-loop while it is already running a nested loop. So make sure the
// quit-closure gets reset to the outer loop's quit-closure once the innermost
@@ -132,12 +64,6 @@ void MenuMessageLoopAura::Run(MenuController* controller,
base::AutoReset<base::Closure> reset_quit_closure(&message_loop_quit_,
base::Closure());
- std::unique_ptr<ActivationChangeObserverImpl> observer;
- if (root) {
- if (!nested_menu)
- observer.reset(new ActivationChangeObserverImpl(controller, root));
- }
-
base::MessageLoop* loop = base::MessageLoop::current();
base::MessageLoop::ScopedNestableTaskAllower allow(loop);
base::RunLoop run_loop;
@@ -158,8 +84,4 @@ void MenuMessageLoopAura::QuitNow() {
#endif
}
-void MenuMessageLoopAura::ClearOwner() {
- owner_ = NULL;
-}
-
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_aura.h b/chromium/ui/views/controls/menu/menu_message_loop_aura.h
index 6ebe8393f80..e123380d134 100644
--- a/chromium/ui/views/controls/menu/menu_message_loop_aura.h
+++ b/chromium/ui/views/controls/menu/menu_message_loop_aura.h
@@ -23,18 +23,11 @@ class MenuMessageLoopAura : public MenuMessageLoop {
MenuMessageLoopAura();
~MenuMessageLoopAura() override;
- // Overridden from MenuMessageLoop:
- void Run(MenuController* controller,
- Widget* owner,
- bool nested_menu) override;
+ // MenuMessageLoop:
+ void Run() override;
void QuitNow() override;
- void ClearOwner() override;
private:
- // Owner of child windows.
- // WARNING: this may be NULL.
- Widget* owner_;
-
base::Closure message_loop_quit_;
DISALLOW_COPY_AND_ASSIGN(MenuMessageLoopAura);
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_mac.cc b/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
index 6d3afb77acc..3d9bea95484 100644
--- a/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
+++ b/chromium/ui/views/controls/menu/menu_message_loop_mac.cc
@@ -28,9 +28,7 @@ MenuMessageLoopMac::MenuMessageLoopMac() {}
MenuMessageLoopMac::~MenuMessageLoopMac() {}
-void MenuMessageLoopMac::Run(MenuController* controller,
- Widget* owner,
- bool nested_menu) {
+void MenuMessageLoopMac::Run() {
base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
base::MessageLoop::ScopedNestableTaskAllower allow(loop);
base::RunLoop run_loop;
@@ -43,7 +41,4 @@ void MenuMessageLoopMac::QuitNow() {
run_loop_->Quit();
}
-void MenuMessageLoopMac::ClearOwner() {
-}
-
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_message_loop_mac.h b/chromium/ui/views/controls/menu/menu_message_loop_mac.h
index ed5cfdbf673..0f35a175784 100644
--- a/chromium/ui/views/controls/menu/menu_message_loop_mac.h
+++ b/chromium/ui/views/controls/menu/menu_message_loop_mac.h
@@ -20,12 +20,9 @@ class MenuMessageLoopMac : public MenuMessageLoop {
MenuMessageLoopMac();
~MenuMessageLoopMac() override;
- // Overridden from MenuMessageLoop:
- void Run(MenuController* controller,
- Widget* owner,
- bool nested_menu) override;
+ // MenuMessageLoop:
+ void Run() override;
void QuitNow() override;
- void ClearOwner() override;
private:
base::RunLoop* run_loop_ = nullptr;
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index b63f9866774..bc04dcb9e24 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -262,7 +262,7 @@ void MenuModelAdapter::WillHideMenu(MenuItemView* menu) {
const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
menu_map_.find(menu);
if (map_iterator != menu_map_.end()) {
- map_iterator->second->MenuClosed();
+ map_iterator->second->MenuWillClose();
return;
}
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 9fddfaf9317..c5df9547874 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -85,7 +85,7 @@ class MenuModelBase : public ui::MenuModel {
void MenuWillShow() override {}
- void MenuClosed() override {}
+ void MenuWillClose() override {}
void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) override {}
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler.cc b/chromium/ui/views/controls/menu/menu_pre_target_handler.cc
new file mode 100644
index 00000000000..7ac7a3f5b47
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler.cc
@@ -0,0 +1,70 @@
+// Copyright 2016 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/controls/menu/menu_pre_target_handler.h"
+
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace views {
+
+namespace {
+
+aura::Window* GetOwnerRootWindow(views::Widget* owner) {
+ return owner ? owner->GetNativeWindow()->GetRootWindow() : nullptr;
+}
+
+} // namespace
+
+MenuPreTargetHandler::MenuPreTargetHandler(MenuController* controller,
+ Widget* owner)
+ : controller_(controller), root_(GetOwnerRootWindow(owner)) {
+ aura::Env::GetInstanceDontCreate()->PrependPreTargetHandler(this);
+ if (root_) {
+ aura::client::GetActivationClient(root_)->AddObserver(this);
+ root_->AddObserver(this);
+ }
+}
+
+MenuPreTargetHandler::~MenuPreTargetHandler() {
+ aura::Env::GetInstanceDontCreate()->RemovePreTargetHandler(this);
+ Cleanup();
+}
+
+void MenuPreTargetHandler::OnWindowActivated(
+ aura::client::ActivationChangeObserver::ActivationReason reason,
+ aura::Window* gained_active,
+ aura::Window* lost_active) {
+ if (!controller_->drag_in_progress())
+ controller_->CancelAll();
+}
+
+void MenuPreTargetHandler::OnWindowDestroying(aura::Window* window) {
+ Cleanup();
+}
+
+void MenuPreTargetHandler::OnCancelMode(ui::CancelModeEvent* event) {
+ controller_->CancelAll();
+}
+
+void MenuPreTargetHandler::OnKeyEvent(ui::KeyEvent* event) {
+ controller_->OnWillDispatchKeyEvent(event);
+}
+
+void MenuPreTargetHandler::Cleanup() {
+ if (!root_)
+ return;
+ // The ActivationClient may have been destroyed by the time we get here.
+ aura::client::ActivationClient* client =
+ aura::client::GetActivationClient(root_);
+ if (client)
+ client->RemoveObserver(this);
+ root_->RemoveObserver(this);
+ root_ = nullptr;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler.h b/chromium/ui/views/controls/menu/menu_pre_target_handler.h
new file mode 100644
index 00000000000..56bdd3596c7
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler.h
@@ -0,0 +1,58 @@
+// Copyright 2016 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_CONTROLS_MENU_PRE_TARGET_HANDLER_H_
+#define UI_VIEWS_CONTROLS_MENU_PRE_TARGET_HANDLER_H_
+
+#include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
+#include "ui/views/views_export.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace aura {
+class Window;
+} // namespace aura
+
+namespace views {
+
+class MenuController;
+class Widget;
+
+// MenuPreTargetHandler is used to observe activation changes, cancel events,
+// and root window destruction, to shutdown the menu.
+//
+// Additionally handles key events to provide accelerator support to menus.
+class VIEWS_EXPORT MenuPreTargetHandler
+ : public aura::client::ActivationChangeObserver,
+ public aura::WindowObserver,
+ public ui::EventHandler {
+ public:
+ MenuPreTargetHandler(MenuController* controller, Widget* owner);
+ ~MenuPreTargetHandler() override;
+
+ // aura::client:ActivationChangeObserver:
+ void OnWindowActivated(
+ aura::client::ActivationChangeObserver::ActivationReason reason,
+ aura::Window* gained_active,
+ aura::Window* lost_active) override;
+
+ // aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override;
+
+ // ui::EventHandler:
+ void OnCancelMode(ui::CancelModeEvent* event) override;
+ void OnKeyEvent(ui::KeyEvent* event) override;
+
+ private:
+ void Cleanup();
+
+ MenuController* controller_;
+ aura::Window* root_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuPreTargetHandler);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_PRE_TARGET_HANDLER_H_
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 09449d24c86..924256ff346 100644
--- a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -35,10 +35,6 @@ class TestModel : public ui::SimpleMenuModel {
return command_id == model_->checked_command_;
}
bool IsCommandIdEnabled(int command_id) const override { return true; }
- bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) override {
- return false;
- }
void ExecuteCommand(int command_id, int event_flags) override {}
void MenuWillShow(SimpleMenuModel* source) override {
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 9350283fde1..a126820718b 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -283,10 +283,9 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
? kBorderPaddingDueToRoundedCorners
: 0;
- int top = menu_config.menu_vertical_border_size + padding;
- int left = menu_config.menu_horizontal_border_size + padding;
- int bottom = menu_config.menu_vertical_border_size + padding;
- int right = menu_config.menu_horizontal_border_size + padding;
+ const int vertical_inset = menu_config.menu_vertical_border_size + padding;
+ const int horizontal_inset =
+ menu_config.menu_horizontal_border_size + padding;
if (menu_config.use_outer_border) {
SkColor color = GetNativeTheme()
@@ -294,11 +293,12 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
ui::NativeTheme::kColorId_MenuBorderColor)
: gfx::kPlaceholderColor;
SetBorder(views::Border::CreateBorderPainter(
- base::WrapUnique(
- new views::RoundRectPainter(color, menu_config.corner_radius)),
- gfx::Insets(top, left, bottom, right)));
+ base::MakeUnique<views::RoundRectPainter>(color,
+ menu_config.corner_radius),
+ gfx::Insets(vertical_inset, horizontal_inset)));
} else {
- SetBorder(Border::CreateEmptyBorder(top, left, bottom, right));
+ SetBorder(Border::CreateEmptyBorder(vertical_inset, horizontal_inset,
+ vertical_inset, horizontal_inset));
}
}
diff --git a/chromium/ui/views/controls/menu/native_menu_win.cc b/chromium/ui/views/controls/menu/native_menu_win.cc
index e205fda62f9..b737cbf974a 100644
--- a/chromium/ui/views/controls/menu/native_menu_win.cc
+++ b/chromium/ui/views/controls/menu/native_menu_win.cc
@@ -57,7 +57,7 @@ NativeMenuWin::NativeMenuWin(ui::MenuModel* model, HWND system_menu_for)
NativeMenuWin::~NativeMenuWin() {
if (destroyed_flag_)
*destroyed_flag_ = true;
- STLDeleteContainerPointers(items_.begin(), items_.end());
+ base::STLDeleteContainerPointers(items_.begin(), items_.end());
DestroyMenu(menu_);
}
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index 1e2de11bd03..a04d83292a6 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -47,7 +47,7 @@ SubmenuView::SubmenuView(MenuItemView* parent)
resize_open_menu_(false),
scroll_animator_(new ScrollAnimator(this)),
roundoff_error_(0),
- prefix_selector_(this) {
+ prefix_selector_(this, this) {
DCHECK(parent);
// We'll delete ourselves, otherwise the ScrollView would delete us on close.
set_owned_by_client();
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 1f929750bbc..2e00de54eb2 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -21,6 +21,10 @@ class MenuHost;
class MenuItemView;
class MenuScrollViewContainer;
+namespace test {
+class MenuControllerTest;
+} // test
+
// SubmenuView is the parent of all menu items.
//
// SubmenuView has the following responsibilities:
@@ -36,7 +40,8 @@ class MenuScrollViewContainer;
// MenuScrollViewContainer handles showing as much of the SubmenuView as the
// screen allows. If the SubmenuView is taller than the screen, scroll buttons
// are provided that allow the user to see all the menu items.
-class VIEWS_EXPORT SubmenuView : public PrefixDelegate,
+class VIEWS_EXPORT SubmenuView : public View,
+ public PrefixDelegate,
public ScrollDelegate {
public:
// The submenu's class name.
@@ -168,6 +173,8 @@ class VIEWS_EXPORT SubmenuView : public PrefixDelegate,
void ChildPreferredSizeChanged(View* child) override;
private:
+ friend class test::MenuControllerTest;
+
void SchedulePaintForDropIndicator(MenuItemView* item,
MenuDelegate::DropPosition position);
diff --git a/chromium/ui/views/controls/message_box_view.h b/chromium/ui/views/controls/message_box_view.h
index 2d83532c898..af6905dafab 100644
--- a/chromium/ui/views/controls/message_box_view.h
+++ b/chromium/ui/views/controls/message_box_view.h
@@ -63,6 +63,9 @@ class VIEWS_EXPORT MessageBoxView : public View {
// Returns user entered data in the prompt field.
base::string16 GetInputText();
+ // Returns true if this message box has a visible checkbox, false otherwise.
+ bool HasCheckBox() const { return !!checkbox_; }
+
// Returns true if a checkbox is selected, false otherwise. (And false if
// the message box has no checkbox.)
bool IsCheckBoxSelected();
diff --git a/chromium/ui/views/controls/non_md_slider.cc b/chromium/ui/views/controls/non_md_slider.cc
new file mode 100644
index 00000000000..1778ddc755e
--- /dev/null
+++ b/chromium/ui/views/controls/non_md_slider.cc
@@ -0,0 +1,106 @@
+// Copyright 2016 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/controls/non_md_slider.h"
+
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/controls/slider.h"
+#include "ui/views/resources/grit/views_resources.h"
+
+namespace {
+const int kBarImagesActive[] = {
+ IDR_SLIDER_ACTIVE_LEFT, IDR_SLIDER_ACTIVE_CENTER, IDR_SLIDER_PRESSED_CENTER,
+ IDR_SLIDER_PRESSED_RIGHT,
+};
+
+const int kBarImagesDisabled[] = {
+ IDR_SLIDER_DISABLED_LEFT, IDR_SLIDER_DISABLED_CENTER,
+ IDR_SLIDER_DISABLED_CENTER, IDR_SLIDER_DISABLED_RIGHT,
+};
+
+// The image chunks.
+enum BorderElements {
+ LEFT,
+ CENTER_LEFT,
+ CENTER_RIGHT,
+ RIGHT,
+};
+} // namespace
+
+namespace views {
+
+NonMdSlider::NonMdSlider(SliderListener* listener)
+ : Slider(listener),
+ bar_active_images_(kBarImagesActive),
+ bar_disabled_images_(kBarImagesDisabled) {
+ UpdateSliderAppearance(true);
+}
+
+NonMdSlider::~NonMdSlider() {}
+
+void NonMdSlider::OnPaint(gfx::Canvas* canvas) {
+ Slider::OnPaint(canvas);
+ gfx::Rect content = GetContentsBounds();
+ float value = GetAnimatingValue();
+
+ // Inset the slider bar a little bit, so that the left or the right end of
+ // the slider bar will not be exposed under the thumb button when the thumb
+ // button slides to the left most or right most position.
+ const int kBarInsetX = 2;
+ int bar_width = content.width() - kBarInsetX * 2;
+ int bar_cy = content.height() / 2 - bar_height_ / 2;
+
+ int w = content.width() - thumb_->width();
+ int full = value * w;
+ int middle = std::max(full, images_[LEFT]->width());
+
+ canvas->Save();
+ canvas->Translate(gfx::Vector2d(kBarInsetX, bar_cy));
+ canvas->DrawImageInt(*images_[LEFT], 0, 0);
+ canvas->DrawImageInt(*images_[RIGHT], bar_width - images_[RIGHT]->width(), 0);
+ canvas->TileImageInt(*images_[CENTER_LEFT], images_[LEFT]->width(), 0,
+ middle - images_[LEFT]->width(), bar_height_);
+ canvas->TileImageInt(*images_[CENTER_RIGHT], middle, 0,
+ bar_width - middle - images_[RIGHT]->width(),
+ bar_height_);
+ canvas->Restore();
+
+ // Paint slider thumb.
+ int button_cx = content.x() + full;
+ int thumb_y = content.height() / 2 - thumb_->height() / 2;
+ canvas->DrawImageInt(*thumb_, button_cx, thumb_y);
+}
+
+const char* NonMdSlider::GetClassName() const {
+ return "NonMdSlider";
+}
+
+void NonMdSlider::UpdateState(bool control_on) {
+ UpdateSliderAppearance(control_on);
+}
+
+void NonMdSlider::UpdateSliderAppearance(bool control_on) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ if (control_on) {
+ thumb_ = rb.GetImageNamed(IDR_SLIDER_ACTIVE_THUMB).ToImageSkia();
+ for (int i = 0; i < 4; ++i)
+ images_[i] = rb.GetImageNamed(bar_active_images_[i]).ToImageSkia();
+ } else {
+ thumb_ = rb.GetImageNamed(IDR_SLIDER_DISABLED_THUMB).ToImageSkia();
+ for (int i = 0; i < 4; ++i)
+ images_[i] = rb.GetImageNamed(bar_disabled_images_[i]).ToImageSkia();
+ }
+ bar_height_ = images_[LEFT]->height();
+ SchedulePaint();
+}
+
+int NonMdSlider::GetThumbWidth() {
+ return thumb_->width();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/non_md_slider.h b/chromium/ui/views/controls/non_md_slider.h
new file mode 100644
index 00000000000..fa6bfc9ca07
--- /dev/null
+++ b/chromium/ui/views/controls/non_md_slider.h
@@ -0,0 +1,49 @@
+// Copyright 2016 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_CONTROLS_NON_MD_SLIDER_H_
+#define UI_VIEWS_CONTROLS_NON_MD_SLIDER_H_
+
+#include "base/macros.h"
+#include "ui/views/controls/slider.h"
+#include "ui/views/view.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+class Slider;
+
+class VIEWS_EXPORT NonMdSlider : public Slider {
+ public:
+ explicit NonMdSlider(SliderListener* listener);
+ ~NonMdSlider() override;
+
+ // ui::Slider:
+ void UpdateState(bool control_on) override;
+
+ // views::View:
+ void OnPaint(gfx::Canvas* canvas) override;
+ const char* GetClassName() const override;
+
+ protected:
+ // ui::Slider:
+ int GetThumbWidth() override;
+
+ private:
+ void UpdateSliderAppearance(bool control_on);
+
+ // Array used to hold active slider states and disabled slider states images.
+ const int* bar_active_images_;
+ const int* bar_disabled_images_;
+ const gfx::ImageSkia* thumb_;
+
+ // Array used to hold current state of slider images.
+ const gfx::ImageSkia* images_[4];
+ int bar_height_;
+
+ DISALLOW_COPY_AND_ASSIGN(NonMdSlider);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_NON_MD_SLIDER_H_
diff --git a/chromium/ui/views/controls/prefix_delegate.h b/chromium/ui/views/controls/prefix_delegate.h
index a6d27ebe7e0..cd3930a6da2 100644
--- a/chromium/ui/views/controls/prefix_delegate.h
+++ b/chromium/ui/views/controls/prefix_delegate.h
@@ -6,11 +6,12 @@
#define UI_VIEWS_CONTROLS_PREFIX_DELEGATE_H_
#include "ui/views/view.h"
+#include "ui/views/views_export.h"
namespace views {
// An interface used to expose lists of items for selection by text input.
-class VIEWS_EXPORT PrefixDelegate : public View {
+class VIEWS_EXPORT PrefixDelegate {
public:
// Returns the total number of selectable items.
virtual int GetRowCount() = 0;
@@ -24,9 +25,6 @@ class VIEWS_EXPORT PrefixDelegate : public View {
// Returns the item at the specified row.
virtual base::string16 GetTextForRow(int row) = 0;
-
- protected:
- ~PrefixDelegate() override {}
};
} // namespace views
diff --git a/chromium/ui/views/controls/prefix_selector.cc b/chromium/ui/views/controls/prefix_selector.cc
index bd57addeaec..b21ff34e09e 100644
--- a/chromium/ui/views/controls/prefix_selector.cc
+++ b/chromium/ui/views/controls/prefix_selector.cc
@@ -9,6 +9,7 @@
#include "ui/base/ime/text_input_type.h"
#include "ui/gfx/range/range.h"
#include "ui/views/controls/prefix_delegate.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -27,8 +28,8 @@ void ConvertRectToScreen(const views::View* src, gfx::Rect* r) {
} // namespace
-PrefixSelector::PrefixSelector(PrefixDelegate* delegate)
- : prefix_delegate_(delegate) {
+PrefixSelector::PrefixSelector(PrefixDelegate* delegate, View* host_view)
+ : prefix_delegate_(delegate), host_view_(host_view) {
}
PrefixSelector::~PrefixSelector() {
@@ -77,10 +78,10 @@ bool PrefixSelector::CanComposeInline() const {
}
gfx::Rect PrefixSelector::GetCaretBounds() const {
- gfx::Rect rect(prefix_delegate_->GetVisibleBounds().origin(), gfx::Size());
+ gfx::Rect rect(host_view_->GetVisibleBounds().origin(), gfx::Size());
// TextInputClient::GetCaretBounds is expected to return a value in screen
// coordinates.
- ConvertRectToScreen(prefix_delegate_, &rect);
+ ConvertRectToScreen(host_view_, &rect);
return rect;
}
diff --git a/chromium/ui/views/controls/prefix_selector.h b/chromium/ui/views/controls/prefix_selector.h
index 9476855534c..76f61419bdf 100644
--- a/chromium/ui/views/controls/prefix_selector.h
+++ b/chromium/ui/views/controls/prefix_selector.h
@@ -17,12 +17,13 @@
namespace views {
class PrefixDelegate;
+class View;
// PrefixSelector is used to change the selection in a view as the user
// types characters.
class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
public:
- explicit PrefixSelector(PrefixDelegate* delegate);
+ PrefixSelector(PrefixDelegate* delegate, View* host_view);
~PrefixSelector() override;
// Invoked from the view when it loses focus.
@@ -71,6 +72,8 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
PrefixDelegate* prefix_delegate_;
+ View* host_view_;
+
// Time OnTextInput() was last invoked.
base::TimeTicks time_of_last_key_;
diff --git a/chromium/ui/views/controls/prefix_selector_unittest.cc b/chromium/ui/views/controls/prefix_selector_unittest.cc
index 8619c76229c..7f026e82dfd 100644
--- a/chromium/ui/views/controls/prefix_selector_unittest.cc
+++ b/chromium/ui/views/controls/prefix_selector_unittest.cc
@@ -16,7 +16,7 @@ using base::ASCIIToUTF16;
namespace views {
-class TestPrefixDelegate : public PrefixDelegate {
+class TestPrefixDelegate : public View, public PrefixDelegate {
public:
TestPrefixDelegate() : selected_row_(0) {
rows_.push_back(ASCIIToUTF16("aardvark"));
@@ -45,7 +45,7 @@ class TestPrefixDelegate : public PrefixDelegate {
class PrefixSelectorTest : public ViewsTestBase {
public:
PrefixSelectorTest() {
- selector_.reset(new PrefixSelector(&delegate_));
+ selector_.reset(new PrefixSelector(&delegate_, &delegate_));
}
~PrefixSelectorTest() override {
// Explicitly release |selector_| here which can happen before releasing
@@ -58,7 +58,7 @@ class PrefixSelectorTest : public ViewsTestBase {
TestPrefixDelegate delegate_;
private:
- DISALLOW_COPY_AND_ASSIGN(PrefixSelectorTest);
+ DISALLOW_COPY_AND_ASSIGN(PrefixSelectorTest);
};
TEST_F(PrefixSelectorTest, PrefixSelect) {
diff --git a/chromium/ui/views/controls/progress_bar.cc b/chromium/ui/views/controls/progress_bar.cc
index 0278e5b51b0..8533d62fa99 100644
--- a/chromium/ui/views/controls/progress_bar.cc
+++ b/chromium/ui/views/controls/progress_bar.cc
@@ -14,306 +14,196 @@
#include "third_party/skia/include/core/SkXfermode.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/accessibility/ax_view_state.h"
+#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/native_theme/native_theme.h"
-namespace {
-
-// Progress bar's border width.
-const int kBorderWidth = 1;
-
-// Corner radius for the progress bar's border.
-const int kCornerRadius = 2;
-
-// The width of the highlight at the right of the progress bar.
-const int kHighlightWidth = 18;
-
-const SkColor kBackgroundColor = SkColorSetRGB(230, 230, 230);
-const SkColor kBackgroundBorderColor = SkColorSetRGB(208, 208, 208);
-const SkColor kBarBorderColor = SkColorSetRGB(65, 137, 237);
-const SkColor kBarTopColor = SkColorSetRGB(110, 188, 249);
-const SkColor kBarColorStart = SkColorSetRGB(86, 167, 247);
-const SkColor kBarColorEnd = SkColorSetRGB(76, 148, 245);
-const SkColor kBarHighlightEnd = SkColorSetRGB(114, 206, 251);
-const SkColor kDisabledBarBorderColor = SkColorSetRGB(191, 191, 191);
-const SkColor kDisabledBarColorStart = SkColorSetRGB(224, 224, 224);
-const SkColor kDisabledBarColorEnd = SkColorSetRGB(212, 212, 212);
-
-void AddRoundRectPathWithPadding(int x, int y,
- int w, int h,
- int corner_radius,
- SkScalar padding,
- SkPath* path) {
- DCHECK(path);
- SkRect rect;
- rect.set(
- SkIntToScalar(x) + padding, SkIntToScalar(y) + padding,
- SkIntToScalar(x + w) - padding, SkIntToScalar(y + h) - padding);
- path->addRoundRect(
- rect,
- SkIntToScalar(corner_radius) - padding,
- SkIntToScalar(corner_radius) - padding);
-}
-
-void AddRoundRectPath(int x, int y,
- int w, int h,
- int corner_radius,
- SkPath* path) {
- AddRoundRectPathWithPadding(x, y, w, h, corner_radius, SK_ScalarHalf, path);
-}
+namespace views {
-void FillRoundRect(gfx::Canvas* canvas,
- int x, int y,
- int w, int h,
- int corner_radius,
- const SkColor colors[],
- const SkScalar points[],
- int count,
- bool gradient_horizontal) {
- SkPath path;
- AddRoundRectPath(x, y, w, h, corner_radius, &path);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
-
- SkPoint p[2];
- p[0].iset(x, y);
- if (gradient_horizontal) {
- p[1].iset(x + w, y);
- } else {
- p[1].iset(x, y + h);
- }
- paint.setShader(SkGradientShader::MakeLinear(p, colors, points, count,
- SkShader::kClamp_TileMode));
+namespace {
- canvas->DrawPath(path, paint);
-}
+// In DP, the amount to round the corners of the progress bar (both bg and
+// fg, aka slice).
+const int kCornerRadius = 3;
-void FillRoundRect(gfx::Canvas* canvas,
- int x, int y,
- int w, int h,
- int corner_radius,
- SkColor gradient_start_color,
- SkColor gradient_end_color,
- bool gradient_horizontal) {
- if (gradient_start_color != gradient_end_color) {
- SkColor colors[2] = { gradient_start_color, gradient_end_color };
- FillRoundRect(canvas, x, y, w, h, corner_radius,
- colors, NULL, 2, gradient_horizontal);
+// Adds a rectangle to the path. The corners will be rounded if there is room.
+void AddPossiblyRoundRectToPath(const gfx::Rect& rectangle, SkPath* path) {
+ if (rectangle.height() < kCornerRadius) {
+ path->addRect(gfx::RectToSkRect(rectangle));
} else {
- SkPath path;
- AddRoundRectPath(x, y, w, h, corner_radius, &path);
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- paint.setColor(gradient_start_color);
- canvas->DrawPath(path, paint);
+ path->addRoundRect(gfx::RectToSkRect(rectangle), kCornerRadius,
+ kCornerRadius);
}
}
-void StrokeRoundRect(gfx::Canvas* canvas,
- int x, int y,
- int w, int h,
- int corner_radius,
- SkColor stroke_color,
- int stroke_width) {
- SkPath path;
- AddRoundRectPath(x, y, w, h, corner_radius, &path);
- SkPaint paint;
- paint.setShader(NULL);
- paint.setColor(stroke_color);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- paint.setStrokeWidth(SkIntToScalar(stroke_width));
- canvas->DrawPath(path, paint);
-}
-
} // namespace
-namespace views {
-
// static
const char ProgressBar::kViewClassName[] = "ProgressBar";
-ProgressBar::ProgressBar()
- : min_display_value_(0.0),
- max_display_value_(1.0),
- current_value_(0.0) {
-}
+ProgressBar::ProgressBar(int preferred_height)
+ : preferred_height_(preferred_height) {}
ProgressBar::~ProgressBar() {
}
-double ProgressBar::GetNormalizedValue() const {
- const double capped_value = std::min(
- std::max(current_value_, min_display_value_), max_display_value_);
- return (capped_value - min_display_value_) /
- (max_display_value_ - min_display_value_);
+void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
+ state->AddStateFlag(ui::AX_STATE_READ_ONLY);
}
-void ProgressBar::SetDisplayRange(double min_display_value,
- double max_display_value) {
- if (min_display_value != min_display_value_ ||
- max_display_value != max_display_value_) {
- DCHECK(min_display_value < max_display_value);
- min_display_value_ = min_display_value;
- max_display_value_ = max_display_value;
- SchedulePaint();
- }
+gfx::Size ProgressBar::GetPreferredSize() const {
+ // The width will typically be ignored.
+ gfx::Size pref_size(1, preferred_height_);
+ gfx::Insets insets = GetInsets();
+ pref_size.Enlarge(insets.width(), insets.height());
+ return pref_size;
+}
+
+const char* ProgressBar::GetClassName() const {
+ return kViewClassName;
+}
+
+void ProgressBar::OnPaint(gfx::Canvas* canvas) {
+ if (IsIndeterminate())
+ return OnPaintIndeterminate(canvas);
+
+ gfx::Rect content_bounds = GetContentsBounds();
+
+ // Draw background.
+ SkPath background_path;
+ AddPossiblyRoundRectToPath(content_bounds, &background_path);
+ SkPaint background_paint;
+ background_paint.setStyle(SkPaint::kFill_Style);
+ background_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ background_paint.setColor(GetBackgroundColor());
+ canvas->DrawPath(background_path, background_paint);
+
+ // Draw slice.
+ SkPath slice_path;
+ const int slice_width = static_cast<int>(
+ content_bounds.width() * std::min(current_value_, 1.0) + 0.5);
+ if (slice_width < 1)
+ return;
+
+ gfx::Rect slice_bounds = content_bounds;
+ slice_bounds.set_width(slice_width);
+ AddPossiblyRoundRectToPath(slice_bounds, &slice_path);
+
+ SkPaint slice_paint;
+ slice_paint.setStyle(SkPaint::kFill_Style);
+ slice_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ slice_paint.setColor(GetForegroundColor());
+ canvas->DrawPath(slice_path, slice_paint);
}
void ProgressBar::SetValue(double value) {
- if (value != current_value_) {
- current_value_ = value;
+ double adjusted_value = (value < 0.0 || value > 1.0) ? -1.0 : value;
+
+ if (adjusted_value == current_value_)
+ return;
+
+ current_value_ = adjusted_value;
+ if (IsIndeterminate()) {
+ indeterminate_bar_animation_.reset(new gfx::LinearAnimation(this));
+ indeterminate_bar_animation_->SetDuration(2000); // In milliseconds.
+ indeterminate_bar_animation_->Start();
+ } else {
+ indeterminate_bar_animation_.reset();
SchedulePaint();
}
}
-void ProgressBar::SetTooltipText(const base::string16& tooltip_text) {
- tooltip_text_ = tooltip_text;
+SkColor ProgressBar::GetForegroundColor() const {
+ return GetNativeTheme()->GetSystemColor(
+ ui::NativeTheme::kColorId_ProminentButtonColor);
}
-bool ProgressBar::GetTooltipText(const gfx::Point& p,
- base::string16* tooltip) const {
- DCHECK(tooltip);
- *tooltip = tooltip_text_;
- return !tooltip_text_.empty();
+SkColor ProgressBar::GetBackgroundColor() const {
+ // The default foreground is GoogleBlue500, and the default background is
+ // that color but 80% lighter.
+ return color_utils::BlendTowardOppositeLuma(GetForegroundColor(), 0xCC);
}
-void ProgressBar::GetAccessibleState(ui::AXViewState* state) {
- state->role = ui::AX_ROLE_PROGRESS_INDICATOR;
- state->AddStateFlag(ui::AX_STATE_READ_ONLY);
+void ProgressBar::AnimationProgressed(const gfx::Animation* animation) {
+ DCHECK_EQ(animation, indeterminate_bar_animation_.get());
+ DCHECK(IsIndeterminate());
+ SchedulePaint();
}
-gfx::Size ProgressBar::GetPreferredSize() const {
- gfx::Size pref_size(100, 11);
- gfx::Insets insets = GetInsets();
- pref_size.Enlarge(insets.width(), insets.height());
- return pref_size;
+void ProgressBar::AnimationEnded(const gfx::Animation* animation) {
+ DCHECK_EQ(animation, indeterminate_bar_animation_.get());
+ // Restarts animation.
+ if (IsIndeterminate())
+ indeterminate_bar_animation_->Start();
}
-const char* ProgressBar::GetClassName() const {
- return kViewClassName;
+bool ProgressBar::IsIndeterminate() {
+ return current_value_ < 0.0;
}
-void ProgressBar::OnPaint(gfx::Canvas* canvas) {
+void ProgressBar::OnPaintIndeterminate(gfx::Canvas* canvas) {
gfx::Rect content_bounds = GetContentsBounds();
- int bar_left = content_bounds.x();
- int bar_top = content_bounds.y();
- int bar_width = content_bounds.width();
- int bar_height = content_bounds.height();
-
- const int progress_width =
- static_cast<int>(bar_width * GetNormalizedValue() + 0.5);
// Draw background.
- FillRoundRect(canvas,
- bar_left, bar_top, bar_width, bar_height,
- kCornerRadius,
- kBackgroundColor, kBackgroundColor,
- false);
- StrokeRoundRect(canvas,
- bar_left, bar_top,
- bar_width, bar_height,
- kCornerRadius,
- kBackgroundBorderColor,
- kBorderWidth);
-
- if (progress_width > 1) {
- // Draw inner if wide enough.
- if (progress_width > kBorderWidth * 2) {
- canvas->Save();
-
- SkPath inner_path;
- AddRoundRectPathWithPadding(
- bar_left, bar_top, progress_width, bar_height,
- kCornerRadius,
- 0,
- &inner_path);
- canvas->ClipPath(inner_path, false);
-
- const SkColor bar_colors[] = {
- kBarTopColor,
- kBarTopColor,
- kBarColorStart,
- kBarColorEnd,
- kBarColorEnd,
- };
- // We want a thin 1-pixel line for kBarTopColor.
- SkScalar scalar_height = SkIntToScalar(bar_height);
- SkScalar highlight_width = 1 / scalar_height;
- SkScalar border_width = kBorderWidth / scalar_height;
- const SkScalar bar_points[] = {
- 0,
- border_width,
- border_width + highlight_width,
- SK_Scalar1 - border_width,
- SK_Scalar1,
- };
-
- const SkColor disabled_bar_colors[] = {
- kDisabledBarColorStart,
- kDisabledBarColorStart,
- kDisabledBarColorEnd,
- kDisabledBarColorEnd,
- };
-
- const SkScalar disabled_bar_points[] = {
- 0,
- border_width,
- SK_Scalar1 - border_width,
- SK_Scalar1
- };
-
- // Do not start from (kBorderWidth, kBorderWidth) because it makes gaps
- // between the inner and the border.
- FillRoundRect(canvas,
- bar_left, bar_top,
- progress_width, bar_height,
- kCornerRadius,
- enabled() ? bar_colors : disabled_bar_colors,
- enabled() ? bar_points : disabled_bar_points,
- enabled() ? arraysize(bar_colors) :
- arraysize(disabled_bar_colors),
- false);
-
- if (enabled()) {
- // Draw the highlight to the right.
- const SkColor highlight_colors[] = {
- SkColorSetA(kBarHighlightEnd, 0),
- kBarHighlightEnd,
- kBarHighlightEnd,
- };
- const SkScalar highlight_points[] = {
- 0, SK_Scalar1 - kBorderWidth / scalar_height, SK_Scalar1,
- };
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
-
- SkPoint p[2];
- int highlight_left =
- std::max(0, progress_width - kHighlightWidth - kBorderWidth);
- p[0].iset(highlight_left, 0);
- p[1].iset(progress_width, 0);
- paint.setShader(SkGradientShader::MakeLinear(
- p, highlight_colors, highlight_points, arraysize(highlight_colors),
- SkShader::kClamp_TileMode));
- paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
- canvas->DrawRect(gfx::Rect(highlight_left, 0,
- kHighlightWidth + kBorderWidth, bar_height),
- paint);
- }
-
- canvas->Restore();
- }
-
- // Draw bar stroke
- StrokeRoundRect(canvas,
- bar_left, bar_top, progress_width, bar_height,
- kCornerRadius,
- enabled() ? kBarBorderColor : kDisabledBarBorderColor,
- kBorderWidth);
+ SkPath background_path;
+ AddPossiblyRoundRectToPath(content_bounds, &background_path);
+ SkPaint background_paint;
+ background_paint.setStyle(SkPaint::kFill_Style);
+ background_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ background_paint.setColor(GetBackgroundColor());
+ canvas->DrawPath(background_path, background_paint);
+
+ // Draw slice.
+ SkPath slice_path;
+ double time = indeterminate_bar_animation_->GetCurrentValue();
+
+ // The animation spec corresponds to the material design lite's parameter.
+ // (cf. https://github.com/google/material-design-lite/)
+ double bar1_left;
+ double bar1_width;
+ double bar2_left;
+ double bar2_width;
+ if (time < 0.50) {
+ bar1_left = time / 2;
+ bar1_width = time * 1.5;
+ bar2_left = 0;
+ bar2_width = 0;
+ } else if (time < 0.75) {
+ bar1_left = time * 3 - 1.25;
+ bar1_width = 0.75 - (time - 0.5) * 3;
+ bar2_left = 0;
+ bar2_width = time - 0.5;
+ } else {
+ bar1_left = 1;
+ bar1_width = 0;
+ bar2_left = (time - 0.75) * 4;
+ bar2_width = 0.25 - (time - 0.75);
}
+
+ int bar1_x = static_cast<int>(content_bounds.width() * bar1_left);
+ int bar1_w =
+ std::min(static_cast<int>(content_bounds.width() * bar1_width + 0.5),
+ content_bounds.width() - bar1_x);
+ int bar2_x = static_cast<int>(content_bounds.width() * bar2_left);
+ int bar2_w =
+ std::min(static_cast<int>(content_bounds.width() * bar2_width + 0.5),
+ content_bounds.width() - bar2_x);
+
+ gfx::Rect slice_bounds = content_bounds;
+ slice_bounds.set_x(content_bounds.x() + bar1_x);
+ slice_bounds.set_width(bar1_w);
+ AddPossiblyRoundRectToPath(slice_bounds, &slice_path);
+ slice_bounds.set_x(content_bounds.x() + bar2_x);
+ slice_bounds.set_width(bar2_w);
+ AddPossiblyRoundRectToPath(slice_bounds, &slice_path);
+
+ SkPaint slice_paint;
+ slice_paint.setStyle(SkPaint::kFill_Style);
+ slice_paint.setFlags(SkPaint::kAntiAlias_Flag);
+ slice_paint.setColor(GetForegroundColor());
+ canvas->DrawPath(slice_path, slice_paint);
}
} // namespace views
diff --git a/chromium/ui/views/controls/progress_bar.h b/chromium/ui/views/controls/progress_bar.h
index 3fb5fb7f7f2..aa09845c7a8 100644
--- a/chromium/ui/views/controls/progress_bar.h
+++ b/chromium/ui/views/controls/progress_bar.h
@@ -7,58 +7,60 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "ui/gfx/animation/animation_delegate.h"
#include "ui/views/view.h"
+namespace gfx {
+class LinearAnimation;
+}
+
namespace views {
// Progress bar is a control that indicates progress visually.
-class VIEWS_EXPORT ProgressBar : public View {
+class VIEWS_EXPORT ProgressBar : public View, public gfx::AnimationDelegate {
public:
- // The value range defaults to [0.0, 1.0].
- ProgressBar();
+ // The preferred height parameter makes it easier to use a ProgressBar with
+ // layout managers that size to preferred size.
+ explicit ProgressBar(int preferred_height = 5);
~ProgressBar() override;
- double current_value() const { return current_value_; }
-
- // Gets a normalized current value in [0.0, 1.0] range based on current value
- // range and the min/max display value range.
- double GetNormalizedValue() const;
+ // Overridden from View:
+ void GetAccessibleState(ui::AXViewState* state) override;
+ gfx::Size GetPreferredSize() const override;
+ const char* GetClassName() const override;
+ void OnPaint(gfx::Canvas* canvas) override;
- // Sets the inclusive range of values to be displayed. Values outside of the
- // range will be capped when displayed.
- void SetDisplayRange(double min_display_value, double max_display_value);
+ double current_value() const { return current_value_; }
- // Sets the current value. Values outside of the range [min_display_value_,
- // max_display_value_] will be stored unmodified and capped for display.
+ // Sets the current value. Values outside of the display range of 0.0-1.0 will
+ // be displayed with an infinite loading animation.
void SetValue(double value);
- // Sets the tooltip text. Default behavior for a progress bar is to show no
- // tooltip on mouse hover. Calling this lets you set a custom tooltip. To
- // revert to default behavior, call this with an empty string.
- void SetTooltipText(const base::string16& tooltip_text);
+ protected:
+ // The color of the progress portion.
+ SkColor GetForegroundColor() const;
+ // The color of the portion that displays potential progress.
+ SkColor GetBackgroundColor() const;
- // Overridden from View:
- bool GetTooltipText(const gfx::Point& p,
- base::string16* tooltip) const override;
- void GetAccessibleState(ui::AXViewState* state) override;
+ int preferred_height() const { return preferred_height_; }
private:
static const char kViewClassName[];
- // Overridden from View:
- gfx::Size GetPreferredSize() const override;
- const char* GetClassName() const override;
- void OnPaint(gfx::Canvas* canvas) override;
+ // gfx::AnimationDelegate:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+ void AnimationEnded(const gfx::Animation* animation) override;
+
+ bool IsIndeterminate();
+ void OnPaintIndeterminate(gfx::Canvas* canvas);
- // Inclusive range used when displaying values.
- double min_display_value_;
- double max_display_value_;
+ // Current progress to display, should be in the range 0.0 to 1.0.
+ double current_value_ = 0.0;
- // Current value. May be outside of [min_display_value_, max_display_value_].
- double current_value_;
+ // In DP, the preferred height of this progress bar.
+ const int preferred_height_;
- // Tooltip text.
- base::string16 tooltip_text_;
+ std::unique_ptr<gfx::LinearAnimation> indeterminate_bar_animation_;
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 b9067b20c9b..5b416bf7135 100644
--- a/chromium/ui/views/controls/progress_bar_unittest.cc
+++ b/chromium/ui/views/controls/progress_bar_unittest.cc
@@ -10,20 +10,9 @@
namespace views {
-TEST(ProgressBarTest, TooltipTextProperty) {
- ProgressBar bar;
- base::string16 tooltip = base::ASCIIToUTF16("Some text");
- EXPECT_FALSE(bar.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(base::string16(), tooltip);
- base::string16 tooltip_text = base::ASCIIToUTF16("My progress");
- bar.SetTooltipText(tooltip_text);
- EXPECT_TRUE(bar.GetTooltipText(gfx::Point(), &tooltip));
- EXPECT_EQ(tooltip_text, tooltip);
-}
-
TEST(ProgressBarTest, Accessibility) {
ProgressBar bar;
- bar.SetValue(62);
+ bar.SetValue(0.62);
ui::AXViewState state;
bar.GetAccessibleState(&state);
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index a3e1e9787a2..4e970225471 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -4,14 +4,16 @@
#include "ui/views/controls/scroll_view.h"
+#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
#include "ui/events/event.h"
#include "ui/gfx/canvas.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/style/platform_style.h"
-#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget.h"
namespace views {
@@ -19,6 +21,15 @@ const char ScrollView::kViewClassName[] = "ScrollView";
namespace {
+const base::Feature kToolkitViewsScrollWithLayers {
+ "ToolkitViewsScrollWithLayers",
+#if defined(OS_MACOSX)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
// Subclass of ScrollView that resets the border when the theme changes.
class ScrollViewWithBorder : public views::ScrollView {
public:
@@ -64,15 +75,31 @@ int CheckScrollBounds(int viewport_size, int content_size, int current_pos) {
}
// Make sure the content is not scrolled out of bounds
-void CheckScrollBounds(View* viewport, View* view) {
+void ConstrainScrollToBounds(View* viewport, View* view) {
if (!view)
return;
- int x = CheckScrollBounds(viewport->width(), view->width(), -view->x());
- int y = CheckScrollBounds(viewport->height(), view->height(), -view->y());
+ // Note that even when ScrollView::ScrollsWithLayers() is true, the header row
+ // scrolls by repainting.
+ const bool scrolls_with_layers = viewport->layer() != nullptr;
+ if (scrolls_with_layers) {
+ DCHECK(view->layer());
+ DCHECK_EQ(0, view->x());
+ DCHECK_EQ(0, view->y());
+ }
+ gfx::ScrollOffset offset = scrolls_with_layers
+ ? view->layer()->CurrentScrollOffset()
+ : gfx::ScrollOffset(-view->x(), -view->y());
+
+ int x = CheckScrollBounds(viewport->width(), view->width(), offset.x());
+ int y = CheckScrollBounds(viewport->height(), view->height(), offset.y());
- // This is no op if bounds are the same
- view->SetBounds(-x, -y, view->width(), view->height());
+ if (scrolls_with_layers) {
+ view->layer()->SetScrollOffset(gfx::ScrollOffset(x, y));
+ } else {
+ // This is no op if bounds are the same
+ view->SetBounds(-x, -y, view->width(), view->height());
+ }
}
// Used by ScrollToPosition() to make sure the new position fits within the
@@ -105,9 +132,18 @@ class ScrollView::Viewport : public View {
View* contents = child_at(0);
gfx::Rect scroll_rect(rect);
- scroll_rect.Offset(-contents->x(), -contents->y());
- static_cast<ScrollView*>(parent())->ScrollContentsRegionToBeVisible(
- scroll_rect);
+
+ ScrollView* scroll_view = static_cast<ScrollView*>(parent());
+ if (scroll_view->ScrollsWithLayers()) {
+ // With layer scrolling, there's no need to "undo" the offset done in the
+ // child's View::ScrollRectToVisible() before it calls this.
+ DCHECK_EQ(0, contents->x());
+ DCHECK_EQ(0, contents->y());
+ } else {
+ scroll_rect.Offset(-contents->x(), -contents->y());
+ }
+
+ scroll_view->ScrollContentsRegionToBeVisible(scroll_rect);
}
void ChildPreferredSizeChanged(View* child) override {
@@ -129,6 +165,7 @@ ScrollView::ScrollView()
corner_view_(new ScrollCornerView()),
min_height_(-1),
max_height_(-1),
+ background_color_(SK_ColorTRANSPARENT),
hide_horizontal_scrollbar_(false) {
set_notify_enter_exit_on_child(true);
@@ -142,6 +179,10 @@ ScrollView::ScrollView()
vert_sb_->SetVisible(false);
vert_sb_->set_controller(this);
corner_view_->SetVisible(false);
+
+ if (!base::FeatureList::IsEnabled(kToolkitViewsScrollWithLayers))
+ return;
+ EnableViewPortLayer();
}
ScrollView::~ScrollView() {
@@ -158,6 +199,18 @@ ScrollView* ScrollView::CreateScrollViewWithBorder() {
}
void ScrollView::SetContents(View* a_view) {
+ // Protect against clients passing a contents view that has its own Layer.
+ DCHECK(!a_view->layer());
+ if (ScrollsWithLayers()) {
+ if (!a_view->background() && background_color_ != SK_ColorTRANSPARENT) {
+ a_view->set_background(
+ Background::CreateSolidBackground(background_color_));
+ }
+ a_view->SetPaintToLayer(true);
+ a_view->layer()->SetScrollable(
+ contents_viewport_->layer(),
+ base::Bind(&ScrollView::OnLayerScrolled, base::Unretained(this)));
+ }
SetHeaderOrContents(contents_viewport_, a_view, &contents_);
}
@@ -165,11 +218,23 @@ void ScrollView::SetHeader(View* header) {
SetHeaderOrContents(header_viewport_, header, &header_);
}
+void ScrollView::SetBackgroundColor(SkColor color) {
+ background_color_ = color;
+ contents_viewport_->set_background(
+ Background::CreateSolidBackground(background_color_));
+ if (contents_ && ScrollsWithLayers() &&
+ background_color_ != SK_ColorTRANSPARENT) {
+ contents_->set_background(
+ Background::CreateSolidBackground(background_color_));
+ }
+}
+
gfx::Rect ScrollView::GetVisibleRect() const {
if (!contents_)
return gfx::Rect();
- return gfx::Rect(-contents_->x(), -contents_->y(),
- contents_viewport_->width(), contents_viewport_->height());
+ gfx::ScrollOffset offset = CurrentOffset();
+ return gfx::Rect(offset.x(), offset.y(), contents_viewport_->width(),
+ contents_viewport_->height());
}
void ScrollView::ClipHeightTo(int min_height, int max_height) {
@@ -224,8 +289,9 @@ int ScrollView::GetHeightForWidth(int width) const {
}
void ScrollView::Layout() {
+ gfx::Rect available_rect = GetContentsBounds();
if (is_bounded()) {
- int content_width = width();
+ int content_width = available_rect.width();
int content_height = contents()->GetHeightForWidth(content_width);
if (content_height > height()) {
content_width = std::max(content_width - GetScrollBarWidth(), 0);
@@ -243,7 +309,7 @@ void ScrollView::Layout() {
// this default behavior, the inner view has to calculate the available space,
// used ComputeScrollBarsVisibility() to use the same calculation that is done
// here and sets its bound to fit within.
- gfx::Rect viewport_bounds = GetContentsBounds();
+ gfx::Rect viewport_bounds = available_rect;
const int contents_x = viewport_bounds.x();
const int contents_y = viewport_bounds.y();
if (viewport_bounds.IsEmpty()) {
@@ -329,13 +395,22 @@ void ScrollView::Layout() {
if (should_layout_contents && contents_)
contents_->Layout();
+ // Even when |contents_| needs to scroll, it can still be narrower or wider
+ // the viewport. So ensure the scrolling layer can fill the viewport, so that
+ // events will correctly hit it, and overscroll looks correct.
+ if (contents_ && ScrollsWithLayers()) {
+ gfx::Size container_size = contents_ ? contents_->size() : gfx::Size();
+ container_size.SetToMax(viewport_bounds.size());
+ contents_->SetBoundsRect(gfx::Rect(container_size));
+ }
+
header_viewport_->SetBounds(contents_x, contents_y,
viewport_bounds.width(), header_height);
if (header_)
header_->Layout();
- CheckScrollBounds(header_viewport_, header_);
- CheckScrollBounds(contents_viewport_, contents_);
+ ConstrainScrollToBounds(header_viewport_, header_);
+ ConstrainScrollToBounds(contents_viewport_, contents_);
SchedulePaint();
UpdateScrollBarPositions();
}
@@ -379,6 +454,14 @@ void ScrollView::OnMouseExited(const ui::MouseEvent& event) {
vert_sb_->OnMouseExitedScrollView(event);
}
+void ScrollView::OnScrollEvent(ui::ScrollEvent* event) {
+#if defined(OS_MACOSX)
+ // TODO(tapted): Send |event| to a cc::InputHandler. For now, there's nothing
+ // to do because Widget::OnScrollEvent() will automatically process an
+ // unhandled ScrollEvent as a MouseWheelEvent.
+#endif
+}
+
void ScrollView::OnGestureEvent(ui::GestureEvent* event) {
// If the event happened on one of the scrollbars, then those events are
// sent directly to the scrollbars. Otherwise, only scroll events are sent to
@@ -406,24 +489,24 @@ void ScrollView::ScrollToPosition(ScrollBar* source, int position) {
if (!contents_)
return;
+ gfx::ScrollOffset offset = CurrentOffset();
if (source == horiz_sb_ && horiz_sb_->visible()) {
- position = AdjustPosition(contents_->x(), position, contents_->width(),
+ position = AdjustPosition(offset.x(), position, contents_->width(),
contents_viewport_->width());
- if (-contents_->x() == position)
+ if (offset.x() == position)
return;
- contents_->SetX(-position);
- if (header_) {
- header_->SetX(-position);
- header_->SchedulePaintInRect(header_->GetVisibleBounds());
- }
+ offset.set_x(position);
} else if (source == vert_sb_ && vert_sb_->visible()) {
- position = AdjustPosition(contents_->y(), position, contents_->height(),
+ position = AdjustPosition(offset.y(), position, contents_->height(),
contents_viewport_->height());
- if (-contents_->y() == position)
+ if (offset.y() == position)
return;
- contents_->SetY(-position);
+ offset.set_y(position);
}
- contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
+ ScrollToOffset(offset);
+
+ if (!ScrollsWithLayers())
+ contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
}
int ScrollView::GetScrollIncrement(ScrollBar* source, bool is_page,
@@ -504,10 +587,7 @@ void ScrollView::ScrollContentsRegionToBeVisible(const gfx::Rect& rect) {
(vis_rect.y() > y) ? y : std::max(0, max_y -
contents_viewport_->height());
- contents_->SetX(-new_x);
- if (header_)
- header_->SetX(-new_x);
- contents_->SetY(-new_y);
+ ScrollToOffset(gfx::ScrollOffset(new_x, new_y));
UpdateScrollBarPositions();
}
@@ -515,6 +595,12 @@ void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size,
const gfx::Size& content_size,
bool* horiz_is_shown,
bool* vert_is_shown) const {
+ if (hide_horizontal_scrollbar_) {
+ *horiz_is_shown = false;
+ *vert_is_shown = content_size.height() > vp_size.height();
+ return;
+ }
+
// Try to fit both ways first, then try vertical bar only, then horizontal
// bar only, then defaults to both shown.
if (content_size.width() <= vp_size.width() &&
@@ -531,9 +617,6 @@ void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size,
*horiz_is_shown = true;
*vert_is_shown = true;
}
-
- if (hide_horizontal_scrollbar_)
- *horiz_is_shown = false;
}
// Make sure that a single scrollbar is created and visible as needed
@@ -555,17 +638,67 @@ void ScrollView::UpdateScrollBarPositions() {
if (!contents_)
return;
+ const gfx::ScrollOffset offset = CurrentOffset();
if (horiz_sb_->visible()) {
int vw = contents_viewport_->width();
int cw = contents_->width();
- int origin = contents_->x();
- horiz_sb_->Update(vw, cw, -origin);
+ horiz_sb_->Update(vw, cw, offset.x());
}
if (vert_sb_->visible()) {
int vh = contents_viewport_->height();
int ch = contents_->height();
- int origin = contents_->y();
- vert_sb_->Update(vh, ch, -origin);
+ vert_sb_->Update(vh, ch, offset.y());
+ }
+}
+
+gfx::ScrollOffset ScrollView::CurrentOffset() const {
+ return ScrollsWithLayers()
+ ? contents_->layer()->CurrentScrollOffset()
+ : gfx::ScrollOffset(-contents_->x(), -contents_->y());
+}
+
+void ScrollView::ScrollToOffset(const gfx::ScrollOffset& offset) {
+ if (ScrollsWithLayers()) {
+ contents_->layer()->SetScrollOffset(offset);
+
+ // TODO(tapted): Remove this call to OnLayerScrolled(). It's unnecessary,
+ // but will only be invoked (asynchronously) when a Compositor is present
+ // and commits a frame, which isn't true in some tests.
+ // See http://crbug.com/637521.
+ OnLayerScrolled();
+ } else {
+ contents_->SetPosition(gfx::Point(-offset.x(), -offset.y()));
+ ScrollHeader();
+ }
+}
+
+bool ScrollView::ScrollsWithLayers() const {
+ // Just check for the presence of a layer since it's cheaper than querying the
+ // Feature flag each time.
+ return contents_viewport_->layer() != nullptr;
+}
+
+void ScrollView::EnableViewPortLayer() {
+ background_color_ = SK_ColorWHITE;
+ contents_viewport_->set_background(
+ Background::CreateSolidBackground(background_color_));
+ contents_viewport_->SetPaintToLayer(true);
+ contents_viewport_->layer()->SetMasksToBounds(true);
+}
+
+void ScrollView::OnLayerScrolled() {
+ UpdateScrollBarPositions();
+ ScrollHeader();
+}
+
+void ScrollView::ScrollHeader() {
+ if (!header_)
+ return;
+
+ int x_offset = CurrentOffset().x();
+ if (header_->x() != -x_offset) {
+ header_->SetX(-x_offset);
+ header_->SchedulePaintInRect(header_->GetVisibleBounds());
}
}
diff --git a/chromium/ui/views/controls/scroll_view.h b/chromium/ui/views/controls/scroll_view.h
index da384801d96..4ec2221d55d 100644
--- a/chromium/ui/views/controls/scroll_view.h
+++ b/chromium/ui/views/controls/scroll_view.h
@@ -12,7 +12,14 @@
#include "base/macros.h"
#include "ui/views/controls/scrollbar/scroll_bar.h"
+namespace gfx {
+class ScrollOffset;
+}
+
namespace views {
+namespace test {
+class ScrollViewTestApi;
+}
/////////////////////////////////////////////////////////////////////////////
//
@@ -48,6 +55,11 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
// Sets the header, deleting the previous header.
void SetHeader(View* header);
+ // Sets the background color. The default is white when scrolling with layers,
+ // otherwise transparent. An opaque color when scrolling with layers ensures
+ // fonts can be drawn with subpixel antialiasing.
+ void SetBackgroundColor(SkColor color);
+
// Returns the visible region of the content View.
gfx::Rect GetVisibleRect() const;
@@ -84,6 +96,7 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
bool OnMouseWheel(const ui::MouseWheelEvent& e) override;
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
+ void OnScrollEvent(ui::ScrollEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
const char* GetClassName() const override;
@@ -93,8 +106,13 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
bool is_page,
bool is_positive) override;
+ // TODO(djacobo): Remove this method when http://crbug.com/656198 is closed.
+ // Force |contents_viewport_| to enable a Layer().
+ void EnableViewPortLayer();
+
private:
- FRIEND_TEST_ALL_PREFIXES(ScrollViewTest, CornerViewVisibility);
+ friend class test::ScrollViewTestApi;
+
class Viewport;
// Used internally by SetHeader() and SetContents() to reset the view. Sets
@@ -121,6 +139,20 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
// Update the scrollbars positions given viewport and content sizes.
void UpdateScrollBarPositions();
+ // Helpers to get and set the current scroll offset (either from the ui::Layer
+ // or from the |contents_| origin offset).
+ gfx::ScrollOffset CurrentOffset() const;
+ void ScrollToOffset(const gfx::ScrollOffset& offset);
+
+ // Whether the ScrollView scrolls using ui::Layer APIs.
+ bool ScrollsWithLayers() const;
+
+ // Callback entrypoint when hosted Layers are scrolled by the Compositor.
+ void OnLayerScrolled();
+
+ // Horizontally scrolls the header (if any) to match the contents.
+ void ScrollHeader();
+
// The current contents and its viewport. |contents_| is contained in
// |contents_viewport_|.
View* contents_;
@@ -145,6 +177,10 @@ class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
int min_height_;
int max_height_;
+ // The background color given to the viewport (for overscroll), and to the
+ // contents when scrolling with layers.
+ SkColor background_color_;
+
// If true, never show the horizontal scrollbar (even if the contents is wider
// than the viewport).
bool hide_horizontal_scrollbar_;
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index d90784ca906..a5421892f11 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -5,16 +5,66 @@
#include "ui/views/controls/scroll_view.h"
#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/border.h"
+#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
+#include "ui/views/controls/scrollbar/native_scroll_bar.h"
+#include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
#include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
#include "ui/views/test/test_views.h"
+#include "ui/views/test/widget_test.h"
#if defined(OS_MACOSX)
#include "ui/base/test/scoped_preferred_scroller_style_mac.h"
#endif
+enum ScrollBarOrientation { HORIZONTAL, VERTICAL };
+
namespace views {
+namespace test {
+
+class ScrollViewTestApi {
+ public:
+ explicit ScrollViewTestApi(ScrollView* scroll_view)
+ : scroll_view_(scroll_view) {}
+
+ BaseScrollBar* GetBaseScrollBar(ScrollBarOrientation orientation) {
+ ScrollBar* scroll_bar = orientation == VERTICAL ? scroll_view_->vert_sb_
+ : scroll_view_->horiz_sb_;
+ if (scroll_bar->GetClassName() == NativeScrollBar::kViewClassName) {
+ return static_cast<NativeScrollBarViews*>(
+ static_cast<NativeScrollBar*>(scroll_bar)->native_wrapper_);
+ }
+ return static_cast<BaseScrollBar*>(scroll_bar);
+ }
+
+ const base::Timer& GetScrollBarTimer(ScrollBarOrientation orientation) {
+ return GetBaseScrollBar(orientation)->repeater_.timer_for_testing();
+ }
+
+ BaseScrollBarThumb* GetScrollBarThumb(ScrollBarOrientation orientation) {
+ return GetBaseScrollBar(orientation)->thumb_;
+ }
+
+ gfx::Point IntegralViewOffset() {
+ return gfx::Point() - gfx::ScrollOffsetToFlooredVector2d(CurrentOffset());
+ }
+
+ gfx::ScrollOffset CurrentOffset() { return scroll_view_->CurrentOffset(); }
+
+ View* corner_view() { return scroll_view_->corner_view_; }
+ View* contents_viewport() { return scroll_view_->contents_viewport_; }
+
+ private:
+ ScrollView* scroll_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScrollViewTestApi);
+};
+
+} // namespace test
namespace {
@@ -22,8 +72,6 @@ const int kWidth = 100;
const int kMinHeight = 50;
const int kMaxHeight = 100;
-enum ScrollBarOrientation { HORIZONTAL, VERTICAL };
-
// View implementation that allows setting the preferred size.
class CustomView : public View {
public:
@@ -34,6 +82,8 @@ class CustomView : public View {
PreferredSizeChanged();
}
+ const gfx::Point last_location() const { return last_location_; }
+
gfx::Size GetPreferredSize() const override { return preferred_size_; }
void Layout() override {
@@ -47,8 +97,14 @@ class CustomView : public View {
SetBounds(x(), y(), width, height);
}
+ bool OnMousePressed(const ui::MouseEvent& event) override {
+ last_location_ = event.location();
+ return true;
+ }
+
private:
gfx::Size preferred_size_;
+ gfx::Point last_location_;
DISALLOW_COPY_AND_ASSIGN(CustomView);
};
@@ -67,8 +123,115 @@ void CheckScrollbarVisibility(const ScrollView& scroll_view,
}
}
+ui::MouseEvent TestLeftMouseAt(const gfx::Point& location, ui::EventType type) {
+ return ui::MouseEvent(type, location, location, base::TimeTicks(),
+ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+}
+
} // namespace
+using test::ScrollViewTestApi;
+
+// Test harness that includes a Widget to help test ui::Event handling.
+class WidgetScrollViewTest : public test::WidgetTest,
+ public ui::CompositorObserver {
+ public:
+ static const int kDefaultHeight = 100;
+ static const int kDefaultWidth = 100;
+
+ WidgetScrollViewTest() {
+#if defined(OS_MACOSX)
+ // Disable scrollbar hiding (i.e. disable overlay scrollbars) by default.
+ scroller_style_.reset(new ui::test::ScopedPreferredScrollerStyle(false));
+#endif
+ }
+
+ // Adds a ScrollView with the given |contents_view| and does layout.
+ ScrollView* AddScrollViewWithContents(View* contents,
+ bool commit_layers = true) {
+ const gfx::Rect default_bounds(50, 50, kDefaultWidth, kDefaultHeight);
+ widget_ = CreateTopLevelFramelessPlatformWidget();
+
+ ScrollView* scroll_view = new ScrollView();
+ scroll_view->SetContents(contents);
+
+ widget_->SetBounds(default_bounds);
+ widget_->Show();
+
+ widget_->SetContentsView(scroll_view);
+ scroll_view->Layout();
+
+ widget_->GetCompositor()->AddObserver(this);
+
+ // Ensure the Compositor has committed layer changes before attempting to
+ // use them for impl-side scrolling. Note that simply RunUntilIdle() works
+ // when tests are run in isolation, but compositor scheduling can interact
+ // between test runs in the general case.
+ if (commit_layers)
+ WaitForCommit();
+ return scroll_view;
+ }
+
+ // Adds a ScrollView with a contents view of the given |size| and does layout.
+ ScrollView* AddScrollViewWithContentSize(const gfx::Size& contents_size,
+ bool commit_layers = true) {
+ View* contents = new View;
+ contents->SetSize(contents_size);
+ return AddScrollViewWithContents(contents, commit_layers);
+ }
+
+ // Wait for a commit to be observed on the compositor.
+ void WaitForCommit() {
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, quit_closure_, TestTimeouts::action_timeout());
+ run_loop.Run();
+ EXPECT_TRUE(quit_closure_.is_null()) << "Timed out waiting for a commit.";
+ }
+
+ void TestClickAt(const gfx::Point& location) {
+ ui::MouseEvent press(TestLeftMouseAt(location, ui::ET_MOUSE_PRESSED));
+ ui::MouseEvent release(TestLeftMouseAt(location, ui::ET_MOUSE_RELEASED));
+ widget_->OnMouseEvent(&press);
+ widget_->OnMouseEvent(&release);
+ }
+
+ // testing::Test:
+ void TearDown() override {
+ widget_->GetCompositor()->RemoveObserver(this);
+ if (widget_)
+ widget_->CloseNow();
+ WidgetTest::TearDown();
+ }
+
+ private:
+ // ui::CompositorObserver:
+ void OnCompositingDidCommit(ui::Compositor* compositor) override {
+ quit_closure_.Run();
+ quit_closure_.Reset();
+ }
+ void OnCompositingStarted(ui::Compositor* compositor,
+ base::TimeTicks start_time) override {}
+ void OnCompositingEnded(ui::Compositor* compositor) override {}
+ void OnCompositingAborted(ui::Compositor* compositor) override {}
+ void OnCompositingLockStateChanged(ui::Compositor* compositor) override {}
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
+
+ Widget* widget_ = nullptr;
+
+ base::Closure quit_closure_;
+
+#if defined(OS_MACOSX)
+ std::unique_ptr<ui::test::ScopedPreferredScrollerStyle> scroller_style_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetScrollViewTest);
+};
+
+const int WidgetScrollViewTest::kDefaultHeight;
+const int WidgetScrollViewTest::kDefaultWidth;
+
// Verifies the viewport is sized to fit the available space.
TEST(ScrollViewTest, ViewportSizedToFit) {
ScrollView scroll_view;
@@ -79,6 +242,23 @@ TEST(ScrollViewTest, ViewportSizedToFit) {
EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString());
}
+// Verifies the viewport and content is sized to fit the available space for
+// bounded scroll view.
+TEST(ScrollViewTest, BoundedViewportSizedToFit) {
+ ScrollView scroll_view;
+ View* contents = new View;
+ scroll_view.SetContents(contents);
+ scroll_view.ClipHeightTo(100, 200);
+ scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+ scroll_view.SetBorder(Border::CreateSolidBorder(2, 0));
+ scroll_view.Layout();
+ EXPECT_EQ("2,2 96x96", contents->parent()->bounds().ToString());
+
+ // Make sure the width of |contents| is set properly not to overflow the
+ // viewport.
+ EXPECT_EQ(96, contents->width());
+}
+
// Verifies the scrollbars are added as necessary.
// If on Mac, test the non-overlay scrollbars.
TEST(ScrollViewTest, ScrollBars) {
@@ -208,10 +388,25 @@ TEST(ScrollViewTest, Header) {
EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString());
EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString());
+ // With layered scrolling, ScrollView::Layout() will impose a size on the
+ // contents that fills the viewport. Since the test view doesn't have its own
+ // Layout, reset it in this case so that adding a header doesn't shift the
+ // contents down and require scrollbars.
+ if (contents->layer()) {
+ EXPECT_EQ("0,0 100x100", contents->bounds().ToString());
+ contents->SetBoundsRect(gfx::Rect());
+ }
+ EXPECT_EQ("0,0 0x0", contents->bounds().ToString());
+
// Get the header a height of 20.
header->SetPreferredSize(gfx::Size(10, 20));
EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString());
EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString());
+ if (contents->layer()) {
+ EXPECT_EQ("0,0 100x80", contents->bounds().ToString());
+ contents->SetBoundsRect(gfx::Rect());
+ }
+ EXPECT_EQ("0,0 0x0", contents->bounds().ToString());
// Remove the header.
scroll_view.SetHeader(NULL);
@@ -289,6 +484,7 @@ TEST(ScrollViewTest, ScrollBarsWithHeader) {
// Verifies the header scrolls horizontally with the content.
TEST(ScrollViewTest, HeaderScrollsWithContent) {
ScrollView scroll_view;
+ ScrollViewTestApi test_api(&scroll_view);
CustomView* contents = new CustomView;
scroll_view.SetContents(contents);
contents->SetPreferredSize(gfx::Size(500, 500));
@@ -298,44 +494,53 @@ TEST(ScrollViewTest, HeaderScrollsWithContent) {
header->SetPreferredSize(gfx::Size(500, 20));
scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
- EXPECT_EQ("0,0", contents->bounds().origin().ToString());
+ EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
EXPECT_EQ("0,0", header->bounds().origin().ToString());
// Scroll the horizontal scrollbar.
ASSERT_TRUE(scroll_view.horizontal_scroll_bar());
scroll_view.ScrollToPosition(
const_cast<ScrollBar*>(scroll_view.horizontal_scroll_bar()), 1);
- EXPECT_EQ("-1,0", contents->bounds().origin().ToString());
+ EXPECT_EQ("-1,0", test_api.IntegralViewOffset().ToString());
EXPECT_EQ("-1,0", header->bounds().origin().ToString());
// Scrolling the vertical scrollbar shouldn't effect the header.
ASSERT_TRUE(scroll_view.vertical_scroll_bar());
scroll_view.ScrollToPosition(
const_cast<ScrollBar*>(scroll_view.vertical_scroll_bar()), 1);
- EXPECT_EQ("-1,-1", contents->bounds().origin().ToString());
+ EXPECT_EQ("-1,-1", test_api.IntegralViewOffset().ToString());
EXPECT_EQ("-1,0", header->bounds().origin().ToString());
}
// Verifies ScrollRectToVisible() on the child works.
TEST(ScrollViewTest, ScrollRectToVisible) {
+#if defined(OS_MACOSX)
+ ui::test::ScopedPreferredScrollerStyle scroller_style_override(false);
+#endif
ScrollView scroll_view;
+ ScrollViewTestApi test_api(&scroll_view);
CustomView* contents = new CustomView;
scroll_view.SetContents(contents);
contents->SetPreferredSize(gfx::Size(500, 1000));
scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
scroll_view.Layout();
- EXPECT_EQ("0,0", contents->bounds().origin().ToString());
+ EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
// Scroll to y=405 height=10, this should make the y position of the content
// at (405 + 10) - viewport_height (scroll region bottom aligned).
contents->ScrollRectToVisible(gfx::Rect(0, 405, 10, 10));
- const int viewport_height = contents->parent()->height();
- EXPECT_EQ(-(415 - viewport_height), contents->y());
+ const int viewport_height = test_api.contents_viewport()->height();
+
+ // Expect there to be a horizontal scrollbar, making the viewport shorter.
+ EXPECT_LT(viewport_height, 100);
+
+ gfx::ScrollOffset offset = test_api.CurrentOffset();
+ EXPECT_EQ(415 - viewport_height, offset.y());
// Scroll to the current y-location and 10x10; should do nothing.
- contents->ScrollRectToVisible(gfx::Rect(0, -contents->y(), 10, 10));
- EXPECT_EQ(-(415 - viewport_height), contents->y());
+ contents->ScrollRectToVisible(gfx::Rect(0, offset.y(), 10, 10));
+ EXPECT_EQ(415 - viewport_height, test_api.CurrentOffset().y());
}
// Verifies ClipHeightTo() uses the height of the content when it is between the
@@ -361,23 +566,29 @@ TEST(ScrollViewTest, ClipHeightToNormalContentHeight) {
}
// Verifies ClipHeightTo() uses the minimum height when the content is shorter
-// thamn the minimum height value.
+// than the minimum height value.
TEST(ScrollViewTest, ClipHeightToShortContentHeight) {
ScrollView scroll_view;
scroll_view.ClipHeightTo(kMinHeight, kMaxHeight);
const int kShortContentHeight = 10;
- scroll_view.SetContents(
- new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight)));
+ View* contents =
+ new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight));
+ scroll_view.SetContents(contents);
EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.GetPreferredSize());
scroll_view.SizeToPreferredSize();
scroll_view.Layout();
- EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight),
- scroll_view.contents()->size());
+ // Layered scrolling requires the contents to fill the viewport.
+ if (contents->layer()) {
+ EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.contents()->size());
+ } else {
+ EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight),
+ scroll_view.contents()->size());
+ }
EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.size());
}
@@ -436,7 +647,7 @@ TEST(ScrollViewTest, CornerViewVisibility) {
View* contents = new View;
scroll_view.SetContents(contents);
scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
- View* corner_view = scroll_view.corner_view_;
+ View* corner_view = ScrollViewTestApi(&scroll_view).corner_view();
// Corner view should be visible when both scrollbars are visible.
contents->SetBounds(0, 0, 200, 200);
@@ -532,4 +743,161 @@ TEST(ScrollViewTest, CocoaOverlayScrollBars) {
}
#endif
+// Test that increasing the size of the viewport "below" scrolled content causes
+// the content to scroll up so that it still fills the viewport.
+TEST(ScrollViewTest, ConstrainScrollToBounds) {
+ ScrollView scroll_view;
+ ScrollViewTestApi test_api(&scroll_view);
+
+ View* contents = new View;
+ contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+ scroll_view.SetContents(contents);
+ scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+ scroll_view.Layout();
+
+ EXPECT_EQ(gfx::ScrollOffset(), test_api.CurrentOffset());
+
+ // Scroll as far as it goes and query location to discount scroll bars.
+ contents->ScrollRectToVisible(gfx::Rect(300, 300, 1, 1));
+ const gfx::ScrollOffset fully_scrolled = test_api.CurrentOffset();
+ EXPECT_NE(gfx::ScrollOffset(), fully_scrolled);
+
+ // Making the viewport 55 pixels taller should scroll up the same amount.
+ scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 155));
+ scroll_view.Layout();
+ EXPECT_EQ(fully_scrolled.y() - 55, test_api.CurrentOffset().y());
+ EXPECT_EQ(fully_scrolled.x(), test_api.CurrentOffset().x());
+
+ // And 77 pixels wider should scroll left. Also make it short again: the y-
+ // offset from the last change should remain.
+ scroll_view.SetBoundsRect(gfx::Rect(0, 0, 177, 100));
+ scroll_view.Layout();
+ EXPECT_EQ(fully_scrolled.y() - 55, test_api.CurrentOffset().y());
+ EXPECT_EQ(fully_scrolled.x() - 77, test_api.CurrentOffset().x());
+}
+
+// Test scrolling behavior when clicking on the scroll track.
+TEST_F(WidgetScrollViewTest, ScrollTrackScrolling) {
+ // Set up with a vertical scroller.
+ ScrollView* scroll_view =
+ AddScrollViewWithContentSize(gfx::Size(10, kDefaultHeight * 5));
+ ScrollViewTestApi test_api(scroll_view);
+ BaseScrollBar* scroll_bar = test_api.GetBaseScrollBar(VERTICAL);
+ View* thumb = test_api.GetScrollBarThumb(VERTICAL);
+
+ // Click in the middle of the track, ensuring it's below the thumb.
+ const gfx::Point location = scroll_bar->bounds().CenterPoint();
+ EXPECT_GT(location.y(), thumb->bounds().bottom());
+ ui::MouseEvent press(TestLeftMouseAt(location, ui::ET_MOUSE_PRESSED));
+ ui::MouseEvent release(TestLeftMouseAt(location, ui::ET_MOUSE_RELEASED));
+
+ const base::Timer& timer = test_api.GetScrollBarTimer(VERTICAL);
+ EXPECT_FALSE(timer.IsRunning());
+
+ EXPECT_EQ(0, scroll_view->GetVisibleRect().y());
+ scroll_bar->OnMouseEvent(&press);
+
+ // Clicking the scroll track should scroll one "page".
+ EXPECT_EQ(kDefaultHeight, scroll_view->GetVisibleRect().y());
+
+ // While the mouse is pressed, timer should trigger more scroll events.
+ EXPECT_TRUE(timer.IsRunning());
+
+ // Upon release timer should stop (and scroll position should remain).
+ scroll_bar->OnMouseEvent(&release);
+ EXPECT_FALSE(timer.IsRunning());
+ EXPECT_EQ(kDefaultHeight, scroll_view->GetVisibleRect().y());
+}
+
+// Test that LocatedEvents are transformed correctly when scrolling.
+TEST_F(WidgetScrollViewTest, EventLocation) {
+ // Set up with both scrollers.
+ CustomView* contents = new CustomView;
+ contents->SetPreferredSize(gfx::Size(kDefaultHeight * 5, kDefaultHeight * 5));
+ AddScrollViewWithContents(contents);
+
+ const gfx::Point location_in_widget(10, 10);
+
+ // Click without scrolling.
+ TestClickAt(location_in_widget);
+ EXPECT_EQ(location_in_widget, contents->last_location());
+
+ // Scroll down a page.
+ contents->ScrollRectToVisible(
+ gfx::Rect(0, kDefaultHeight, 1, kDefaultHeight));
+ TestClickAt(location_in_widget);
+ EXPECT_EQ(gfx::Point(10, 10 + kDefaultHeight), contents->last_location());
+
+ // Scroll right a page (and back up).
+ contents->ScrollRectToVisible(gfx::Rect(kDefaultWidth, 0, kDefaultWidth, 1));
+ TestClickAt(location_in_widget);
+ EXPECT_EQ(gfx::Point(10 + kDefaultWidth, 10), contents->last_location());
+
+ // Scroll both directions.
+ contents->ScrollRectToVisible(
+ gfx::Rect(kDefaultWidth, kDefaultHeight, kDefaultWidth, kDefaultHeight));
+ TestClickAt(location_in_widget);
+ EXPECT_EQ(gfx::Point(10 + kDefaultWidth, 10 + kDefaultHeight),
+ contents->last_location());
+}
+
+// Test that views scroll offsets are in sync with the layer scroll offsets.
+TEST_F(WidgetScrollViewTest, ScrollOffsetUsingLayers) {
+ // Set up with a vertical scroller, but don't commit the layer changes yet.
+ ScrollView* scroll_view =
+ AddScrollViewWithContentSize(gfx::Size(10, kDefaultHeight * 5), false);
+ ScrollViewTestApi test_api(scroll_view);
+
+ EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset());
+
+ // UI code may request a scroll before layer changes are committed.
+ gfx::Rect offset(0, kDefaultHeight * 2, 1, kDefaultHeight);
+ scroll_view->contents()->ScrollRectToVisible(offset);
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
+
+ // The following only makes sense when layered scrolling is enabled.
+ View* container = scroll_view->contents();
+#if defined(OS_MACOSX)
+ // Sanity check: Mac should always scroll with layers.
+ EXPECT_TRUE(container->layer());
+#endif
+ if (!container->layer())
+ return;
+
+ // Container and viewport should have layers.
+ EXPECT_TRUE(container->layer());
+ EXPECT_TRUE(test_api.contents_viewport()->layer());
+
+ // In a Widget, so there should be a compositor.
+ ui::Compositor* compositor = container->layer()->GetCompositor();
+ EXPECT_TRUE(compositor);
+
+ // But setting on the impl side should fail since the layer isn't committed.
+ int layer_id = container->layer()->cc_layer_for_testing()->id();
+ EXPECT_FALSE(compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, 0)));
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
+
+ WaitForCommit();
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
+
+ // Upon commit, the impl side should report the same value too.
+ gfx::ScrollOffset impl_offset;
+ EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset);
+
+ // Now impl-side scrolling should work, and also update the ScrollView.
+ offset.set_y(kDefaultHeight * 3);
+ EXPECT_TRUE(
+ compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, offset.y())));
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
+
+ // Scroll via ScrollView API. Should be reflected on the impl side.
+ offset.set_y(kDefaultHeight * 4);
+ scroll_view->contents()->ScrollRectToVisible(offset);
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
+
+ EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+ EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset);
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
index 28da57db9a8..82d852944b6 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -290,8 +290,9 @@ void BaseScrollBar::ShowContextMenuForView(View* source,
views::MenuItemView* menu = new views::MenuItemView(this);
// MenuRunner takes ownership of |menu|.
- menu_runner_.reset(new MenuRunner(
- menu, MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
+ menu_runner_.reset(new MenuRunner(menu, MenuRunner::HAS_MNEMONICS |
+ views::MenuRunner::CONTEXT_MENU |
+ views::MenuRunner::ASYNC));
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere);
menu->AppendSeparator();
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart);
@@ -302,13 +303,8 @@ void BaseScrollBar::ShowContextMenuForView(View* source,
menu->AppendSeparator();
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev);
menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext);
- if (menu_runner_->RunMenuAt(GetWidget(),
- NULL,
- gfx::Rect(p, gfx::Size()),
- MENU_ANCHOR_TOPLEFT,
- source_type) == MenuRunner::MENU_DELETED) {
- return;
- }
+ menu_runner_->RunMenuAt(GetWidget(), nullptr, gfx::Rect(p, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT, source_type);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
index 6d6944259d3..b56663dc825 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
@@ -15,6 +15,9 @@
#include "ui/views/repeat_controller.h"
namespace views {
+namespace test {
+class ScrollViewTestApi;
+}
class BaseScrollBarThumb;
class MenuRunner;
@@ -114,6 +117,8 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
virtual int GetScrollIncrement(bool is_page, bool is_positive);
private:
+ friend class test::ScrollViewTestApi;
+
FRIEND_TEST_ALL_PREFIXES(NativeScrollBarTest, ScrollBarFitsToBottom);
FRIEND_TEST_ALL_PREFIXES(NativeScrollBarTest, ThumbFullLengthOfTrack);
int GetThumbSizeForTest();
diff --git a/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
index f11ea1a237d..3c6bb9b607f 100644
--- a/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
+++ b/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -290,6 +290,7 @@ bool CocoaScrollBar::OnMousePressed(const ui::MouseEvent& event) {
void CocoaScrollBar::OnMouseReleased(const ui::MouseEvent& event) {
ResetOverlayScrollbar();
+ BaseScrollBar::OnMouseReleased(event);
}
void CocoaScrollBar::OnMouseEntered(const ui::MouseEvent& event) {
diff --git a/chromium/ui/views/controls/scrollbar/native_scroll_bar.h b/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
index c9d96af77e7..c94089514c3 100644
--- a/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/native_scroll_bar.h
@@ -18,6 +18,9 @@ class NativeTheme;
}
namespace views {
+namespace test {
+class ScrollViewTestApi;
+}
class NativeScrollBarWrapper;
@@ -38,6 +41,7 @@ class VIEWS_EXPORT NativeScrollBar : public ScrollBar {
private:
friend class NativeScrollBarTest;
+ friend class test::ScrollViewTestApi;
FRIEND_TEST_ALL_PREFIXES(NativeScrollBarTest, Scrolling);
// Overridden from View.
diff --git a/chromium/ui/views/controls/single_split_view.cc b/chromium/ui/views/controls/single_split_view.cc
deleted file mode 100644
index 354d3e14bb9..00000000000
--- a/chromium/ui/views/controls/single_split_view.cc
+++ /dev/null
@@ -1,264 +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/controls/single_split_view.h"
-
-#include "build/build_config.h"
-#include "ui/accessibility/ax_view_state.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/gfx/canvas.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/single_split_view_listener.h"
-#include "ui/views/native_cursor.h"
-
-#if defined(OS_WIN)
-#include "skia/ext/skia_utils_win.h"
-#endif
-
-namespace views {
-
-// static
-const char SingleSplitView::kViewClassName[] = "SingleSplitView";
-
-// Size of the divider in pixels.
-static const int kDividerSize = 4;
-
-SingleSplitView::SingleSplitView(View* leading,
- View* trailing,
- Orientation orientation,
- SingleSplitViewListener* listener)
- : is_horizontal_(orientation == HORIZONTAL_SPLIT),
- divider_offset_(-1),
- resize_leading_on_bounds_change_(true),
- resize_disabled_(false),
- listener_(listener) {
- AddChildView(leading);
- AddChildView(trailing);
-#if defined(OS_WIN)
- set_background(
- views::Background::CreateSolidBackground(
- skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE))));
-#endif
-}
-
-void SingleSplitView::Layout() {
- gfx::Rect leading_bounds;
- gfx::Rect trailing_bounds;
- CalculateChildrenBounds(GetContentsBounds(), &leading_bounds,
- &trailing_bounds);
-
- if (has_children()) {
- if (child_at(0)->visible())
- child_at(0)->SetBoundsRect(leading_bounds);
- if (child_count() > 1) {
- if (child_at(1)->visible())
- child_at(1)->SetBoundsRect(trailing_bounds);
- }
- }
-
- // Invoke super's implementation so that the children are layed out.
- View::Layout();
-}
-
-const char* SingleSplitView::GetClassName() const {
- return kViewClassName;
-}
-
-void SingleSplitView::GetAccessibleState(ui::AXViewState* state) {
- state->role = ui::AX_ROLE_GROUP;
- state->name = accessible_name_;
-}
-
-gfx::Size SingleSplitView::GetPreferredSize() const {
- int width = 0;
- int height = 0;
- for (int i = 0; i < 2 && i < child_count(); ++i) {
- const View* view = child_at(i);
- gfx::Size pref = view->GetPreferredSize();
- if (is_horizontal_) {
- width += pref.width();
- height = std::max(height, pref.height());
- } else {
- width = std::max(width, pref.width());
- height += pref.height();
- }
- }
- if (is_horizontal_)
- width += GetDividerSize();
- else
- height += GetDividerSize();
- width += GetInsets().width();
- height += GetInsets().height();
- return gfx::Size(width, height);
-}
-
-gfx::NativeCursor SingleSplitView::GetCursor(const ui::MouseEvent& event) {
- if (!IsPointInDivider(event.location()))
- return gfx::kNullCursor;
- return is_horizontal_ ? GetNativeEastWestResizeCursor()
- : GetNativeNorthSouthResizeCursor();
-}
-
-int SingleSplitView::GetDividerSize() const {
- bool both_visible = child_count() > 1 && child_at(0)->visible() &&
- child_at(1)->visible();
- return both_visible && !resize_disabled_ ? kDividerSize : 0;
-}
-
-void SingleSplitView::CalculateChildrenBounds(
- const gfx::Rect& bounds,
- gfx::Rect* leading_bounds,
- gfx::Rect* trailing_bounds) const {
- bool is_leading_visible = has_children() && child_at(0)->visible();
- bool is_trailing_visible = child_count() > 1 && child_at(1)->visible();
-
- if (!is_leading_visible && !is_trailing_visible) {
- *leading_bounds = gfx::Rect();
- *trailing_bounds = gfx::Rect();
- return;
- }
-
- int divider_at;
-
- if (!is_trailing_visible) {
- divider_at = GetPrimaryAxisSize(bounds.width(), bounds.height());
- } else if (!is_leading_visible) {
- divider_at = 0;
- } else {
- divider_at = CalculateDividerOffset(divider_offset_, bounds, bounds);
- divider_at = NormalizeDividerOffset(divider_at, bounds);
- }
-
- int divider_size = GetDividerSize();
-
- if (is_horizontal_) {
- *leading_bounds =
- gfx::Rect(bounds.x(), bounds.y(), divider_at, bounds.height());
- *trailing_bounds =
- gfx::Rect(divider_at + divider_size + bounds.x(), bounds.y(),
- std::max(0, bounds.width() - divider_at - divider_size),
- bounds.height());
- } else {
- *leading_bounds =
- gfx::Rect(bounds.x(), bounds.y(), bounds.width(), divider_at);
- *trailing_bounds = gfx::Rect(
- bounds.x(), divider_at + divider_size + bounds.y(), bounds.width(),
- std::max(0, bounds.height() - divider_at - divider_size));
- }
-}
-
-void SingleSplitView::SetAccessibleName(const base::string16& name) {
- accessible_name_ = name;
-}
-
-bool SingleSplitView::OnMousePressed(const ui::MouseEvent& event) {
- if (!IsPointInDivider(event.location()))
- return false;
- drag_info_.initial_mouse_offset = GetPrimaryAxisSize(event.x(), event.y());
- drag_info_.initial_divider_offset =
- NormalizeDividerOffset(divider_offset_, GetContentsBounds());
- return true;
-}
-
-bool SingleSplitView::OnMouseDragged(const ui::MouseEvent& event) {
- if (child_count() < 2)
- return false;
-
- int delta_offset = GetPrimaryAxisSize(event.x(), event.y()) -
- drag_info_.initial_mouse_offset;
- if (is_horizontal_ && base::i18n::IsRTL())
- delta_offset *= -1;
- // Honor the first child's minimum size when resizing.
- gfx::Size min = child_at(0)->GetMinimumSize();
- int new_size = std::max(GetPrimaryAxisSize(min.width(), min.height()),
- drag_info_.initial_divider_offset + delta_offset);
-
- // Honor the second child's minimum size, and don't let the view
- // get bigger than our width.
- min = child_at(1)->GetMinimumSize();
- new_size = std::min(GetPrimaryAxisSize() - kDividerSize -
- GetPrimaryAxisSize(min.width(), min.height()), new_size);
-
- if (new_size != divider_offset_) {
- set_divider_offset(new_size);
- if (!listener_ || listener_->SplitHandleMoved(this))
- Layout();
- }
- return true;
-}
-
-void SingleSplitView::OnMouseCaptureLost() {
- if (child_count() < 2)
- return;
-
- if (drag_info_.initial_divider_offset != divider_offset_) {
- set_divider_offset(drag_info_.initial_divider_offset);
- if (!listener_ || listener_->SplitHandleMoved(this))
- Layout();
- }
-}
-
-void SingleSplitView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
- gfx::Rect previous_content_bounds = previous_bounds;
- previous_content_bounds.Inset(GetInsets());
- divider_offset_ = CalculateDividerOffset(
- divider_offset_, previous_content_bounds, GetContentsBounds());
-}
-
-bool SingleSplitView::IsPointInDivider(const gfx::Point& p) {
- if (resize_disabled_)
- return false;
-
- if (child_count() < 2)
- return false;
-
- if (!child_at(0)->visible() || !child_at(1)->visible())
- return false;
-
- int divider_relative_offset;
- if (is_horizontal_) {
- divider_relative_offset =
- p.x() - child_at(base::i18n::IsRTL() ? 1 : 0)->width();
- } else {
- divider_relative_offset = p.y() - child_at(0)->height();
- }
- return (divider_relative_offset >= 0 &&
- divider_relative_offset < GetDividerSize());
-}
-
-int SingleSplitView::CalculateDividerOffset(
- int divider_offset,
- const gfx::Rect& previous_bounds,
- const gfx::Rect& new_bounds) const {
- if (resize_leading_on_bounds_change_ && divider_offset != -1) {
- // We do not update divider_offset on minimize (to zero) and on restore
- // (to largest value). As a result we get back to the original value upon
- // window restore.
- bool is_minimize_or_restore =
- previous_bounds.height() == 0 || new_bounds.height() == 0;
- if (!is_minimize_or_restore) {
- if (is_horizontal_)
- divider_offset += new_bounds.width() - previous_bounds.width();
- else
- divider_offset += new_bounds.height() - previous_bounds.height();
-
- if (divider_offset < 0)
- divider_offset = GetDividerSize();
- }
- }
- return divider_offset;
-}
-
-int SingleSplitView::NormalizeDividerOffset(int divider_offset,
- const gfx::Rect& bounds) const {
- int primary_axis_size = GetPrimaryAxisSize(bounds.width(), bounds.height());
- if (divider_offset < 0)
- // primary_axis_size may < GetDividerSize during initial layout.
- return std::max(0, (primary_axis_size - GetDividerSize()) / 2);
- return std::min(divider_offset,
- std::max(primary_axis_size - GetDividerSize(), 0));
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/single_split_view.h b/chromium/ui/views/controls/single_split_view.h
deleted file mode 100644
index 2cc21ea8a84..00000000000
--- a/chromium/ui/views/controls/single_split_view.h
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2011 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_CONTROLS_SINGLE_SPLIT_VIEW_H_
-#define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "ui/views/view.h"
-
-namespace views {
-
-class SingleSplitViewListener;
-
-// SingleSplitView lays out two views next to each other, either horizontally
-// or vertically. A splitter exists between the two views that the user can
-// drag around to resize the views.
-// SingleSplitViewListener's SplitHandleMoved notification helps to monitor user
-// initiated layout changes.
-class VIEWS_EXPORT SingleSplitView : public View {
- public:
- enum Orientation {
- HORIZONTAL_SPLIT,
- VERTICAL_SPLIT
- };
-
- static const char kViewClassName[];
-
- SingleSplitView(View* leading,
- View* trailing,
- Orientation orientation,
- SingleSplitViewListener* listener);
-
- void Layout() override;
- const char* GetClassName() const override;
-
- void GetAccessibleState(ui::AXViewState* state) override;
-
- // SingleSplitView's preferred size is the sum of the preferred widths
- // and the max of the heights.
- gfx::Size GetPreferredSize() const override;
-
- // Overriden to return a resize cursor when over the divider.
- gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
-
- Orientation orientation() const {
- return is_horizontal_ ? HORIZONTAL_SPLIT : VERTICAL_SPLIT;
- }
-
- void set_orientation(Orientation orientation) {
- is_horizontal_ = orientation == HORIZONTAL_SPLIT;
- }
-
- void set_divider_offset(int divider_offset) {
- divider_offset_ = divider_offset;
- }
- int divider_offset() const { return divider_offset_; }
-
- int GetDividerSize() const;
-
- void set_resize_disabled(bool resize_disabled) {
- resize_disabled_ = resize_disabled;
- }
- bool is_resize_disabled() const { return resize_disabled_; }
-
- // Sets whether the leading component is resized when the split views size
- // changes. The default is true. A value of false results in the trailing
- // component resizing on a bounds change.
- void set_resize_leading_on_bounds_change(bool resize) {
- resize_leading_on_bounds_change_ = resize;
- }
-
- // Calculates ideal leading and trailing view bounds according to the given
- // split view |bounds|, current divider offset and children visiblity.
- // Does not change children view bounds.
- void CalculateChildrenBounds(const gfx::Rect& bounds,
- gfx::Rect* leading_bounds,
- gfx::Rect* trailing_bounds) const;
-
- void SetAccessibleName(const base::string16& name);
-
- protected:
- // View overrides.
- bool OnMousePressed(const ui::MouseEvent& event) override;
- bool OnMouseDragged(const ui::MouseEvent& event) override;
- void OnMouseCaptureLost() override;
- void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
-
- private:
- // This test calls OnMouse* functions.
- FRIEND_TEST_ALL_PREFIXES(SingleSplitViewTest, MouseDrag);
-
- // Returns true if |x| or |y| is over the divider.
- bool IsPointInDivider(const gfx::Point& p);
-
- // Calculates the new |divider_offset| based on the changes of split view
- // bounds.
- int CalculateDividerOffset(int divider_offset,
- const gfx::Rect& previous_bounds,
- const gfx::Rect& new_bounds) const;
-
- // Returns divider offset within primary axis size range for given split
- // view |bounds|.
- int NormalizeDividerOffset(int divider_offset, const gfx::Rect& bounds) const;
-
- // Returns width in case of horizontal split and height otherwise.
- int GetPrimaryAxisSize() const {
- return GetPrimaryAxisSize(width(), height());
- }
-
- int GetPrimaryAxisSize(int h, int v) const {
- return is_horizontal_ ? h : v;
- }
-
- // Used to track drag info.
- struct DragInfo {
- // The initial coordinate of the mouse when the user started the drag.
- int initial_mouse_offset;
- // The initial position of the divider when the user started the drag.
- int initial_divider_offset;
- };
-
- DragInfo drag_info_;
-
- // Orientation of the split view.
- bool is_horizontal_;
-
- // Position of the divider.
- int divider_offset_;
-
- bool resize_leading_on_bounds_change_;
-
- // Whether resizing is disabled.
- bool resize_disabled_;
-
- // Listener to notify about user initiated handle movements. Not owned.
- SingleSplitViewListener* listener_;
-
- // The accessible name of this view.
- base::string16 accessible_name_;
-
- DISALLOW_COPY_AND_ASSIGN(SingleSplitView);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
diff --git a/chromium/ui/views/controls/single_split_view_listener.h b/chromium/ui/views/controls/single_split_view_listener.h
deleted file mode 100644
index 0d589c9cfb8..00000000000
--- a/chromium/ui/views/controls/single_split_view_listener.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2011 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_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
-#define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
-
-#include "ui/views/views_export.h"
-
-namespace views {
-
-class SingleSplitView;
-
-// An interface implemented by objects that want to be notified when the
-// splitter moves.
-class VIEWS_EXPORT SingleSplitViewListener {
- public:
- // Invoked when split handle is moved by the user. |sender|'s divider_offset
- // is already set to the new value, but Layout has not happened yet.
- // Returns false if the layout has been handled by the listener, returns
- // true if |sender| should do it by itself.
- virtual bool SplitHandleMoved(SingleSplitView* sender) = 0;
-
- protected:
- virtual ~SingleSplitViewListener() {}
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
diff --git a/chromium/ui/views/controls/single_split_view_unittest.cc b/chromium/ui/views/controls/single_split_view_unittest.cc
deleted file mode 100644
index d2a588e0c74..00000000000
--- a/chromium/ui/views/controls/single_split_view_unittest.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) 2011 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/controls/single_split_view.h"
-
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event_utils.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/single_split_view_listener.h"
-
-namespace {
-
-static void VerifySplitViewLayout(const views::SingleSplitView& split) {
- ASSERT_EQ(2, split.child_count());
-
- const views::View* leading = split.child_at(0);
- const views::View* trailing = split.child_at(1);
-
- if (split.bounds().IsEmpty()) {
- EXPECT_TRUE(leading->bounds().IsEmpty());
- EXPECT_TRUE(trailing->bounds().IsEmpty());
- return;
- }
-
- EXPECT_FALSE(leading->bounds().IsEmpty());
- EXPECT_FALSE(trailing->bounds().IsEmpty());
- EXPECT_FALSE(leading->bounds().Intersects(trailing->bounds()));
-
- if (split.orientation() == views::SingleSplitView::HORIZONTAL_SPLIT) {
- EXPECT_EQ(leading->bounds().height(),
- split.bounds().height() - split.GetInsets().height());
- EXPECT_EQ(trailing->bounds().height(),
- split.bounds().height() - split.GetInsets().height());
- EXPECT_LT(leading->bounds().width() + trailing->bounds().width(),
- split.bounds().width() - split.GetInsets().width());
- } else if (split.orientation() == views::SingleSplitView::VERTICAL_SPLIT) {
- EXPECT_EQ(leading->bounds().width(),
- split.bounds().width() - split.GetInsets().width());
- EXPECT_EQ(trailing->bounds().width(),
- split.bounds().width() - split.GetInsets().width());
- EXPECT_LT(leading->bounds().height() + trailing->bounds().height(),
- split.bounds().height() - split.GetInsets().height());
- } else {
- NOTREACHED();
- }
-}
-
-class SingleSplitViewListenerImpl : public views::SingleSplitViewListener {
- public:
- SingleSplitViewListenerImpl() : count_(0) {}
-
- bool SplitHandleMoved(views::SingleSplitView* sender) override {
- ++count_;
- return false;
- }
-
- int count() const { return count_; }
-
- private:
- int count_;
-
- DISALLOW_COPY_AND_ASSIGN(SingleSplitViewListenerImpl);
-};
-
-class MinimumSizedView: public views::View {
- public:
- MinimumSizedView(gfx::Size min_size) : min_size_(min_size) {}
-
- private:
- gfx::Size min_size_;
- gfx::Size GetMinimumSize() const override;
-};
-
-gfx::Size MinimumSizedView::GetMinimumSize() const {
- return min_size_;
-}
-
-} // namespace
-
-namespace views {
-
-TEST(SingleSplitViewTest, Resize) {
- // Test cases to iterate through for horizontal and vertical split views.
- struct TestCase {
- // Split view resize policy for this test case.
- bool resize_leading_on_bounds_change;
- // Split view size to set.
- int primary_axis_size;
- int secondary_axis_size;
- // Expected divider offset.
- int divider_offset;
- } test_cases[] = {
- // The initial split size is 100x100, divider at 33.
- { true, 100, 100, 33 },
- // Grow the split view, leading view should grow.
- { true, 1000, 100, 933 },
- // Shrink the split view, leading view should shrink.
- { true, 200, 100, 133 },
- // Minimize the split view, divider should not move.
- { true, 0, 0, 133 },
- // Restore the split view, divider should not move.
- { false, 500, 100, 133 },
- // Resize the split view by secondary axis, divider should not move.
- { false, 500, 600, 133 }
- };
-
- SingleSplitView::Orientation orientations[] = {
- SingleSplitView::HORIZONTAL_SPLIT,
- SingleSplitView::VERTICAL_SPLIT
- };
-
- int borders[][4] = {
- {0, 0, 0, 0}, {5, 5, 5, 5}, {10, 5, 5, 0},
- };
-
- for (size_t orientation = 0; orientation < arraysize(orientations);
- ++orientation) {
- for (size_t border = 0; border < arraysize(borders); ++border) {
- // Create a split view.
- SingleSplitView split(new View(), new View(), orientations[orientation],
- NULL);
-
- // Set initial size and divider offset.
- EXPECT_EQ(test_cases[0].primary_axis_size,
- test_cases[0].secondary_axis_size);
- split.SetBounds(0, 0, test_cases[0].primary_axis_size,
- test_cases[0].secondary_axis_size);
-
- if (border != 0)
- split.SetBorder(
- Border::CreateEmptyBorder(borders[border][0], borders[border][1],
- borders[border][2], borders[border][3]));
-
- split.set_divider_offset(test_cases[0].divider_offset);
- split.Layout();
-
- // Run all test cases.
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- split.set_resize_leading_on_bounds_change(
- test_cases[i].resize_leading_on_bounds_change);
- if (split.orientation() == SingleSplitView::HORIZONTAL_SPLIT) {
- split.SetBounds(0, 0, test_cases[i].primary_axis_size,
- test_cases[i].secondary_axis_size);
- } else {
- split.SetBounds(0, 0, test_cases[i].secondary_axis_size,
- test_cases[i].primary_axis_size);
- }
-
- EXPECT_EQ(test_cases[i].divider_offset, split.divider_offset());
- VerifySplitViewLayout(split);
- }
-
- // Special cases, one of the child views is hidden.
- split.child_at(0)->SetVisible(false);
- split.Layout();
-
- EXPECT_EQ(split.GetContentsBounds().size(), split.child_at(1)->size());
-
- split.child_at(0)->SetVisible(true);
- split.child_at(1)->SetVisible(false);
- split.Layout();
-
- EXPECT_EQ(split.GetContentsBounds().size(), split.child_at(0)->size());
- }
- }
-}
-
-TEST(SingleSplitViewTest, MouseDrag) {
- const int kMinimumChildSize = 25;
- MinimumSizedView *child0 =
- new MinimumSizedView(gfx::Size(5, kMinimumChildSize));
- MinimumSizedView *child1 =
- new MinimumSizedView(gfx::Size(5, kMinimumChildSize));
- SingleSplitViewListenerImpl listener;
- SingleSplitView split(
- child0, child1, SingleSplitView::VERTICAL_SPLIT, &listener);
-
- const int kTotalSplitSize = 100;
- split.SetBounds(0, 0, 10, kTotalSplitSize);
- const int kInitialDividerOffset = 33;
- const int kMouseOffset = 2; // Mouse offset in the divider.
- const int kMouseMoveDelta = 7;
- split.set_divider_offset(kInitialDividerOffset);
- split.Layout();
-
- gfx::Point press_point(7, kInitialDividerOffset + kMouseOffset);
- ui::MouseEvent mouse_pressed(ui::ET_MOUSE_PRESSED, press_point, press_point,
- ui::EventTimeForNow(), 0, 0);
- ASSERT_TRUE(split.OnMousePressed(mouse_pressed));
- EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
- EXPECT_EQ(0, listener.count());
-
- // Drag divider to the bottom.
- gfx::Point drag_1_point(
- 5, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta);
- ui::MouseEvent mouse_dragged_1(ui::ET_MOUSE_DRAGGED, drag_1_point,
- drag_1_point, ui::EventTimeForNow(), 0, 0);
- ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_1));
- EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta, split.divider_offset());
- EXPECT_EQ(1, listener.count());
-
- // Drag divider to the top, beyond first child minimum size.
- gfx::Point drag_2_point(
- 7, kMinimumChildSize - 5);
- ui::MouseEvent mouse_dragged_2(ui::ET_MOUSE_DRAGGED, drag_2_point,
- drag_2_point, ui::EventTimeForNow(), 0, 0);
- ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_2));
- EXPECT_EQ(kMinimumChildSize, split.divider_offset());
- EXPECT_EQ(2, listener.count());
-
- // Drag divider to the bottom, beyond second child minimum size.
- gfx::Point drag_3_point(
- 7, kTotalSplitSize - kMinimumChildSize + 5);
- ui::MouseEvent mouse_dragged_3(ui::ET_MOUSE_DRAGGED, drag_3_point,
- drag_3_point, ui::EventTimeForNow(), 0, 0);
- ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_3));
- EXPECT_EQ(kTotalSplitSize - kMinimumChildSize - split.GetDividerSize(),
- split.divider_offset());
- EXPECT_EQ(3, listener.count());
-
- // Drag divider between childs' minimum sizes.
- gfx::Point drag_4_point(
- 6, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2);
- ui::MouseEvent mouse_dragged_4(ui::ET_MOUSE_DRAGGED, drag_4_point,
- drag_4_point, ui::EventTimeForNow(), 0, 0);
- ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_4));
- EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
- split.divider_offset());
- EXPECT_EQ(4, listener.count());
-
- gfx::Point release_point(
- 7, kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2);
- ui::MouseEvent mouse_released(ui::ET_MOUSE_RELEASED, release_point,
- release_point, ui::EventTimeForNow(), 0, 0);
- split.OnMouseReleased(mouse_released);
- EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
- split.divider_offset());
-
- // Expect intial offset after a system/user gesture cancels the drag.
- // This shouldn't occur after mouse release, but it's sufficient for testing.
- split.OnMouseCaptureLost();
- EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
- EXPECT_EQ(5, listener.count());
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/slider.cc b/chromium/ui/views/controls/slider.cc
index c930e3c66ee..5bf9f1301d6 100644
--- a/chromium/ui/views/controls/slider.cc
+++ b/chromium/ui/views/controls/slider.cc
@@ -21,25 +21,13 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/controls/md_slider.h"
+#include "ui/views/controls/non_md_slider.h"
#include "ui/views/resources/grit/views_resources.h"
#include "ui/views/widget/widget.h"
namespace {
-const int kSlideValueChangeDurationMS = 150;
-
-const int kBarImagesActive[] = {
- IDR_SLIDER_ACTIVE_LEFT,
- IDR_SLIDER_ACTIVE_CENTER,
- IDR_SLIDER_PRESSED_CENTER,
- IDR_SLIDER_PRESSED_RIGHT,
-};
-
-const int kBarImagesDisabled[] = {
- IDR_SLIDER_DISABLED_LEFT,
- IDR_SLIDER_DISABLED_CENTER,
- IDR_SLIDER_DISABLED_CENTER,
- IDR_SLIDER_DISABLED_RIGHT,
-};
+const int kSlideValueChangeDurationMs = 150;
// The image chunks.
enum BorderElements {
@@ -55,36 +43,64 @@ namespace views {
// static
const char Slider::kViewClassName[] = "Slider";
-Slider::Slider(SliderListener* listener, Orientation orientation)
+// static
+Slider* Slider::CreateSlider(bool is_material_design,
+ SliderListener* listener) {
+ if (is_material_design)
+ return new MdSlider(listener);
+ return new NonMdSlider(listener);
+}
+
+Slider::~Slider() {
+}
+
+void Slider::SetValue(float value) {
+ SetValueInternal(value, VALUE_CHANGED_BY_API);
+}
+
+void Slider::SetAccessibleName(const base::string16& name) {
+ accessible_name_ = name;
+}
+
+Slider::Slider(SliderListener* listener)
: listener_(listener),
- orientation_(orientation),
value_(0.f),
keyboard_increment_(0.1f),
- animating_value_(0.f),
+ initial_animating_value_(0.f),
value_is_valid_(false),
accessibility_events_enabled_(true),
focus_border_color_(0),
- bar_active_images_(kBarImagesActive),
- bar_disabled_images_(kBarImagesDisabled) {
+ initial_button_offset_(0) {
EnableCanvasFlippingForRTLUI(true);
#if defined(OS_MACOSX)
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
#else
SetFocusBehavior(FocusBehavior::ALWAYS);
#endif
+}
- UpdateState(true);
+float Slider::GetAnimatingValue() const{
+ return move_animation_ && move_animation_->is_animating()
+ ? move_animation_->CurrentValueBetween(initial_animating_value_,
+ value_)
+ : value_;
}
-Slider::~Slider() {
+void Slider::SetHighlighted(bool is_highlighted) {}
+
+void Slider::OnPaint(gfx::Canvas* canvas) {
+ View::OnPaint(canvas);
+ OnPaintFocus(canvas);
}
-void Slider::SetValue(float value) {
- SetValueInternal(value, VALUE_CHANGED_BY_API);
+void Slider::AnimationProgressed(const gfx::Animation* animation) {
+ if (animation == move_animation_.get())
+ SchedulePaint();
}
-void Slider::SetKeyboardIncrement(float increment) {
- keyboard_increment_ = increment;
+void Slider::AnimationEnded(const gfx::Animation* animation) {
+ if (animation == move_animation_.get())
+ move_animation_.reset();
}
void Slider::SetValueInternal(float value, SliderChangeReason reason) {
@@ -105,81 +121,46 @@ void Slider::SetValueInternal(float value, SliderChangeReason reason) {
if (old_value_valid && base::MessageLoop::current()) {
// Do not animate when setting the value of the slider for the first time.
// There is no message-loop when running tests. So we cannot animate then.
- animating_value_ = old_value;
- move_animation_.reset(new gfx::SlideAnimation(this));
- move_animation_->SetSlideDuration(kSlideValueChangeDurationMS);
- move_animation_->Show();
- AnimationProgressed(move_animation_.get());
+ if (!move_animation_) {
+ initial_animating_value_ = old_value;
+ move_animation_.reset(new gfx::SlideAnimation(this));
+ move_animation_->SetSlideDuration(kSlideValueChangeDurationMs);
+ move_animation_->Show();
+ }
} else {
SchedulePaint();
}
- if (accessibility_events_enabled_ && GetWidget()) {
- NotifyAccessibilityEvent(
- ui::AX_EVENT_VALUE_CHANGED, true);
- }
+ if (accessibility_events_enabled_ && GetWidget())
+ NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
}
-void Slider::PrepareForMove(const gfx::Point& point) {
+void Slider::PrepareForMove(const int new_x) {
// Try to remember the position of the mouse cursor on the button.
gfx::Insets inset = GetInsets();
gfx::Rect content = GetContentsBounds();
- float value = move_animation_.get() && move_animation_->is_animating() ?
- animating_value_ : value_;
+ float value = GetAnimatingValue();
- // For the horizontal orientation.
- const int thumb_x = value * (content.width() - thumb_->width());
+ const int thumb_width = GetThumbWidth();
+ const int thumb_x = value * (content.width() - thumb_width);
const int candidate_x = (base::i18n::IsRTL() ?
- width() - (point.x() - inset.left()) :
- point.x() - inset.left()) - thumb_x;
- if (candidate_x >= 0 && candidate_x < thumb_->width())
- initial_button_offset_.set_x(candidate_x);
- else
- initial_button_offset_.set_x(thumb_->width() / 2);
-
- // For the vertical orientation.
- const int thumb_y = (1.0 - value) * (content.height() - thumb_->height());
- const int candidate_y = point.y() - thumb_y;
- if (candidate_y >= 0 && candidate_y < thumb_->height())
- initial_button_offset_.set_y(candidate_y);
+ width() - (new_x - inset.left()) :
+ new_x - inset.left()) - thumb_x;
+ if (candidate_x >= 0 && candidate_x < thumb_width)
+ initial_button_offset_ = candidate_x;
else
- initial_button_offset_.set_y(thumb_->height() / 2);
+ initial_button_offset_ = thumb_width / 2;
}
void Slider::MoveButtonTo(const gfx::Point& point) {
- gfx::Insets inset = GetInsets();
+ const gfx::Insets inset = GetInsets();
+ const int thumb_width = GetThumbWidth();
// Calculate the value.
- if (orientation_ == HORIZONTAL) {
- int amount = base::i18n::IsRTL() ?
- width() - inset.left() - point.x() - initial_button_offset_.x() :
- point.x() - inset.left() - initial_button_offset_.x();
- SetValueInternal(static_cast<float>(amount) /
- (width() - inset.width() - thumb_->width()),
- VALUE_CHANGED_BY_USER);
- } else {
- SetValueInternal(
- 1.0f - static_cast<float>(point.y() - initial_button_offset_.y()) /
- (height() - thumb_->height()),
- VALUE_CHANGED_BY_USER);
- }
-}
-
-void Slider::UpdateState(bool control_on) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- if (control_on) {
- thumb_ = rb.GetImageNamed(IDR_SLIDER_ACTIVE_THUMB).ToImageSkia();
- for (int i = 0; i < 4; ++i)
- images_[i] = rb.GetImageNamed(bar_active_images_[i]).ToImageSkia();
- } else {
- thumb_ = rb.GetImageNamed(IDR_SLIDER_DISABLED_THUMB).ToImageSkia();
- for (int i = 0; i < 4; ++i)
- images_[i] = rb.GetImageNamed(bar_disabled_images_[i]).ToImageSkia();
- }
- bar_height_ = images_[LEFT]->height();
- SchedulePaint();
-}
-
-void Slider::SetAccessibleName(const base::string16& name) {
- accessible_name_ = name;
+ int amount = base::i18n::IsRTL()
+ ? width() - inset.left() - point.x() - initial_button_offset_
+ : point.x() - inset.left() - initial_button_offset_;
+ SetValueInternal(
+ static_cast<float>(amount) / (width() - inset.width() - thumb_width),
+ VALUE_CHANGED_BY_USER);
}
void Slider::OnPaintFocus(gfx::Canvas* canvas) {
@@ -195,6 +176,18 @@ void Slider::OnPaintFocus(gfx::Canvas* canvas) {
}
}
+void Slider::OnSliderDragStarted() {
+ SetHighlighted(true);
+ if (listener_)
+ listener_->SliderDragStarted(this);
+}
+
+void Slider::OnSliderDragEnded() {
+ SetHighlighted(false);
+ if (listener_)
+ listener_->SliderDragEnded(this);
+}
+
const char* Slider::GetClassName() const {
return kViewClassName;
}
@@ -203,87 +196,14 @@ gfx::Size Slider::GetPreferredSize() const {
const int kSizeMajor = 200;
const int kSizeMinor = 40;
- if (orientation_ == HORIZONTAL)
- return gfx::Size(std::max(width(), kSizeMajor), kSizeMinor);
- return gfx::Size(kSizeMinor, std::max(height(), kSizeMajor));
-}
-
-void Slider::OnPaint(gfx::Canvas* canvas) {
- View::OnPaint(canvas);
- gfx::Rect content = GetContentsBounds();
- float value = move_animation_.get() && move_animation_->is_animating() ?
- animating_value_ : value_;
- if (orientation_ == HORIZONTAL) {
- // Paint slider bar with image resources.
-
- // Inset the slider bar a little bit, so that the left or the right end of
- // the slider bar will not be exposed under the thumb button when the thumb
- // button slides to the left most or right most position.
- const int kBarInsetX = 2;
- int bar_width = content.width() - kBarInsetX * 2;
- int bar_cy = content.height() / 2 - bar_height_ / 2;
-
- int w = content.width() - thumb_->width();
- int full = value * w;
- int middle = std::max(full, images_[LEFT]->width());
-
- canvas->Save();
- canvas->Translate(gfx::Vector2d(kBarInsetX, bar_cy));
- canvas->DrawImageInt(*images_[LEFT], 0, 0);
- canvas->DrawImageInt(*images_[RIGHT],
- bar_width - images_[RIGHT]->width(),
- 0);
- canvas->TileImageInt(*images_[CENTER_LEFT],
- images_[LEFT]->width(),
- 0,
- middle - images_[LEFT]->width(),
- bar_height_);
- canvas->TileImageInt(*images_[CENTER_RIGHT],
- middle,
- 0,
- bar_width - middle - images_[RIGHT]->width(),
- bar_height_);
- canvas->Restore();
-
- // Paint slider thumb.
- int button_cx = content.x() + full;
- int thumb_y = content.height() / 2 - thumb_->height() / 2;
- canvas->DrawImageInt(*thumb_, button_cx, thumb_y);
- } else {
- // TODO(jennyz): draw vertical slider bar with resources.
- // TODO(sad): The painting code should use NativeTheme for various
- // platforms.
- const int kButtonRadius = thumb_->width() / 2;
- const int kLineThickness = bar_height_ / 2;
- const SkColor kFullColor = SkColorSetARGB(125, 0, 0, 0);
- const SkColor kEmptyColor = SkColorSetARGB(50, 0, 0, 0);
-
- int h = content.height() - thumb_->height();
- int full = value * h;
- int empty = h - full;
- int x = content.width() / 2 - kLineThickness / 2;
- canvas->FillRect(gfx::Rect(x, content.y() + kButtonRadius,
- kLineThickness, empty),
- kEmptyColor);
- canvas->FillRect(gfx::Rect(x, content.y() + empty + 2 * kButtonRadius,
- kLineThickness, full),
- kFullColor);
-
- // TODO(mtomasz): We draw a thumb here because so far it is the same
- // for horizontal and vertical orientations. If it is different, then
- // we will need a separate resource.
- int button_cy = content.y() + h - full;
- int thumb_x = content.width() / 2 - thumb_->width() / 2;
- canvas->DrawImageInt(*thumb_, thumb_x, button_cy);
- }
- OnPaintFocus(canvas);
+ return gfx::Size(std::max(width(), kSizeMajor), kSizeMinor);
}
bool Slider::OnMousePressed(const ui::MouseEvent& event) {
if (!event.IsOnlyLeftMouseButton())
return false;
OnSliderDragStarted();
- PrepareForMove(event.location());
+ PrepareForMove(event.location().x());
MoveButtonTo(event.location());
return true;
}
@@ -298,24 +218,22 @@ void Slider::OnMouseReleased(const ui::MouseEvent& event) {
}
bool Slider::OnKeyPressed(const ui::KeyEvent& event) {
- if (orientation_ == HORIZONTAL) {
- if (event.key_code() == ui::VKEY_LEFT) {
- SetValueInternal(value_ - keyboard_increment_, VALUE_CHANGED_BY_USER);
- return true;
- } else if (event.key_code() == ui::VKEY_RIGHT) {
- SetValueInternal(value_ + keyboard_increment_, VALUE_CHANGED_BY_USER);
- return true;
- }
- } else {
- if (event.key_code() == ui::VKEY_DOWN) {
- SetValueInternal(value_ - keyboard_increment_, VALUE_CHANGED_BY_USER);
- return true;
- } else if (event.key_code() == ui::VKEY_UP) {
- SetValueInternal(value_ + keyboard_increment_, VALUE_CHANGED_BY_USER);
- return true;
- }
- }
- return false;
+ float new_value = value_;
+ if (event.key_code() == ui::VKEY_LEFT)
+ new_value -= keyboard_increment_;
+ else if (event.key_code() == ui::VKEY_RIGHT)
+ new_value += keyboard_increment_;
+ else
+ return false;
+ SetValueInternal(new_value, VALUE_CHANGED_BY_USER);
+ return true;
+}
+
+void Slider::GetAccessibleState(ui::AXViewState* state) {
+ state->role = ui::AX_ROLE_SLIDER;
+ state->name = accessible_name_;
+ state->value = base::UTF8ToUTF16(
+ base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5)));
}
void Slider::OnFocus() {
@@ -334,7 +252,7 @@ void Slider::OnGestureEvent(ui::GestureEvent* event) {
// an ET_GESTURE_TAP_DOWN event.
case ui::ET_GESTURE_TAP_DOWN:
OnSliderDragStarted();
- PrepareForMove(event->location());
+ PrepareForMove(event->location().x());
// Intentional fall through to next case.
case ui::ET_GESTURE_SCROLL_BEGIN:
case ui::ET_GESTURE_SCROLL_UPDATE:
@@ -352,26 +270,4 @@ void Slider::OnGestureEvent(ui::GestureEvent* event) {
}
}
-void Slider::AnimationProgressed(const gfx::Animation* animation) {
- animating_value_ = animation->CurrentValueBetween(animating_value_, value_);
- SchedulePaint();
-}
-
-void Slider::GetAccessibleState(ui::AXViewState* state) {
- state->role = ui::AX_ROLE_SLIDER;
- state->name = accessible_name_;
- state->value = base::UTF8ToUTF16(
- base::StringPrintf("%d%%", static_cast<int>(value_ * 100 + 0.5)));
-}
-
-void Slider::OnSliderDragStarted() {
- if (listener_)
- listener_->SliderDragStarted(this);
-}
-
-void Slider::OnSliderDragEnded() {
- if (listener_)
- listener_->SliderDragEnded(this);
-}
-
} // namespace views
diff --git a/chromium/ui/views/controls/slider.h b/chromium/ui/views/controls/slider.h
index 3d2090aca47..961f96ddcf4 100644
--- a/chromium/ui/views/controls/slider.h
+++ b/chromium/ui/views/controls/slider.h
@@ -51,20 +51,15 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// Internal class name.
static const char kViewClassName[];
- enum Orientation {
- HORIZONTAL,
- VERTICAL
- };
-
- Slider(SliderListener* listener, Orientation orientation);
+ // Based on the bool |is_material_design|, either a md version or a non-md
+ // version of the slider will be created.
+ static Slider* CreateSlider(bool is_material_design,
+ SliderListener* listener);
~Slider() override;
float value() const { return value_; }
void SetValue(float value);
- // Set the delta used for changing the value via keyboard.
- void SetKeyboardIncrement(float increment);
-
void SetAccessibleName(const base::string16& name);
void set_enable_accessibility_events(bool enabled) {
@@ -74,7 +69,27 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
void set_focus_border_color(SkColor color) { focus_border_color_ = color; }
// Update UI based on control on/off state.
- void UpdateState(bool control_on);
+ virtual void UpdateState(bool control_on) = 0;
+
+ protected:
+ explicit Slider(SliderListener* listener);
+
+ // Returns the current position of the thumb on the slider.
+ float GetAnimatingValue() const;
+
+ // Shows or hides the highlight on the slider thumb. The default
+ // implementation does nothing.
+ virtual void SetHighlighted(bool is_highlighted);
+
+ // Gets the size of the slider's thumb.
+ virtual int GetThumbWidth() = 0;
+
+ // views::View:
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ // gfx::AnimationDelegate:
+ void AnimationProgressed(const gfx::Animation* animation) override;
+ void AnimationEnded(const gfx::Animation* animation) override;
private:
friend class test::SliderTestApi;
@@ -84,7 +99,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// Should be called on the Mouse Down event. Used to calculate relative
// position of the mouse cursor (or the touch point) on the button to
// accurately move the button using the MoveButtonTo() method.
- void PrepareForMove(const gfx::Point& point);
+ void PrepareForMove(const int new_x);
// Moves the button to the specified point and updates the value accordingly.
void MoveButtonTo(const gfx::Point& point);
@@ -97,10 +112,9 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// Notify the listener_, if not NULL, that dragging ended.
void OnSliderDragEnded();
- // views::View overrides:
+ // views::View:
const char* GetClassName() const override;
gfx::Size GetPreferredSize() const override;
- void OnPaint(gfx::Canvas* canvas) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
@@ -109,24 +123,20 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
void OnFocus() override;
void OnBlur() override;
- // ui::EventHandler overrides:
+ // ui::EventHandler:
void OnGestureEvent(ui::GestureEvent* event) override;
- // gfx::AnimationDelegate overrides:
- void AnimationProgressed(const gfx::Animation* animation) override;
-
void set_listener(SliderListener* listener) {
listener_ = listener;
}
SliderListener* listener_;
- Orientation orientation_;
std::unique_ptr<gfx::SlideAnimation> move_animation_;
float value_;
float keyboard_increment_;
- float animating_value_;
+ float initial_animating_value_;
bool value_is_valid_;
base::string16 accessible_name_;
bool accessibility_events_enabled_;
@@ -134,13 +144,7 @@ class VIEWS_EXPORT Slider : public View, public gfx::AnimationDelegate {
// Relative position of the mouse cursor (or the touch point) on the slider's
// button.
- gfx::Point initial_button_offset_;
-
- const int* bar_active_images_;
- const int* bar_disabled_images_;
- const gfx::ImageSkia* thumb_;
- const gfx::ImageSkia* images_[4];
- int bar_height_;
+ int initial_button_offset_;
DISALLOW_COPY_AND_ASSIGN(Slider);
};
diff --git a/chromium/ui/views/controls/slider_unittest.cc b/chromium/ui/views/controls/slider_unittest.cc
index 86b1c045b9d..390d837e0ab 100644
--- a/chromium/ui/views/controls/slider_unittest.cc
+++ b/chromium/ui/views/controls/slider_unittest.cc
@@ -16,8 +16,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/gesture_event_details.h"
+#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/test/slider_test_api.h"
+#include "ui/views/test/test_slider.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -122,7 +124,7 @@ namespace views {
// Base test fixture for Slider tests.
class SliderTest : public views::ViewsTestBase {
public:
- explicit SliderTest(Slider::Orientation orientation);
+ SliderTest();
~SliderTest() override;
protected:
@@ -153,8 +155,6 @@ class SliderTest : public views::ViewsTestBase {
}
private:
- // The Slider's orientation
- Slider::Orientation orientation_;
// The Slider to be tested.
Slider* slider_;
// A simple SliderListener test double.
@@ -174,13 +174,8 @@ class SliderTest : public views::ViewsTestBase {
DISALLOW_COPY_AND_ASSIGN(SliderTest);
};
-SliderTest::SliderTest(Slider::Orientation orientation)
- : orientation_(orientation),
- slider_(NULL),
- default_locale_(""),
- max_x_(0),
- max_y_(0) {
-}
+SliderTest::SliderTest()
+ : slider_(NULL), default_locale_(), max_x_(0), max_y_(0) {}
SliderTest::~SliderTest() {
}
@@ -188,7 +183,7 @@ SliderTest::~SliderTest() {
void SliderTest::SetUp() {
views::ViewsTestBase::SetUp();
- slider_ = new Slider(NULL, orientation_);
+ slider_ = new TestSlider(nullptr);
View* view = slider_;
gfx::Size size = view->GetPreferredSize();
view->SetSize(size);
@@ -234,30 +229,11 @@ class HorizontalSliderTest : public SliderTest {
DISALLOW_COPY_AND_ASSIGN(HorizontalSliderTest);
};
-HorizontalSliderTest::HorizontalSliderTest()
- : SliderTest(Slider::HORIZONTAL) {
-}
+HorizontalSliderTest::HorizontalSliderTest() : SliderTest() {}
HorizontalSliderTest::~HorizontalSliderTest() {
}
-// Test fixture for vertically oriented slider tests.
-class VerticalSliderTest : public SliderTest {
- public:
- VerticalSliderTest();
- ~VerticalSliderTest() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VerticalSliderTest);
-};
-
-VerticalSliderTest::VerticalSliderTest()
- : SliderTest(Slider::VERTICAL) {
-}
-
-VerticalSliderTest::~VerticalSliderTest() {
-}
-
TEST_F(HorizontalSliderTest, UpdateFromClickHorizontal) {
ClickAt(0, 0);
EXPECT_EQ(0.0f, slider()->value());
@@ -266,13 +242,6 @@ TEST_F(HorizontalSliderTest, UpdateFromClickHorizontal) {
EXPECT_EQ(1.0f, slider()->value());
}
-TEST_F(VerticalSliderTest, UpdateFromClickVertical) {
- ClickAt(0, 0);
- EXPECT_EQ(1.0f, slider()->value());
-
- ClickAt(0, max_y());
- EXPECT_EQ(0.0f, slider()->value());
-}
TEST_F(HorizontalSliderTest, UpdateFromClickRTLHorizontal) {
base::i18n::SetICUDefaultLocale("he");
@@ -319,10 +288,8 @@ TEST_F(HorizontalSliderTest, SliderValueForScrollGesture) {
// Scroll above the maximum.
slider()->SetValue(0.5);
event_generator()->GestureScrollSequence(
- gfx::Point(0.5 * max_x(), 0.5 * max_y()),
- gfx::Point(max_x(), max_y()),
- base::TimeDelta::FromMilliseconds(10),
- 5 /* steps */);
+ gfx::Point(0.5 * max_x(), 0.5 * max_y()), gfx::Point(max_x(), max_y()),
+ base::TimeDelta::FromMilliseconds(10), 5 /* steps */);
EXPECT_EQ(1, slider()->value());
// Scroll somewhere in the middle.
@@ -335,6 +302,19 @@ TEST_F(HorizontalSliderTest, SliderValueForScrollGesture) {
EXPECT_NEAR(0.75, slider()->value(), 0.03);
}
+// Test the slider location by adjusting it using keyboard.
+TEST_F(HorizontalSliderTest, SliderValueForKeyboard) {
+ float value =0.5;
+ slider()->SetValue(value);
+ slider()->RequestFocus();
+ event_generator()->PressKey(ui::VKEY_RIGHT, 0);
+ EXPECT_GT(slider()->value(), value);
+
+ slider()->SetValue(value);
+ event_generator()->PressKey(ui::VKEY_LEFT, 0);
+ EXPECT_LT(slider()->value(), value);
+}
+
// Verifies the correct SliderListener events are raised for a tap gesture.
TEST_F(HorizontalSliderTest, SliderListenerEventsForTapGesture) {
test::SliderTestApi slider_test_api(slider());
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 0be0af67873..07fe5a69545 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -10,12 +10,16 @@
#include "third_party/skia/include/core/SkPath.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/default_style.h"
+#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/border.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
+#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_manager.h"
#include "ui/views/widget/widget.h"
@@ -32,6 +36,9 @@ const gfx::Font::Weight kHoverWeight = gfx::Font::Weight::NORMAL;
const gfx::Font::Weight kActiveWeight = gfx::Font::Weight::BOLD;
const gfx::Font::Weight kInactiveWeight = gfx::Font::Weight::NORMAL;
+const int kHarmonyTabStripVerticalPad = 16;
+const int kHarmonyTabStripTabHeight = 40;
+
} // namespace
namespace views {
@@ -62,6 +69,12 @@ class Tab : public View {
void Layout() override;
const char* GetClassName() const override;
+ protected:
+ Label* title() { return title_; }
+
+ // Called whenever |tab_state_| changes.
+ virtual void OnStateChanged();
+
private:
enum TabState {
TAB_INACTIVE,
@@ -81,6 +94,19 @@ class Tab : public View {
DISALLOW_COPY_AND_ASSIGN(Tab);
};
+// A subclass of Tab that implements the Harmony visual styling.
+class MdTab : public Tab {
+ public:
+ MdTab(TabbedPane* tabbed_pane, const base::string16& title, View* contents);
+ ~MdTab() override;
+
+ // Overridden from Tab:
+ void OnStateChanged() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MdTab);
+};
+
// The tab strip shown above the tab contents.
class TabStrip : public View {
public:
@@ -102,6 +128,22 @@ class TabStrip : public View {
DISALLOW_COPY_AND_ASSIGN(TabStrip);
};
+// A subclass of TabStrip that implements the Harmony visual styling. This
+// class uses a BoxLayout to position tabs.
+class MdTabStrip : public TabStrip {
+ public:
+ explicit MdTabStrip(TabbedPane* tabbed_pane);
+ ~MdTabStrip() override;
+
+ // Overridden from View:
+ gfx::Size GetPreferredSize() const override;
+ void Layout() override;
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MdTabStrip);
+};
+
// static
const char Tab::kViewClassName[] = "Tab";
@@ -129,6 +171,27 @@ void Tab::SetSelected(bool selected) {
SetState(selected ? TAB_ACTIVE : TAB_INACTIVE);
}
+void Tab::OnStateChanged() {
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ switch (tab_state_) {
+ case TAB_INACTIVE:
+ title_->SetEnabledColor(kTabTitleColor_Inactive);
+ title_->SetFontList(rb.GetFontListWithDelta(
+ ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kInactiveWeight));
+ break;
+ case TAB_ACTIVE:
+ title_->SetEnabledColor(kTabTitleColor_Active);
+ title_->SetFontList(rb.GetFontListWithDelta(
+ ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kActiveWeight));
+ break;
+ case TAB_HOVERED:
+ title_->SetEnabledColor(kTabTitleColor_Hovered);
+ title_->SetFontList(rb.GetFontListWithDelta(
+ ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kHoverWeight));
+ break;
+ }
+}
+
bool Tab::OnMousePressed(const ui::MouseEvent& event) {
if (event.IsOnlyLeftMouseButton() &&
GetLocalBounds().Contains(event.location()))
@@ -185,26 +248,42 @@ void Tab::SetState(TabState tab_state) {
if (tab_state == tab_state_)
return;
tab_state_ = tab_state;
+ OnStateChanged();
+ SchedulePaint();
+}
+
+MdTab::MdTab(TabbedPane* tabbed_pane,
+ const base::string16& title,
+ View* contents)
+ : Tab(tabbed_pane, title, contents) {
+ OnStateChanged();
+}
+
+MdTab::~MdTab() {}
+
+void MdTab::OnStateChanged() {
+ ui::NativeTheme* theme = GetNativeTheme();
+ SkColor border_color = theme->GetSystemColor(
+ selected() ? ui::NativeTheme::kColorId_FocusedBorderColor
+ : ui::NativeTheme::kColorId_UnfocusedBorderColor);
+ int border_thickness = selected() ? 2 : 1;
+ SetBorder(
+ Border::CreateSolidSidedBorder(0, 0, border_thickness, 0, border_color));
+
+ SkColor font_color = selected()
+ ? theme->GetSystemColor(ui::NativeTheme::kColorId_ProminentButtonColor)
+ : theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonEnabledColor);
+ title()->SetEnabledColor(font_color);
+
+ gfx::Font::Weight font_weight = gfx::Font::Weight::MEDIUM;
+#if defined(OS_WIN)
+ if (selected())
+ font_weight = gfx::Font::Weight::BOLD;
+#endif
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- switch (tab_state) {
- case TAB_INACTIVE:
- title_->SetEnabledColor(kTabTitleColor_Inactive);
- title_->SetFontList(rb.GetFontListWithDelta(
- ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kInactiveWeight));
- break;
- case TAB_ACTIVE:
- title_->SetEnabledColor(kTabTitleColor_Active);
- title_->SetFontList(rb.GetFontListWithDelta(
- ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kActiveWeight));
- break;
- case TAB_HOVERED:
- title_->SetEnabledColor(kTabTitleColor_Hovered);
- title_->SetFontList(rb.GetFontListWithDelta(
- ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kHoverWeight));
- break;
- }
- SchedulePaint();
+ title()->SetFontList(rb.GetFontListWithDelta(ui::kLabelFontSizeDelta,
+ gfx::Font::NORMAL, font_weight));
}
// static
@@ -273,11 +352,40 @@ void TabStrip::OnPaint(gfx::Canvas* canvas) {
}
}
+MdTabStrip::MdTabStrip(TabbedPane* tabbed_pane) : TabStrip(tabbed_pane) {
+ BoxLayout* layout =
+ new BoxLayout(BoxLayout::kHorizontal, 0, kHarmonyTabStripVerticalPad, 0);
+ layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
+ layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
+ layout->SetDefaultFlex(1);
+ SetLayoutManager(layout);
+}
+
+MdTabStrip::~MdTabStrip() {}
+
+gfx::Size MdTabStrip::GetPreferredSize() const {
+ return gfx::Size(width(),
+ kHarmonyTabStripVerticalPad * 2 + kHarmonyTabStripTabHeight);
+}
+
+// Let this class's LayoutManager handle the layout.
+void MdTabStrip::Layout() {
+ return View::Layout();
+}
+
+// The tab strip "border" is drawn as part of the tabs, so all this method needs
+// to do is paint the background.
+void MdTabStrip::OnPaint(gfx::Canvas* canvas) {
+ OnPaintBackground(canvas);
+}
+
TabbedPane::TabbedPane()
- : listener_(NULL),
- tab_strip_(new TabStrip(this)),
- contents_(new View()),
- selected_tab_index_(-1) {
+ : listener_(NULL),
+ tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial()
+ ? new MdTabStrip(this)
+ : new TabStrip(this)),
+ contents_(new View()),
+ selected_tab_index_(-1) {
#if defined(OS_MACOSX)
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
#else
@@ -310,7 +418,11 @@ void TabbedPane::AddTabAtIndex(int index,
DCHECK(index >= 0 && index <= GetTabCount());
contents->SetVisible(false);
- tab_strip_->AddChildViewAt(new Tab(this, title, contents), index);
+ tab_strip_->AddChildViewAt(
+ ui::MaterialDesignController::IsSecondaryUiMaterial()
+ ? new MdTab(this, title, contents)
+ : new Tab(this, title, contents),
+ index);
contents_->AddChildViewAt(contents, index);
if (selected_tab_index() < 0)
SelectTabAt(index);
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
index 76d927ac564..aa808acadcb 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -58,18 +58,18 @@ class VIEWS_EXPORT TabbedPane : public View {
const char* GetClassName() const override;
private:
- friend class TabStrip;
+ friend class TabStrip;
- // Get the Tab (the tabstrip view, not its content) at the valid |index|.
- Tab* GetTabAt(int index);
+ // Get the Tab (the tabstrip view, not its content) at the valid |index|.
+ Tab* GetTabAt(int index);
// Overridden from View:
- void Layout() override;
- void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) override;
- bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
- void OnFocus() override;
- void GetAccessibleState(ui::AXViewState* state) override;
+ void Layout() override;
+ void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) override;
+ bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
+ void OnFocus() override;
+ void GetAccessibleState(ui::AXViewState* state) override;
// A listener notified when tab selection changes. Weak, not owned.
TabbedPaneListener* listener_;
diff --git a/chromium/ui/views/controls/table/table_view.cc b/chromium/ui/views/controls/table/table_view.cc
index 9ef4fe95a81..9ce94cc4519 100644
--- a/chromium/ui/views/controls/table/table_view.cc
+++ b/chromium/ui/views/controls/table/table_view.cc
@@ -234,15 +234,20 @@ void TableView::SetColumnVisibility(int id, bool is_visible) {
void TableView::ToggleSortOrder(int visible_column_index) {
DCHECK(visible_column_index >= 0 &&
visible_column_index < static_cast<int>(visible_columns_.size()));
- if (!visible_columns_[visible_column_index].column.sortable)
+ const ui::TableColumn& column = visible_columns_[visible_column_index].column;
+ if (!column.sortable)
return;
- const int column_id = visible_columns_[visible_column_index].column.id;
SortDescriptors sort(sort_descriptors_);
- if (!sort.empty() && sort[0].column_id == column_id) {
- sort[0].ascending = !sort[0].ascending;
+ if (!sort.empty() && sort[0].column_id == column.id) {
+ if (sort[0].ascending == column.initial_sort_is_ascending) {
+ // First toggle inverts the order.
+ sort[0].ascending = !sort[0].ascending;
+ } else {
+ // Second toggle clears the sort.
+ sort.clear();
+ }
} else {
- SortDescriptor descriptor(column_id, visible_columns_[
- visible_column_index].column.initial_sort_is_ascending);
+ SortDescriptor descriptor(column.id, column.initial_sort_is_ascending);
sort.insert(sort.begin(), descriptor);
// Only persist two sort descriptors.
if (sort.size() > 2)
@@ -251,6 +256,13 @@ void TableView::ToggleSortOrder(int visible_column_index) {
SetSortDescriptors(sort);
}
+void TableView::SetSortDescriptors(const SortDescriptors& sort_descriptors) {
+ sort_descriptors_ = sort_descriptors;
+ SortItemsAndUpdateMapping();
+ if (header_)
+ header_->SchedulePaint();
+}
+
bool TableView::IsColumnVisible(int id) const {
for (size_t i = 0; i < visible_columns_.size(); ++i) {
if (visible_columns_[i].column.id == id)
@@ -640,13 +652,6 @@ void TableView::NumRowsChanged() {
SchedulePaint();
}
-void TableView::SetSortDescriptors(const SortDescriptors& sort_descriptors) {
- sort_descriptors_ = sort_descriptors;
- SortItemsAndUpdateMapping();
- if (header_)
- header_->SchedulePaint();
-}
-
void TableView::SortItemsAndUpdateMapping() {
if (!is_sorted()) {
view_to_model_.clear();
diff --git a/chromium/ui/views/controls/table/table_view.h b/chromium/ui/views/controls/table/table_view.h
index fc7f028164b..3c2e954e737 100644
--- a/chromium/ui/views/controls/table/table_view.h
+++ b/chromium/ui/views/controls/table/table_view.h
@@ -154,10 +154,17 @@ class VIEWS_EXPORT TableView
// Sets the width of the column. |index| is in terms of |visible_columns_|.
void SetVisibleColumnWidth(int index, int width);
- // Toggles the sort order of the specified visible column index.
+ // Modify the table sort order, depending on a clicked column and the previous
+ // table sort order. Does nothing if this column is not sortable.
+ //
+ // When called repeatedly on the same sortable column, the sort order will
+ // cycle through three states in order: sorted -> reverse-sorted -> unsorted.
+ // When switching from one sort column to another, the previous sort column
+ // will be remembered and used as a secondary sort key.
void ToggleSortOrder(int visible_column_index);
const SortDescriptors& sort_descriptors() const { return sort_descriptors_; }
+ void SetSortDescriptors(const SortDescriptors& descriptors);
bool is_sorted() const { return !sort_descriptors_.empty(); }
// Maps from the index in terms of the model to that of the view.
@@ -227,9 +234,6 @@ class VIEWS_EXPORT TableView
// Invoked when the number of rows changes in some way.
void NumRowsChanged();
- // Resets the sort descriptions.
- void SetSortDescriptors(const SortDescriptors& sort_descriptors);
-
// Does the actual sort and updates the mappings (|view_to_model_| and
// |model_to_view_|) appropriately.
void SortItemsAndUpdateMapping();
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index 9fb6bb0fc2d..c94994cd819 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -161,6 +161,29 @@ std::string GetModelToViewAsString(TableView* table) {
return result;
}
+// Formats the whole table as a string, like: "[a, b, c], [d, e, f]". Rows
+// scrolled out of view are included; hidden columns are excluded.
+std::string GetRowsInViewOrderAsString(TableView* table) {
+ std::string result;
+ for (int i = 0; i < table->RowCount(); ++i) {
+ if (i != 0)
+ result += ", "; // Comma between each row.
+
+ // Format row |i| like this: "[value1, value2, value3]"
+ result += "[";
+ for (size_t j = 0; j < table->visible_columns().size(); ++j) {
+ const ui::TableColumn& column = table->visible_columns()[j].column;
+ if (j != 0)
+ result += ", "; // Comma between each value in the row.
+
+ result += base::UTF16ToUTF8(
+ table->model()->GetText(table->ViewToModel(i), column.id));
+ }
+ result += "]";
+ }
+ return result;
+}
+
class TestTableView : public TableView {
public:
TestTableView(ui::TableModel* model,
@@ -335,6 +358,13 @@ TEST_F(TableViewTest, ResizeViaGesture) {
// Assertions for table sorting.
TEST_F(TableViewTest, Sort) {
+ // Initial ordering.
+ EXPECT_TRUE(table_->sort_descriptors().empty());
+ EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
+ EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
+ EXPECT_EQ("[0, 1], [1, 1], [2, 2], [3, 0]",
+ GetRowsInViewOrderAsString(table_));
+
// Toggle the sort order of the first column, shouldn't change anything.
table_->ToggleSortOrder(0);
ASSERT_EQ(1u, table_->sort_descriptors().size());
@@ -342,46 +372,119 @@ TEST_F(TableViewTest, Sort) {
EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
+ EXPECT_EQ("[0, 1], [1, 1], [2, 2], [3, 0]",
+ GetRowsInViewOrderAsString(table_));
- // Invert the sort (first column descending).
+ // Toggle the sort (first column descending).
table_->ToggleSortOrder(0);
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
EXPECT_EQ("3 2 1 0", GetViewToModelAsString(table_));
EXPECT_EQ("3 2 1 0", GetModelToViewAsString(table_));
+ EXPECT_EQ("[3, 0], [2, 2], [1, 1], [0, 1]",
+ GetRowsInViewOrderAsString(table_));
- // Change cell 0x3 to -1, meaning we have 0, 1, 2, -1 (in the first column).
+ // Change the [3, 0] cell to [-1, 0]. This should move it to the back of
+ // the current sort order.
model_->ChangeRow(3, -1, 0);
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
EXPECT_EQ("2 1 0 3", GetViewToModelAsString(table_));
EXPECT_EQ("2 1 0 3", GetModelToViewAsString(table_));
+ EXPECT_EQ("[2, 2], [1, 1], [0, 1], [-1, 0]",
+ GetRowsInViewOrderAsString(table_));
- // Invert sort again (first column ascending).
+ // Toggle the sort again, to clear the sort and restore the model ordering.
+ table_->ToggleSortOrder(0);
+ EXPECT_TRUE(table_->sort_descriptors().empty());
+ EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
+ EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
+ EXPECT_EQ("[0, 1], [1, 1], [2, 2], [-1, 0]",
+ GetRowsInViewOrderAsString(table_));
+
+ // Toggle the sort again (first column ascending).
table_->ToggleSortOrder(0);
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
EXPECT_EQ("3 0 1 2", GetViewToModelAsString(table_));
EXPECT_EQ("1 2 3 0", GetModelToViewAsString(table_));
+ EXPECT_EQ("[-1, 0], [0, 1], [1, 1], [2, 2]",
+ GetRowsInViewOrderAsString(table_));
- // Add a row so that model has 0, 3, 1, 2, -1.
+ // Add a row that's second in the model order, but last in the active sort
+ // order.
model_->AddRow(1, 3, 4);
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
EXPECT_EQ("4 0 2 3 1", GetViewToModelAsString(table_));
EXPECT_EQ("1 4 2 3 0", GetModelToViewAsString(table_));
+ EXPECT_EQ("[-1, 0], [0, 1], [1, 1], [2, 2], [3, 4]",
+ GetRowsInViewOrderAsString(table_));
- // Delete the first row, ending up with 3, 1, 2, -1.
- model_->RemoveRow(0);
+ // Add a row that's last in the model order but second in the the active sort
+ // order.
+ model_->AddRow(5, -1, 20);
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
- EXPECT_EQ("3 1 2 0", GetViewToModelAsString(table_));
- EXPECT_EQ("3 1 2 0", GetModelToViewAsString(table_));
+ EXPECT_EQ("4 5 0 2 3 1", GetViewToModelAsString(table_));
+ EXPECT_EQ("2 5 3 4 0 1", GetModelToViewAsString(table_));
+ EXPECT_EQ("[-1, 0], [-1, 20], [0, 1], [1, 1], [2, 2], [3, 4]",
+ GetRowsInViewOrderAsString(table_));
+
+ // Click the first column again, then click the second column. This should
+ // yield an ordering of second column ascending, with the first column
+ // descending as a tiebreaker.
+ table_->ToggleSortOrder(0);
+ table_->ToggleSortOrder(1);
+ ASSERT_EQ(2u, table_->sort_descriptors().size());
+ EXPECT_EQ(1, table_->sort_descriptors()[0].column_id);
+ EXPECT_TRUE(table_->sort_descriptors()[0].ascending);
+ EXPECT_EQ(0, table_->sort_descriptors()[1].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[1].ascending);
+ EXPECT_EQ("4 2 0 3 1 5", GetViewToModelAsString(table_));
+ EXPECT_EQ("2 4 1 3 0 5", GetModelToViewAsString(table_));
+ EXPECT_EQ("[-1, 0], [1, 1], [0, 1], [2, 2], [3, 4], [-1, 20]",
+ GetRowsInViewOrderAsString(table_));
+
+ // Toggle the current column to change from ascending to descending. This
+ // should result in an almost-reversal of the previous order, except for the
+ // two rows with the same value for the second column.
+ table_->ToggleSortOrder(1);
+ ASSERT_EQ(2u, table_->sort_descriptors().size());
+ EXPECT_EQ(1, table_->sort_descriptors()[0].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
+ EXPECT_EQ(0, table_->sort_descriptors()[1].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[1].ascending);
+ EXPECT_EQ("5 1 3 2 0 4", GetViewToModelAsString(table_));
+ EXPECT_EQ("4 1 3 2 5 0", GetModelToViewAsString(table_));
+ EXPECT_EQ("[-1, 20], [3, 4], [2, 2], [1, 1], [0, 1], [-1, 0]",
+ GetRowsInViewOrderAsString(table_));
+
+ // Delete the [0, 1] row from the model. It's at model index zero.
+ model_->RemoveRow(0);
+ ASSERT_EQ(2u, table_->sort_descriptors().size());
+ EXPECT_EQ(1, table_->sort_descriptors()[0].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[0].ascending);
+ EXPECT_EQ(0, table_->sort_descriptors()[1].column_id);
+ EXPECT_FALSE(table_->sort_descriptors()[1].ascending);
+ EXPECT_EQ("4 0 2 1 3", GetViewToModelAsString(table_));
+ EXPECT_EQ("1 3 2 4 0", GetModelToViewAsString(table_));
+ EXPECT_EQ("[-1, 20], [3, 4], [2, 2], [1, 1], [-1, 0]",
+ GetRowsInViewOrderAsString(table_));
+
+ // Toggle the current sort column again. This should clear both the primary
+ // and secondary sort descriptor.
+ table_->ToggleSortOrder(1);
+ EXPECT_TRUE(table_->sort_descriptors().empty());
+ EXPECT_EQ("0 1 2 3 4", GetViewToModelAsString(table_));
+ EXPECT_EQ("0 1 2 3 4", GetModelToViewAsString(table_));
+ EXPECT_EQ("[3, 4], [1, 1], [2, 2], [-1, 0], [-1, 20]",
+ GetRowsInViewOrderAsString(table_));
}
// Verfies clicking on the header sorts.
@@ -501,7 +604,13 @@ TEST_F(TableViewTest, Grouping) {
EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
- // Toggle to ascending sort.
+ // Toggle to clear the sort.
+ table_->ToggleSortOrder(0);
+ EXPECT_TRUE(table_->sort_descriptors().empty());
+ EXPECT_EQ("0 1 2 3", GetViewToModelAsString(table_));
+ EXPECT_EQ("0 1 2 3", GetModelToViewAsString(table_));
+
+ // Toggle again to effect an ascending sort.
table_->ToggleSortOrder(0);
ASSERT_EQ(1u, table_->sort_descriptors().size());
EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index fa1025ec784..3698349384b 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -17,6 +17,7 @@
#include "ui/base/dragdrop/drag_utils.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_edit_commands.h"
+#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/compositor/canvas_painter.h"
@@ -32,6 +33,7 @@
#include "ui/native_theme/native_theme.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/background.h"
+#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/focusable_border.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/menu/menu_runner.h"
@@ -60,6 +62,18 @@ namespace views {
namespace {
+#if defined(OS_MACOSX)
+const gfx::SelectionBehavior kLineSelectionBehavior = gfx::SELECTION_EXTEND;
+const gfx::SelectionBehavior kWordSelectionBehavior = gfx::SELECTION_CARET;
+const gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
+ gfx::SELECTION_CARET;
+#else
+const gfx::SelectionBehavior kLineSelectionBehavior = gfx::SELECTION_RETAIN;
+const gfx::SelectionBehavior kWordSelectionBehavior = gfx::SELECTION_RETAIN;
+const gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
+ gfx::SELECTION_RETAIN;
+#endif
+
// Default placeholder text color.
const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
@@ -199,6 +213,13 @@ ui::TextEditCommand GetTextEditCommandFromMenuCommand(int command_id,
return ui::TextEditCommand::INVALID_COMMAND;
}
+base::TimeDelta GetPasswordRevealDuration() {
+ return ViewsDelegate::GetInstance()
+ ? ViewsDelegate::GetInstance()
+ ->GetTextfieldPasswordRevealDuration()
+ : base::TimeDelta();
+}
+
} // namespace
// static
@@ -235,7 +256,6 @@ Textfield::Textfield()
text_input_flags_(0),
performing_user_action_(false),
skip_input_method_cancel_composition_(false),
- cursor_visible_(false),
drop_cursor_visible_(false),
initiating_drag_(false),
aggregated_clicks_(0),
@@ -248,12 +268,6 @@ Textfield::Textfield()
SetBorder(std::unique_ptr<Border>(new FocusableBorder()));
SetFocusBehavior(FocusBehavior::ALWAYS);
- if (ViewsDelegate::GetInstance()) {
- password_reveal_duration_ =
- ViewsDelegate::GetInstance()
- ->GetDefaultTextfieldObscuredRevealDuration();
- }
-
// These allow BrowserView to pass edit commands from the Chrome menu to us
// when we're focused by simply asking the FocusManager to
// ProcessAccelerator() with the relevant accelerators.
@@ -310,8 +324,7 @@ void Textfield::InsertOrReplaceText(const base::string16& new_text) {
if (new_text.empty())
return;
model_->InsertText(new_text);
- OnCaretBoundsChanged();
- SchedulePaint();
+ UpdateAfterChange(true, true);
}
base::string16 Textfield::GetSelectedText() const {
@@ -343,7 +356,7 @@ SkColor Textfield::GetTextColor() const {
if (!use_default_text_color_)
return text_color_;
- return GetNativeTheme()->GetSystemColor(read_only() ?
+ return GetNativeTheme()->GetSystemColor(read_only() || !enabled() ?
ui::NativeTheme::kColorId_TextfieldReadOnlyColor :
ui::NativeTheme::kColorId_TextfieldDefaultColor);
}
@@ -363,7 +376,7 @@ SkColor Textfield::GetBackgroundColor() const {
if (!use_default_background_color_)
return background_color_;
- return GetNativeTheme()->GetSystemColor(read_only() ?
+ return GetNativeTheme()->GetSystemColor(read_only() || !enabled() ?
ui::NativeTheme::kColorId_TextfieldReadOnlyBackground :
ui::NativeTheme::kColorId_TextfieldDefaultBackground);
}
@@ -604,12 +617,9 @@ bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
bool Textfield::OnMouseDragged(const ui::MouseEvent& event) {
last_drag_location_ = event.location();
- // Don't adjust the cursor on a potential drag and drop, or if the mouse
- // movement from the last mouse click does not exceed the drag threshold.
- if (initiating_drag_ || !event.IsOnlyLeftMouseButton() ||
- !ExceededDragThreshold(last_drag_location_ - last_click_location_)) {
+ // Don't adjust the cursor on a potential drag and drop.
+ if (initiating_drag_ || !event.IsOnlyLeftMouseButton())
return true;
- }
// A timer is used to continuously scroll while selecting beyond side edges.
const int x = event.location().x();
@@ -639,6 +649,10 @@ void Textfield::OnMouseReleased(const ui::MouseEvent& event) {
OnAfterUserAction();
}
+WordLookupClient* Textfield::GetWordLookupClient() {
+ return this;
+}
+
bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
ui::TextEditCommand edit_command = scheduled_text_edit_command_;
scheduled_text_edit_command_ = ui::TextEditCommand::INVALID_COMMAND;
@@ -674,6 +688,9 @@ bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
ExecuteTextEditCommand(edit_command);
handled = true;
}
+
+ if (!handled)
+ OnKeypressUnhandled();
return handled;
}
@@ -841,6 +858,8 @@ int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
OnCaretBoundsChanged();
SchedulePaint();
+ StopBlinkingCursor();
+
if (initiating_drag_) {
if (in_selection)
return ui::DragDropTypes::DRAG_NONE;
@@ -852,6 +871,8 @@ int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
void Textfield::OnDragExited() {
drop_cursor_visible_ = false;
+ if (ShouldBlinkCursor())
+ StartBlinkingCursor();
SchedulePaint();
}
@@ -963,30 +984,28 @@ void Textfield::OnPaint(gfx::Canvas* canvas) {
void Textfield::OnFocus() {
GetRenderText()->set_focused(true);
- cursor_visible_ = true;
+ if (ShouldShowCursor())
+ GetRenderText()->set_cursor_visible(true);
SchedulePaint();
if (GetInputMethod())
GetInputMethod()->SetFocusedTextInputClient(this);
OnCaretBoundsChanged();
-
- const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
- if (caret_blink_ms != 0) {
- cursor_repaint_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(caret_blink_ms), this,
- &Textfield::UpdateCursor);
- }
-
+ if (ShouldBlinkCursor())
+ StartBlinkingCursor();
View::OnFocus();
SchedulePaint();
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial())
+ FocusRing::Install(this);
}
void Textfield::OnBlur() {
- GetRenderText()->set_focused(false);
+ gfx::RenderText* render_text = GetRenderText();
+ render_text->set_focused(false);
if (GetInputMethod())
GetInputMethod()->DetachTextInputClient(this);
- cursor_repaint_timer_.Stop();
- if (cursor_visible_) {
- cursor_visible_ = false;
+ StopBlinkingCursor();
+ if (render_text->cursor_visible()) {
+ render_text->set_cursor_visible(false);
RepaintCursor();
}
@@ -994,6 +1013,8 @@ void Textfield::OnBlur() {
// Border typically draws focus indicator.
SchedulePaint();
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial())
+ FocusRing::Uninstall(this);
}
gfx::Point Textfield::GetKeyboardContextMenuLocation() {
@@ -1084,6 +1105,16 @@ bool Textfield::CanStartDragForView(View* sender,
}
////////////////////////////////////////////////////////////////////////////////
+// Textfield, WordLookupClient overrides:
+
+bool Textfield::GetDecoratedWordAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) {
+ return GetRenderText()->GetDecoratedWordAtPoint(point, decorated_word,
+ baseline_point);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Textfield, ui::TouchEditable overrides:
void Textfield::SelectRect(const gfx::Point& start, const gfx::Point& end) {
@@ -1179,7 +1210,7 @@ bool Textfield::IsCommandIdEnabled(int command_id) const {
}
bool Textfield::GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) {
+ ui::Accelerator* accelerator) const {
switch (command_id) {
case IDS_APP_UNDO:
*accelerator = ui::Accelerator(ui::VKEY_Z, ui::EF_CONTROL_DOWN);
@@ -1264,6 +1295,11 @@ void Textfield::InsertText(const base::string16& new_text) {
}
void Textfield::InsertChar(const ui::KeyEvent& event) {
+ if (read_only()) {
+ OnKeypressUnhandled();
+ return;
+ }
+
// Filter out all control characters, including tab and new line characters,
// and all characters with Alt modifier (and Search on ChromeOS). But allow
// characters with the AltGr modifier. On Windows AltGr is represented by
@@ -1278,7 +1314,7 @@ void Textfield::InsertChar(const ui::KeyEvent& event) {
DoInsertChar(ch);
if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD &&
- !password_reveal_duration_.is_zero()) {
+ !GetPasswordRevealDuration().is_zero()) {
const size_t change_offset = model_->GetCursorPosition();
DCHECK_GT(change_offset, 0u);
RevealPasswordChar(change_offset - 1);
@@ -1467,6 +1503,8 @@ bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
case ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH:
case ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_WORD_BACKWARD:
case ui::TextEditCommand::MOVE_WORD_BACKWARD_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_WORD_FORWARD:
@@ -1493,6 +1531,8 @@ bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
case ui::TextEditCommand::TRANSPOSE:
return editable && !model_->HasSelection() &&
!model_->HasCompositionText();
+ case ui::TextEditCommand::YANK:
+ return editable;
case ui::TextEditCommand::MOVE_DOWN:
case ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_PAGE_DOWN:
@@ -1501,6 +1541,13 @@ bool Textfield::IsTextEditCommandEnabled(ui::TextEditCommand command) const {
case ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_UP:
case ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION:
+// On Mac, the textfield should respond to Up/Down arrows keys and
+// PageUp/PageDown.
+#if defined(OS_MACOSX)
+ return true;
+#else
+ return false;
+#endif
case ui::TextEditCommand::INSERT_TEXT:
case ui::TextEditCommand::SET_MARK:
case ui::TextEditCommand::UNSELECT:
@@ -1543,21 +1590,24 @@ base::string16 Textfield::GetSelectionClipboardText() const {
void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
DestroyTouchSelection();
+ bool add_to_kill_buffer = false;
+
// Some codepaths may bypass GetCommandForKeyEvent, so any selection-dependent
// modifications of the command should happen here.
- if (HasSelection()) {
- switch (command) {
- case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE:
- case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH:
- case ui::TextEditCommand::DELETE_TO_END_OF_LINE:
- case ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH:
- case ui::TextEditCommand::DELETE_WORD_BACKWARD:
- case ui::TextEditCommand::DELETE_WORD_FORWARD:
+ switch (command) {
+ case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE:
+ case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH:
+ case ui::TextEditCommand::DELETE_TO_END_OF_LINE:
+ case ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH:
+ add_to_kill_buffer = text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD;
+ // Fall through.
+ case ui::TextEditCommand::DELETE_WORD_BACKWARD:
+ case ui::TextEditCommand::DELETE_WORD_FORWARD:
+ if (HasSelection())
command = ui::TextEditCommand::DELETE_FORWARD;
- break;
- default:
- break;
- }
+ break;
+ default:
+ break;
}
// We only execute the commands enabled in Textfield::IsTextEditCommandEnabled
@@ -1575,98 +1625,125 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
OnBeforeUserAction();
switch (command) {
case ui::TextEditCommand::DELETE_BACKWARD:
- text_changed = cursor_changed = model_->Backspace();
+ text_changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_FORWARD:
- text_changed = cursor_changed = model_->Delete();
+ text_changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE:
case ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH:
- model_->MoveCursor(gfx::LINE_BREAK, begin, true);
- text_changed = cursor_changed = model_->Backspace();
+ model_->MoveCursor(gfx::LINE_BREAK, begin, gfx::SELECTION_RETAIN);
+ text_changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_TO_END_OF_LINE:
case ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH:
- model_->MoveCursor(gfx::LINE_BREAK, end, true);
- text_changed = cursor_changed = model_->Delete();
+ model_->MoveCursor(gfx::LINE_BREAK, end, gfx::SELECTION_RETAIN);
+ text_changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_WORD_BACKWARD:
- model_->MoveCursor(gfx::WORD_BREAK, begin, true);
- text_changed = cursor_changed = model_->Backspace();
+ model_->MoveCursor(gfx::WORD_BREAK, begin, gfx::SELECTION_RETAIN);
+ text_changed = cursor_changed = model_->Backspace(add_to_kill_buffer);
break;
case ui::TextEditCommand::DELETE_WORD_FORWARD:
- model_->MoveCursor(gfx::WORD_BREAK, end, true);
- text_changed = cursor_changed = model_->Delete();
+ model_->MoveCursor(gfx::WORD_BREAK, end, gfx::SELECTION_RETAIN);
+ text_changed = cursor_changed = model_->Delete(add_to_kill_buffer);
break;
case ui::TextEditCommand::MOVE_BACKWARD:
- model_->MoveCursor(gfx::CHARACTER_BREAK, begin, false);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, begin, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_BACKWARD_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::CHARACTER_BREAK, begin, true);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, begin, gfx::SELECTION_RETAIN);
break;
case ui::TextEditCommand::MOVE_FORWARD:
- model_->MoveCursor(gfx::CHARACTER_BREAK, end, false);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, end, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_FORWARD_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::CHARACTER_BREAK, end, true);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, end, gfx::SELECTION_RETAIN);
break;
case ui::TextEditCommand::MOVE_LEFT:
- model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_LEFT_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
break;
case ui::TextEditCommand::MOVE_RIGHT:
- model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
break;
case ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT:
case ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE:
case ui::TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH:
- model_->MoveCursor(gfx::LINE_BREAK, begin, false);
+ case ui::TextEditCommand::MOVE_UP:
+ case ui::TextEditCommand::MOVE_PAGE_UP:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::
MOVE_TO_BEGINNING_OF_DOCUMENT_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
case ui::TextEditCommand::
MOVE_TO_BEGINNING_OF_PARAGRAPH_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::LINE_BREAK, begin, true);
+ model_->MoveCursor(gfx::LINE_BREAK, begin, kLineSelectionBehavior);
+ break;
+ case ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, begin, gfx::SELECTION_RETAIN);
break;
case ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT:
case ui::TextEditCommand::MOVE_TO_END_OF_LINE:
case ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH:
- model_->MoveCursor(gfx::LINE_BREAK, end, false);
+ case ui::TextEditCommand::MOVE_DOWN:
+ case ui::TextEditCommand::MOVE_PAGE_DOWN:
+ model_->MoveCursor(gfx::LINE_BREAK, end, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
case ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::LINE_BREAK, end, true);
+ model_->MoveCursor(gfx::LINE_BREAK, end, kLineSelectionBehavior);
+ break;
+ case ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, end, gfx::SELECTION_RETAIN);
+ break;
+ case ui::TextEditCommand::MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, begin,
+ kMoveParagraphSelectionBehavior);
+ break;
+ case ui::TextEditCommand::MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION:
+ model_->MoveCursor(gfx::LINE_BREAK, end, kMoveParagraphSelectionBehavior);
break;
case ui::TextEditCommand::MOVE_WORD_BACKWARD:
- model_->MoveCursor(gfx::WORD_BREAK, begin, false);
+ model_->MoveCursor(gfx::WORD_BREAK, begin, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_WORD_BACKWARD_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::WORD_BREAK, begin, true);
+ model_->MoveCursor(gfx::WORD_BREAK, begin, kWordSelectionBehavior);
break;
case ui::TextEditCommand::MOVE_WORD_FORWARD:
- model_->MoveCursor(gfx::WORD_BREAK, end, false);
+ model_->MoveCursor(gfx::WORD_BREAK, end, gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_WORD_FORWARD_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::WORD_BREAK, end, true);
+ model_->MoveCursor(gfx::WORD_BREAK, end, kWordSelectionBehavior);
break;
case ui::TextEditCommand::MOVE_WORD_LEFT:
- model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT,
+ kWordSelectionBehavior);
break;
case ui::TextEditCommand::MOVE_WORD_RIGHT:
- model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
break;
case ui::TextEditCommand::MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
- model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT,
+ kWordSelectionBehavior);
break;
case ui::TextEditCommand::UNDO:
text_changed = cursor_changed = model_->Undo();
@@ -1689,14 +1766,9 @@ void Textfield::ExecuteTextEditCommand(ui::TextEditCommand command) {
case ui::TextEditCommand::TRANSPOSE:
text_changed = cursor_changed = model_->Transpose();
break;
- case ui::TextEditCommand::MOVE_DOWN:
- case ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION:
- case ui::TextEditCommand::MOVE_PAGE_DOWN:
- case ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION:
- case ui::TextEditCommand::MOVE_PAGE_UP:
- case ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION:
- case ui::TextEditCommand::MOVE_UP:
- case ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION:
+ case ui::TextEditCommand::YANK:
+ text_changed = cursor_changed = model_->Yank();
+ break;
case ui::TextEditCommand::INSERT_TEXT:
case ui::TextEditCommand::SET_MARK:
case ui::TextEditCommand::UNSELECT:
@@ -1724,12 +1796,18 @@ void Textfield::AccessibilitySetValue(const base::string16& new_value) {
void Textfield::UpdateBackgroundColor() {
const SkColor color = GetBackgroundColor();
- set_background(Background::CreateSolidBackground(color));
+ if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
+ set_background(Background::CreateBackgroundPainter(
+ true, Painter::CreateSolidRoundRectPainter(
+ color, FocusableBorder::kCornerRadiusDp)));
+ } else {
+ set_background(Background::CreateSolidBackground(color));
+ }
// Disable subpixel rendering when the background color is transparent
// because it draws incorrect colors around the glyphs in that case.
// See crbug.com/115198
GetRenderText()->set_subpixel_rendering_suppressed(
- SkColorGetA(color) != 0xFF);
+ SkColorGetA(color) != SK_AlphaOPAQUE);
SchedulePaint();
}
@@ -1740,10 +1818,12 @@ void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
}
if (cursor_changed) {
- cursor_visible_ = true;
+ GetRenderText()->set_cursor_visible(ShouldShowCursor());
RepaintCursor();
- if (cursor_repaint_timer_.IsRunning())
- cursor_repaint_timer_.Reset();
+ if (ShouldBlinkCursor())
+ StartBlinkingCursor();
+ else
+ StopBlinkingCursor();
if (!text_changed) {
// TEXT_CHANGED implies TEXT_SELECTION_CHANGED, so we only need to fire
// this if only the selection changed.
@@ -1756,12 +1836,6 @@ void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
}
}
-void Textfield::UpdateCursor() {
- const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
- cursor_visible_ = !cursor_visible_ || (caret_blink_ms == 0);
- RepaintCursor();
-}
-
void Textfield::RepaintCursor() {
gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
r.Inset(-1, -1, -1, -1);
@@ -1776,12 +1850,12 @@ void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) {
gfx::RenderText* render_text = GetRenderText();
if (text().empty() && !GetPlaceholderText().empty()) {
canvas->DrawStringRect(GetPlaceholderText(), GetFontList(),
- placeholder_text_color(), render_text->display_rect());
+ ui::MaterialDesignController::IsSecondaryUiMaterial()
+ ? SkColorSetA(GetTextColor(), 0x83)
+ : placeholder_text_color_,
+ render_text->display_rect());
}
- // Draw the text, cursor, and selection.
- render_text->set_cursor_visible(cursor_visible_ && !drop_cursor_visible_ &&
- !HasSelection());
render_text->Draw(canvas);
// Draw the detached drop cursor that marks where the text will be dropped.
@@ -1802,10 +1876,12 @@ void Textfield::SelectThroughLastDragLocation() {
const bool drags_to_end = PlatformStyle::kTextfieldDragVerticallyDragsToEnd;
if (drags_to_end && last_drag_location_.y() < 0) {
model_->MoveCursor(gfx::BreakType::LINE_BREAK,
- gfx::VisualCursorDirection::CURSOR_LEFT, true);
+ gfx::VisualCursorDirection::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
} else if (drags_to_end && last_drag_location_.y() > height()) {
model_->MoveCursor(gfx::BreakType::LINE_BREAK,
- gfx::VisualCursorDirection::CURSOR_RIGHT, true);
+ gfx::VisualCursorDirection::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
} else {
model_->MoveCursorTo(last_drag_location_, true);
}
@@ -1894,9 +1970,10 @@ void Textfield::UpdateContextMenu() {
if (controller_)
controller_->UpdateContextMenu(context_menu_contents_.get());
}
- context_menu_runner_.reset(
- new MenuRunner(context_menu_contents_.get(),
- MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
+ context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get(),
+ MenuRunner::HAS_MNEMONICS |
+ MenuRunner::CONTEXT_MENU |
+ MenuRunner::ASYNC));
}
void Textfield::TrackMouseClicks(const ui::MouseEvent& event) {
@@ -1928,7 +2005,7 @@ void Textfield::RevealPasswordChar(int index) {
SchedulePaint();
if (index != -1) {
- password_reveal_timer_.Start(FROM_HERE, password_reveal_duration_,
+ password_reveal_timer_.Start(FROM_HERE, GetPasswordRevealDuration(),
base::Bind(&Textfield::RevealPasswordChar,
weak_ptr_factory_.GetWeakPtr(), -1));
}
@@ -1948,7 +2025,8 @@ void Textfield::CreateTouchSelectionControllerAndNotifyIt() {
void Textfield::UpdateSelectionClipboard() const {
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
- if (performing_user_action_ && HasSelection()) {
+ if (performing_user_action_ && HasSelection() &&
+ text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD) {
ui::ScopedClipboardWriter(
ui::CLIPBOARD_TYPE_SELECTION).WriteText(GetSelectedText());
if (controller_)
@@ -1974,4 +2052,35 @@ void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) {
OnAfterUserAction();
}
+void Textfield::OnKeypressUnhandled() {
+ PlatformStyle::OnTextfieldKeypressUnhandled();
+}
+
+bool Textfield::ShouldShowCursor() const {
+ return HasFocus() && !HasSelection() && enabled() && !read_only() &&
+ !drop_cursor_visible_;
+}
+
+bool Textfield::ShouldBlinkCursor() const {
+ return ShouldShowCursor() && Textfield::GetCaretBlinkMs() != 0;
+}
+
+void Textfield::StartBlinkingCursor() {
+ DCHECK(ShouldBlinkCursor());
+ cursor_blink_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(
+ Textfield::GetCaretBlinkMs()),
+ this, &Textfield::OnCursorBlinkTimerFired);
+}
+
+void Textfield::StopBlinkingCursor() {
+ cursor_blink_timer_.Stop();
+}
+
+void Textfield::OnCursorBlinkTimerFired() {
+ DCHECK(ShouldBlinkCursor());
+ gfx::RenderText* render_text = GetRenderText();
+ render_text->set_cursor_visible(!render_text->cursor_visible());
+ RepaintCursor();
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index ac1f0cf6df1..d59a1f9187a 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -30,6 +30,7 @@
#include "ui/views/controls/textfield/textfield_model.h"
#include "ui/views/drag_controller.h"
#include "ui/views/view.h"
+#include "ui/views/word_lookup_client.h"
namespace views {
@@ -42,6 +43,7 @@ class VIEWS_EXPORT Textfield : public View,
public TextfieldModel::Delegate,
public ContextMenuController,
public DragController,
+ public WordLookupClient,
public ui::TouchEditable,
public ui::TextInputClient {
public:
@@ -73,7 +75,8 @@ class VIEWS_EXPORT Textfield : public View,
// features. The flags is the bit map of ui::TextInputFlags.
void SetTextInputFlags(int flags);
- // Gets the text currently displayed in the Textfield.
+ // Gets the text for the Textfield. Call sites should take care to not reveal
+ // the text for a password textfield.
const base::string16& text() const { return model_->text(); }
// Sets the text currently displayed in the Textfield. This doesn't
@@ -86,9 +89,13 @@ class VIEWS_EXPORT Textfield : public View,
void AppendText(const base::string16& new_text);
// Inserts |new_text| at the cursor position, replacing any selected text.
+ // This method is used to handle user input via paths Textfield doesn't
+ // normally handle, so it calls UpdateAfterChange() and notifies observers of
+ // changes.
void InsertOrReplaceText(const base::string16& new_text);
- // Returns the text that is currently selected.
+ // Returns the text that is currently selected. Call sites should take care to
+ // not reveal the text for a password textfield.
base::string16 GetSelectedText() const;
// Select the entire text range. If |reversed| is true, the range will end at
@@ -150,9 +157,8 @@ class VIEWS_EXPORT Textfield : public View,
void set_placeholder_text(const base::string16& text) {
placeholder_text_ = text;
}
- virtual base::string16 GetPlaceholderText() const;
+ base::string16 GetPlaceholderText() const;
- SkColor placeholder_text_color() const { return placeholder_text_color_; }
void set_placeholder_text_color(SkColor color) {
placeholder_text_color_ = color;
}
@@ -212,8 +218,7 @@ class VIEWS_EXPORT Textfield : public View,
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
- bool OnKeyPressed(const ui::KeyEvent& event) override;
- bool OnKeyReleased(const ui::KeyEvent& event) override;
+ WordLookupClient* GetWordLookupClient() override;
void OnGestureEvent(ui::GestureEvent* event) override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
bool CanHandleAccelerators() const override;
@@ -255,6 +260,11 @@ class VIEWS_EXPORT Textfield : public View,
const gfx::Point& press_pt,
const gfx::Point& p) override;
+ // WordLookupClient overrides:
+ bool GetDecoratedWordAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) override;
+
// ui::TouchEditable overrides:
void SelectRect(const gfx::Point& start, const gfx::Point& end) override;
void MoveCaretTo(const gfx::Point& point) override;
@@ -272,7 +282,7 @@ class VIEWS_EXPORT Textfield : public View,
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) override;
+ ui::Accelerator* accelerator) const override;
void ExecuteCommand(int command_id, int event_flags) override;
// ui::TextInputClient overrides:
@@ -323,6 +333,13 @@ class VIEWS_EXPORT Textfield : public View,
private:
friend class TextfieldTestApi;
+ // View overrides:
+ // Declared final since overriding by subclasses would interfere with the
+ // accounting related to the scheduled text edit command. Subclasses should
+ // use TextfieldController::HandleKeyEvent, to intercept the key event.
+ bool OnKeyPressed(const ui::KeyEvent& event) final;
+ bool OnKeyReleased(const ui::KeyEvent& event) final;
+
// Handles a request to change the value of this text field from software
// using an accessibility API (typically automation software, screen readers
// don't normally use this). Sets the value and clears the selection.
@@ -382,12 +399,33 @@ class VIEWS_EXPORT Textfield : public View,
void CreateTouchSelectionControllerAndNotifyIt();
- // Updates the selection clipboard to any non-empty text selection.
+ // Updates the selection clipboard to any non-empty text selection for a non-
+ // password textfield.
void UpdateSelectionClipboard() const;
// Pastes the selection clipboard for the specified mouse event.
void PasteSelectionClipboard(const ui::MouseEvent& event);
+ // Called whenever a keypress is unhandled for any reason, including failing
+ // to insert text into a readonly text field.
+ void OnKeypressUnhandled();
+
+ // Returns true if an insertion cursor should be visible (a vertical bar,
+ // placed at the point new text will be inserted).
+ bool ShouldShowCursor() const;
+
+ // Returns true if an insertion cursor should be visible and blinking.
+ bool ShouldBlinkCursor() const;
+
+ // Starts and stops blinking the cursor, respectively. These are both
+ // idempotent if the cursor is already blinking/not blinking.
+ void StartBlinkingCursor();
+ void StopBlinkingCursor();
+
+ // Callback for the cursor blink timer. Called every
+ // Textfield::GetCaretBlinkMs().
+ void OnCursorBlinkTimerFired();
+
// The text model.
std::unique_ptr<TextfieldModel> model_;
@@ -423,6 +461,7 @@ class VIEWS_EXPORT Textfield : public View,
base::string16 placeholder_text_;
// Placeholder text color.
+ // TODO(estade): remove this when Harmony/MD is default.
SkColor placeholder_text_color_;
// The accessible name of the text field.
@@ -434,8 +473,7 @@ class VIEWS_EXPORT Textfield : public View,
// The input flags of this text field.
int text_input_flags_;
- // The duration and timer to reveal the last typed password character.
- base::TimeDelta password_reveal_duration_;
+ // The timer to reveal the last typed password character.
base::OneShotTimer password_reveal_timer_;
// Tracks whether a user action is being performed; i.e. OnBeforeUserAction()
@@ -445,9 +483,8 @@ class VIEWS_EXPORT Textfield : public View,
// True if InputMethod::CancelComposition() should not be called.
bool skip_input_method_cancel_composition_;
- // The text editing cursor repaint timer and visibility.
- base::RepeatingTimer cursor_repaint_timer_;
- bool cursor_visible_;
+ // Insertion cursor repaint timer and visibility.
+ base::RepeatingTimer cursor_blink_timer_;
// The drop cursor is a visual cue for where dragged text will be dropped.
bool drop_cursor_visible_;
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index 297ea1978cb..dc1bc5539ef 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -263,6 +264,24 @@ gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) {
return gfx::Range::InvalidRange();
}
+// Returns a pointer to the kill buffer which holds the text to be inserted on
+// executing yank command. Singleton since it needs to be persisted across
+// multiple textfields.
+// On Mac, the size of the kill ring (no. of buffers) is controlled by
+// NSTextKillRingSize, a text system default. However to keep things simple,
+// the default kill ring size of 1 (i.e. a single buffer) is assumed.
+base::string16* GetKillBuffer() {
+ CR_DEFINE_STATIC_LOCAL(base::string16, kill_buffer, ());
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+ return &kill_buffer;
+}
+
+// Helper method to set the kill buffer.
+void SetKillBuffer(const base::string16& buffer) {
+ base::string16* kill_buffer = GetKillBuffer();
+ *kill_buffer = buffer;
+}
+
} // namespace
using internal::Edit;
@@ -317,21 +336,26 @@ void TextfieldModel::Append(const base::string16& new_text) {
if (HasCompositionText())
ConfirmCompositionText();
size_t save = GetCursorPosition();
- MoveCursor(gfx::LINE_BREAK,
- render_text_->GetVisualDirectionOfLogicalEnd(),
- false);
+ MoveCursor(gfx::LINE_BREAK, render_text_->GetVisualDirectionOfLogicalEnd(),
+ gfx::SELECTION_NONE);
InsertText(new_text);
render_text_->SetCursorPosition(save);
ClearSelection();
}
-bool TextfieldModel::Delete() {
+bool TextfieldModel::Delete(bool add_to_kill_buffer) {
+ // |add_to_kill_buffer| should never be true for an obscured textfield.
+ DCHECK(!add_to_kill_buffer || !render_text_->obscured());
+
if (HasCompositionText()) {
// No undo/redo for composition text.
CancelCompositionText();
return true;
}
+
if (HasSelection()) {
+ if (add_to_kill_buffer)
+ SetKillBuffer(GetSelectedText());
DeleteSelection();
return true;
}
@@ -339,28 +363,40 @@ bool TextfieldModel::Delete() {
size_t cursor_position = GetCursorPosition();
size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme(
cursor_position, gfx::CURSOR_FORWARD);
- ExecuteAndRecordDelete(gfx::Range(cursor_position, next_grapheme_index),
- true);
+ 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);
return true;
}
return false;
}
-bool TextfieldModel::Backspace() {
+bool TextfieldModel::Backspace(bool add_to_kill_buffer) {
+ // |add_to_kill_buffer| should never be true for an obscured textfield.
+ DCHECK(!add_to_kill_buffer || !render_text_->obscured());
+
if (HasCompositionText()) {
// No undo/redo for composition text.
CancelCompositionText();
return true;
}
+
if (HasSelection()) {
+ if (add_to_kill_buffer)
+ SetKillBuffer(GetSelectedText());
DeleteSelection();
return true;
}
size_t cursor_position = GetCursorPosition();
if (cursor_position > 0) {
// Delete one code point, which may be two UTF-16 words.
- size_t previous_char = gfx::UTF16OffsetToIndex(text(), cursor_position, -1);
- ExecuteAndRecordDelete(gfx::Range(cursor_position, previous_char), true);
+ size_t previous_grapheme_index =
+ gfx::UTF16OffsetToIndex(text(), cursor_position, -1);
+ gfx::Range range_to_delete(cursor_position, previous_grapheme_index);
+ if (add_to_kill_buffer)
+ SetKillBuffer(GetTextFromRange(range_to_delete));
+ ExecuteAndRecordDelete(range_to_delete, true);
return true;
}
return false;
@@ -372,10 +408,10 @@ size_t TextfieldModel::GetCursorPosition() const {
void TextfieldModel::MoveCursor(gfx::BreakType break_type,
gfx::VisualCursorDirection direction,
- bool select) {
+ gfx::SelectionBehavior selection_behavior) {
if (HasCompositionText())
ConfirmCompositionText();
- render_text_->MoveCursor(break_type, direction, select);
+ render_text_->MoveCursor(break_type, direction, selection_behavior);
}
bool TextfieldModel::MoveCursorTo(const gfx::SelectionModel& cursor) {
@@ -402,8 +438,7 @@ bool TextfieldModel::MoveCursorTo(const gfx::Point& point, bool select) {
}
base::string16 TextfieldModel::GetSelectedText() const {
- return text().substr(render_text_->selection().GetMin(),
- render_text_->selection().length());
+ return GetTextFromRange(render_text_->selection());
}
void TextfieldModel::SelectRange(const gfx::Range& range) {
@@ -441,7 +476,7 @@ bool TextfieldModel::CanUndo() {
}
bool TextfieldModel::CanRedo() {
- if (!edit_history_.size())
+ if (edit_history_.empty())
return false;
// There is no redo iff the current edit is the last element in the history.
EditHistory::iterator iter = current_edit_;
@@ -464,7 +499,7 @@ bool TextfieldModel::Undo() {
if (current_edit_ == edit_history_.begin())
current_edit_ = edit_history_.end();
else
- current_edit_--;
+ --current_edit_;
return old != text() || old_cursor != GetCursorPosition();
}
@@ -478,7 +513,7 @@ bool TextfieldModel::Redo() {
if (current_edit_ == edit_history_.end())
current_edit_ = edit_history_.begin();
else
- current_edit_ ++;
+ ++current_edit_;
base::string16 old = text();
size_t old_cursor = GetCursorPosition();
(*current_edit_)->Redo(this);
@@ -557,6 +592,15 @@ bool TextfieldModel::Transpose() {
return true;
}
+bool TextfieldModel::Yank() {
+ const base::string16* kill_buffer = GetKillBuffer();
+ if (!kill_buffer->empty() || HasSelection()) {
+ InsertTextInternal(*kill_buffer, false);
+ return true;
+ }
+ return false;
+}
+
bool TextfieldModel::HasSelection() const {
return !render_text_->selection().is_empty();
}
@@ -580,9 +624,7 @@ void TextfieldModel::DeleteSelectionAndInsertTextAt(
}
base::string16 TextfieldModel::GetTextFromRange(const gfx::Range& range) const {
- if (range.IsValid() && range.GetMin() < text().length())
- return text().substr(range.GetMin(), range.length());
- return base::string16();
+ return render_text_->GetTextFromRange(range);
}
void TextfieldModel::GetTextRange(gfx::Range* range) const {
@@ -668,7 +710,7 @@ bool TextfieldModel::HasCompositionText() const {
}
void TextfieldModel::ClearEditHistory() {
- STLDeleteElements(&edit_history_);
+ base::STLDeleteElements(&edit_history_);
current_edit_ = edit_history_.end();
}
@@ -716,8 +758,8 @@ void TextfieldModel::ClearRedoHistory() {
return;
}
EditHistory::iterator delete_start = current_edit_;
- delete_start++;
- STLDeleteContainerPointers(delete_start, edit_history_.end());
+ ++delete_start;
+ base::STLDeleteContainerPointers(delete_start, edit_history_.end());
edit_history_.erase(delete_start, edit_history_.end());
}
@@ -789,7 +831,7 @@ bool TextfieldModel::AddOrMergeEditHistory(Edit* edit) {
DCHECK_EQ(1u, edit_history_.size());
current_edit_ = edit_history_.begin();
} else {
- current_edit_++;
+ ++current_edit_;
}
return false;
}
@@ -810,4 +852,9 @@ void TextfieldModel::ModifyText(size_t delete_from,
// TODO(oshima): Select text that was just undone, like Mac (but not GTK).
}
+// static
+void TextfieldModel::ClearKillBuffer() {
+ SetKillBuffer(base::string16());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/textfield/textfield_model.h b/chromium/ui/views/controls/textfield/textfield_model.h
index df3e9754e2d..c66fe6d0680 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.h
+++ b/chromium/ui/views/controls/textfield/textfield_model.h
@@ -37,6 +37,10 @@ enum MergeType {
} // namespace internal
+namespace test {
+class BridgedNativeWidgetTest;
+} // namsespace test
+
// A model that represents text content for a views::Textfield.
// It supports editing, selection and cursor manipulation.
class VIEWS_EXPORT TextfieldModel {
@@ -95,15 +99,17 @@ class VIEWS_EXPORT TextfieldModel {
// Deletes the first character after the current cursor position (as if, the
// the user has pressed delete key in the textfield). Returns true if
- // the deletion is successful.
+ // the deletion is successful. If |add_to_kill_buffer| is true, the deleted
+ // text is copied to the kill buffer.
// If there is composition text, it'll be deleted instead.
- bool Delete();
+ bool Delete(bool add_to_kill_buffer = false);
// Deletes the first character before the current cursor position (as if, the
// the user has pressed backspace key in the textfield). Returns true if
- // the removal is successful.
+ // the removal is successful. If |add_to_kill_buffer| is true, the deleted
+ // text is copied to the kill buffer.
// If there is composition text, it'll be deleted instead.
- bool Backspace();
+ bool Backspace(bool add_to_kill_buffer = false);
// Cursor related methods.
@@ -114,7 +120,7 @@ class VIEWS_EXPORT TextfieldModel {
// The current composition text will be confirmed.
void MoveCursor(gfx::BreakType break_type,
gfx::VisualCursorDirection direction,
- bool select);
+ gfx::SelectionBehavior selection_behavior);
// Updates the cursor to the specified selection model. Any composition text
// will be confirmed, which may alter the specified selection range start.
@@ -182,6 +188,10 @@ class VIEWS_EXPORT TextfieldModel {
// changed.
bool Transpose();
+ // Pastes text from the kill buffer at the current cursor position. Returns
+ // true if the text has changed after yanking.
+ bool Yank();
+
// Tells if any text is selected, even if the selection is in composition
// text.
bool HasSelection() const;
@@ -225,6 +235,9 @@ class VIEWS_EXPORT TextfieldModel {
private:
friend class internal::Edit;
+ friend class test::BridgedNativeWidgetTest;
+ friend class TextfieldModelTest;
+ friend class TextfieldTest;
FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_BasicTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldModelTest, UndoRedo_CutCopyPasteTest);
@@ -269,6 +282,9 @@ class VIEWS_EXPORT TextfieldModel {
void ClearComposition();
+ // Clears the kill buffer. Used to clear global state between tests.
+ static void ClearKillBuffer();
+
// The TextfieldModel::Delegate instance should be provided by the owner.
Delegate* delegate_;
diff --git a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
index 36638168130..be0a344f5a3 100644
--- a/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model_unittest.cc
@@ -55,6 +55,14 @@ class TextfieldModelTest : public ViewsTestBase,
composition_text_confirmed_or_cleared_(false) {
}
+ // ::testing::Test:
+ void TearDown() override {
+ // Clear kill buffer used for "Yank" text editing command so that no state
+ // persists between tests.
+ TextfieldModel::ClearKillBuffer();
+ ViewsTestBase::TearDown();
+ }
+
void OnCompositionTextConfirmedOrCleared() override {
composition_text_confirmed_or_cleared_ = true;
}
@@ -80,7 +88,8 @@ TEST_F(TextfieldModelTest, EditString) {
EXPECT_STR_EQ("HILLWORLD", model.text());
// Insert "E" and replace "I" with "L" to make "HELLO".
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
model.InsertChar('E');
EXPECT_STR_EQ("HEILLWORLD", model.text());
model.ReplaceChar('L');
@@ -98,11 +107,11 @@ TEST_F(TextfieldModelTest, EditString) {
EXPECT_STR_EQ("HELLORLD", model.text());
// Move the cursor to start; backspace should fail.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_FALSE(model.Backspace());
EXPECT_STR_EQ("HELLORLD", model.text());
// Move the cursor to the end; delete should fail, but backspace should work.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_FALSE(model.Delete());
EXPECT_STR_EQ("HELLORLD", model.text());
EXPECT_TRUE(model.Backspace());
@@ -233,7 +242,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"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ 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"),
model.text());
@@ -244,9 +253,11 @@ TEST_F(TextfieldModelTest, EmptyString) {
EXPECT_EQ(base::string16(), model.text());
EXPECT_EQ(base::string16(), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(0U, model.GetCursorPosition());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_EQ(base::string16(), model.GetSelectedText());
@@ -258,15 +269,18 @@ TEST_F(TextfieldModelTest, EmptyString) {
TEST_F(TextfieldModelTest, Selection) {
TextfieldModel model(NULL);
model.Append(base::ASCIIToUTF16("HELLO"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("E", model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("EL", model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("H", model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("ELLO", model.GetSelectedText());
model.ClearSelection();
EXPECT_EQ(base::string16(), model.GetSelectedText());
@@ -284,18 +298,20 @@ TEST_F(TextfieldModelTest, Selection) {
// Select and move cursor.
model.SelectRange(gfx::Range(1U, 3U));
EXPECT_STR_EQ("EL", model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_EQ(1U, model.GetCursorPosition());
model.SelectRange(gfx::Range(1U, 3U));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
EXPECT_EQ(3U, model.GetCursorPosition());
// Select all and move cursor.
model.SelectAll(false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_EQ(0U, model.GetCursorPosition());
model.SelectAll(false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
EXPECT_EQ(5U, model.GetCursorPosition());
}
@@ -312,23 +328,29 @@ TEST_F(TextfieldModelTest, Selection_BidiWithNonSpacingMarks) {
#if defined(OS_LINUX)
model.Append(base::WideToUTF16(
L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
EXPECT_EQ(base::WideToUTF16(L"c"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(gfx::Range(2, 7), model.render_text()->selection());
EXPECT_EQ(base::WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"),
model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection());
EXPECT_EQ(base::WideToUTF16(L"c"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(gfx::Range(2, 10), model.render_text()->selection());
EXPECT_EQ(base::WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"d"),
model.GetSelectedText());
@@ -345,36 +367,49 @@ TEST_F(TextfieldModelTest, Selection_BidiWithNonSpacingMarks) {
// an RTL character.
model.SetText(base::WideToUTF16(L"a\x05E9" L"b"));
MoveCursorTo(model, 0);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"a"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"a"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
EXPECT_EQ(3U, model.GetCursorPosition());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"b"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"b"), model.GetSelectedText());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"a\x05E9"), model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
EXPECT_EQ(base::WideToUTF16(L"\x05E9" L"b"), model.GetSelectedText());
model.ClearSelection();
@@ -386,28 +421,37 @@ TEST_F(TextfieldModelTest, Selection_BidiWithNonSpacingMarks) {
TEST_F(TextfieldModelTest, SelectionAndEdit) {
TextfieldModel model(NULL);
model.Append(base::ASCIIToUTF16("HELLO"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL"
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN); // "EL"
EXPECT_TRUE(model.Backspace());
EXPECT_STR_EQ("HLO", model.text());
model.Append(base::ASCIIToUTF16("ILL"));
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO"
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN); // "LO"
EXPECT_TRUE(model.Delete());
EXPECT_STR_EQ("HILL", model.text());
EXPECT_EQ(1U, model.GetCursorPosition());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I"
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN); // "I"
model.InsertChar('E');
EXPECT_STR_EQ("HELL", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H"
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN); // "H"
model.ReplaceChar('B');
EXPECT_STR_EQ("BELL", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL"
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN); // "ELL"
model.ReplaceChar('E');
EXPECT_STR_EQ("BEE", model.text());
}
@@ -416,43 +460,45 @@ TEST_F(TextfieldModelTest, Word) {
TextfieldModel model(NULL);
model.Append(
base::ASCIIToUTF16("The answer to Life, the Universe, and Everything"));
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(3U, model.GetCursorPosition());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(10U, model.GetCursorPosition());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(18U, model.GetCursorPosition());
// Should passes the non word char ','
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
EXPECT_EQ(23U, model.GetCursorPosition());
EXPECT_STR_EQ(", the", model.GetSelectedText());
// Move to the end.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
// Should be safe to go next word at the end.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
model.InsertChar('2');
EXPECT_EQ(19U, model.GetCursorPosition());
// Now backwards.
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); // leave 2.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_NONE); // leave 2.
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
EXPECT_EQ(14U, model.GetCursorPosition());
EXPECT_STR_EQ("Life", model.GetSelectedText());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("to Life", model.GetSelectedText());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); // Now at start.
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN); // Now at start.
EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
// Should be safe to go to the previous word at the beginning.
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
model.ReplaceChar('4');
EXPECT_EQ(base::string16(), model.GetSelectedText());
@@ -462,14 +508,14 @@ TEST_F(TextfieldModelTest, Word) {
TEST_F(TextfieldModelTest, SetText) {
TextfieldModel model(NULL);
model.Append(base::ASCIIToUTF16("HELLO"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.SetText(base::ASCIIToUTF16("GOODBYE"));
EXPECT_STR_EQ("GOODBYE", model.text());
// SetText move the cursor to the end of the new text.
EXPECT_EQ(7U, model.GetCursorPosition());
model.SelectAll(false);
EXPECT_STR_EQ("GOODBYE", model.GetSelectedText());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(7U, model.GetCursorPosition());
model.SetText(base::ASCIIToUTF16("BYE"));
@@ -492,7 +538,7 @@ TEST_F(TextfieldModelTest, Clipboard) {
model.Append(base::ASCIIToUTF16("HELLO WORLD"));
// Cut with an empty selection should do nothing.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_FALSE(model.Cut());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_EQ(initial_clipboard_text, clipboard_text);
@@ -525,8 +571,8 @@ TEST_F(TextfieldModelTest, Clipboard) {
// Cut with non-empty selection.
model.render_text()->SetObscured(false);
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
EXPECT_TRUE(model.Cut());
clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text);
EXPECT_STR_EQ("WORLD", clipboard_text);
@@ -543,7 +589,7 @@ TEST_F(TextfieldModelTest, Clipboard) {
// Test that paste works regardless of the obscured bit. Please note that
// trailing spaces and tabs in clipboard strings will be stripped.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_TRUE(model.Paste());
EXPECT_STR_EQ("HELLO HELLO", model.text());
EXPECT_EQ(11U, model.GetCursorPosition());
@@ -566,7 +612,7 @@ TEST_F(TextfieldModelTest, SelectWordTest) {
model.Append(base::ASCIIToUTF16(" HELLO !! WO RLD "));
// Test when cursor is at the beginning.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
model.SelectWord();
SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 2U);
@@ -593,7 +639,7 @@ TEST_F(TextfieldModelTest, SelectWordTest) {
SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 20U);
// Test when cursor is at the end.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.SelectWord();
SelectWordTestVerifier(model, base::ASCIIToUTF16(" "), 24U);
}
@@ -623,9 +669,10 @@ TEST_F(TextfieldModelTest, SelectWordTest_MixScripts) {
model.SetText(base::WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 "
L"\x4E2D\x56FD\x82B1\x5929"));
for (size_t i = 0; i < word_and_cursor.size(); ++i) {
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
for (size_t j = 0; j < i; ++j)
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
model.SelectWord();
SelectWordTestVerifier(model, base::WideToUTF16(word_and_cursor[i].word),
word_and_cursor[i].cursor);
@@ -636,60 +683,62 @@ TEST_F(TextfieldModelTest, SelectWordTest_MixScripts) {
TEST_F(TextfieldModelTest, RangeTest) {
TextfieldModel model(NULL);
model.Append(base::ASCIIToUTF16("HELLO WORLD"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
gfx::Range range = model.render_text()->selection();
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(0U, range.end());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_FALSE(range.is_empty());
EXPECT_FALSE(range.is_reversed());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(5U, range.end());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_FALSE(range.is_empty());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(4U, range.end());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(0U, range.end());
// now from the end.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
range = model.render_text()->selection();
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(11U, range.end());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_FALSE(range.is_empty());
EXPECT_TRUE(range.is_reversed());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(6U, range.end());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_FALSE(range.is_empty());
EXPECT_TRUE(range.is_reversed());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(7U, range.end());
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(11U, range.end());
// Select All
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
range = model.render_text()->selection();
EXPECT_FALSE(range.is_empty());
EXPECT_TRUE(range.is_reversed());
@@ -744,41 +793,43 @@ TEST_F(TextfieldModelTest, SelectRangeTest) {
TEST_F(TextfieldModelTest, SelectionTest) {
TextfieldModel model(NULL);
model.Append(base::ASCIIToUTF16("HELLO WORLD"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
gfx::Range selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(0), selection);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(0, 5), selection);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(0, 4), selection);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(0), selection);
// now from the end.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(11), selection);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(11, 6), selection);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(11, 7), selection);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(11), selection);
// Select All
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
selection = model.render_text()->selection();
EXPECT_EQ(gfx::Range(11, 0), selection);
}
@@ -874,7 +925,7 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
EXPECT_TRUE(model.SetText(base::ASCIIToUTF16("1234567890")));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.SetCompositionText(composition);
EXPECT_STR_EQ("1234567890678", model.text());
@@ -886,7 +937,8 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
EXPECT_FALSE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT,
+ gfx::SELECTION_RETAIN);
EXPECT_STR_EQ("-", model.GetSelectedText());
model.SetCompositionText(composition);
EXPECT_STR_EQ("1234567890678", model.text());
@@ -918,39 +970,40 @@ TEST_F(TextfieldModelTest, CompositionTextTest) {
model.SetText(base::string16());
model.SetCompositionText(composition);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("678", model.text());
EXPECT_EQ(2U, model.GetCursorPosition());
model.SetCompositionText(composition);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("676788", model.text());
EXPECT_EQ(6U, model.GetCursorPosition());
model.SetCompositionText(composition);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("676788678", model.text());
model.SetText(base::string16());
model.SetCompositionText(composition);
- model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
model.SetCompositionText(composition);
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_RETAIN);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("678678", model.text());
model.SetCompositionText(composition);
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
EXPECT_STR_EQ("678", model.text());
@@ -1065,7 +1118,7 @@ TEST_F(TextfieldModelTest, UndoRedo_BasicTest) {
MoveCursorTo(model, 2);
EXPECT_TRUE(model.Delete());
EXPECT_STR_EQ("ABDE", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
EXPECT_TRUE(model.Delete());
EXPECT_STR_EQ("BDE", model.text());
EXPECT_TRUE(model.Undo());
@@ -1161,7 +1214,7 @@ TEST_F(TextfieldModelTest, UndoRedo_BackspaceThenSetText) {
EXPECT_EQ(14U, model.GetCursorPosition());
EXPECT_STR_EQ("www.google.com", model.text());
model.SetText(base::ASCIIToUTF16("www.google.com")); // Confirm the text.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(14U, model.GetCursorPosition());
EXPECT_TRUE(model.Backspace());
EXPECT_TRUE(model.Backspace());
@@ -1249,7 +1302,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
EXPECT_EQ(1U, model.GetCursorPosition());
model.SelectRange(gfx::Range(1, 1));
EXPECT_FALSE(model.Cut());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_TRUE(model.Paste());
EXPECT_STR_EQ("ABCBCDEBC", model.text());
EXPECT_EQ(9U, model.GetCursorPosition());
@@ -1303,7 +1356,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
model.SelectRange(gfx::Range(1, 3));
model.Copy();
EXPECT_STR_EQ("1232345", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_TRUE(model.Paste());
EXPECT_STR_EQ("123234523", model.text());
EXPECT_EQ(9U, model.GetCursorPosition());
@@ -1315,8 +1368,9 @@ TEST_F(TextfieldModelTest, UndoRedo_CutCopyPasteTest) {
TEST_F(TextfieldModelTest, UndoRedo_CursorTest) {
TextfieldModel model(NULL);
model.InsertChar('a');
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
- model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
+ model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT,
+ gfx::SELECTION_NONE);
model.InsertChar('b');
// Moving the cursor shouldn't create a new edit.
EXPECT_STR_EQ("ab", model.text());
@@ -1418,7 +1472,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
composition.selection = gfx::Range(2, 3);
model.SetText(base::ASCIIToUTF16("ABCDE"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
model.InsertChar('x');
EXPECT_STR_EQ("ABCDEx", model.text());
EXPECT_TRUE(model.Undo()); // set composition should forget undone edit.
@@ -1441,7 +1495,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
EXPECT_FALSE(model.Redo());
// Cancel the composition.
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, gfx::SELECTION_NONE);
model.SetCompositionText(composition);
EXPECT_STR_EQ("abcABCDEabc", model.text());
model.CancelCompositionText();
@@ -1457,7 +1511,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
// Call SetText with the same text as the result.
ResetModel(&model);
model.SetText(base::ASCIIToUTF16("ABCDE"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ 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"));
@@ -1471,7 +1525,7 @@ TEST_F(TextfieldModelTest, UndoRedo_CompositionText) {
// Call SetText with a different result; the composition should be forgotten.
ResetModel(&model);
model.SetText(base::ASCIIToUTF16("ABCDE"));
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ 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"));
@@ -1498,7 +1552,7 @@ TEST_F(TextfieldModelTest, Clipboard_WhiteSpaceStringTest) {
TextfieldModel model(NULL);
model.Append(base::ASCIIToUTF16("HELLO WORLD"));
EXPECT_STR_EQ("HELLO WORLD", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(11U, model.GetCursorPosition());
EXPECT_TRUE(model.Paste());
@@ -1516,7 +1570,7 @@ TEST_F(TextfieldModelTest, Clipboard_WhiteSpaceStringTest) {
model.Append(base::ASCIIToUTF16("HELLO WORLD"));
EXPECT_STR_EQ("HELLO WORLD", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(11U, model.GetCursorPosition());
EXPECT_TRUE(model.Paste());
EXPECT_STR_EQ("HELLO WORLDB", model.text());
@@ -1533,7 +1587,7 @@ TEST_F(TextfieldModelTest, Clipboard_WhiteSpaceStringTest) {
model.Append(base::ASCIIToUTF16("HELLO WORLD"));
EXPECT_STR_EQ("HELLO WORLD", model.text());
- model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false);
+ model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, gfx::SELECTION_NONE);
EXPECT_EQ(11U, model.GetCursorPosition());
EXPECT_TRUE(model.Paste());
EXPECT_STR_EQ("HELLO WORLDFOO BAR", model.text());
@@ -1653,4 +1707,52 @@ TEST_F(TextfieldModelTest, Transpose) {
}
}
+TEST_F(TextfieldModelTest, Yank) {
+ TextfieldModel model(nullptr);
+ model.SetText(base::ASCIIToUTF16("abcde"));
+ model.SelectRange(gfx::Range(1, 3));
+
+ // Delete selection but don't add to kill buffer.
+ model.Delete(false);
+ EXPECT_STR_EQ("ade", model.text());
+
+ // Since the kill buffer is empty, yank should cause no change.
+ model.Yank();
+ EXPECT_STR_EQ("ade", model.text());
+
+ // Delete selection and add to kill buffer.
+ model.SelectRange(gfx::Range(0, 1));
+ model.Delete(true);
+ EXPECT_STR_EQ("de", model.text());
+
+ // Yank twice.
+ model.Yank();
+ model.Yank();
+ EXPECT_STR_EQ("aade", 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());
+
+ // Backspace twice but don't add to kill buffer.
+ model.Backspace(false);
+ model.Backspace(false);
+ EXPECT_STR_EQ("aad", model.text());
+
+ // Ensure kill buffer is not modified.
+ model.Yank();
+ EXPECT_STR_EQ("aada", model.text());
+
+ // Backspace twice, each time modifying the kill buffer.
+ model.Backspace(true);
+ model.Backspace(true);
+ EXPECT_STR_EQ("aa", model.text());
+
+ // Ensure yanking inserts the modified kill buffer text.
+ model.Yank();
+ EXPECT_STR_EQ("aad", model.text());
+}
+
} // 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 4505b712907..f488f2cfefc 100644
--- a/chromium/ui/views/controls/textfield/textfield_test_api.h
+++ b/chromium/ui/views/controls/textfield/textfield_test_api.h
@@ -25,6 +25,10 @@ class TextfieldTestApi {
TextfieldModel* model() const { return textfield_->model_.get(); }
+ void ExecuteTextEditCommand(ui::TextEditCommand command) {
+ textfield_->ExecuteTextEditCommand(command);
+ }
+
ui::MenuModel* context_menu_contents() const {
return textfield_->context_menu_contents_.get();
}
@@ -33,6 +37,14 @@ class TextfieldTestApi {
return textfield_->touch_selection_controller_.get();
}
+ ui::TextEditCommand scheduled_text_edit_command() const {
+ return textfield_->scheduled_text_edit_command_;
+ }
+
+ bool IsCursorBlinkTimerRunning() const {
+ return textfield_->cursor_blink_timer_.IsRunning();
+ }
+
private:
Textfield* textfield_;
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index c6e4fba368c..4786bf1ed8b 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -27,6 +27,7 @@
#include "ui/base/ime/input_method_base.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/input_method_factory.h"
+#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/ui_base_switches_util.h"
@@ -35,6 +36,7 @@
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
+#include "ui/events/test/keyboard_layout.h"
#include "ui/gfx/render_text.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/textfield/textfield_controller.h"
@@ -82,8 +84,6 @@ class MockInputMethod : public ui::InputMethodBase {
void OnTextInputTypeChanged(const ui::TextInputClient* client) override;
void OnCaretBoundsChanged(const ui::TextInputClient* client) override {}
void CancelComposition(const ui::TextInputClient* client) override;
- void OnInputLocaleChanged() override {}
- std::string GetInputLocale() override;
bool IsCandidatePopupOpen() const override;
void ShowImeIfNeeded() override {}
@@ -210,10 +210,6 @@ void MockInputMethod::CancelComposition(const ui::TextInputClient* client) {
}
}
-std::string MockInputMethod::GetInputLocale() {
- return "en-US";
-}
-
bool MockInputMethod::IsCandidatePopupOpen() const {
return false;
}
@@ -265,29 +261,6 @@ class TestTextfield : public views::Textfield {
key_received_(false),
weak_ptr_factory_(this) {}
- bool OnKeyPressed(const ui::KeyEvent& e) override {
- key_received_ = true;
-
- // Since OnKeyPressed() might destroy |this|, get a weak pointer and
- // verify it isn't null before writing the bool value to key_handled_.
- base::WeakPtr<TestTextfield> textfield(weak_ptr_factory_.GetWeakPtr());
- bool key = views::Textfield::OnKeyPressed(e);
-
- if (!textfield)
- return key;
-
- key_handled_ = key;
-
- return key_handled_;
- }
-
- bool OnKeyReleased(const ui::KeyEvent& e) override {
- key_received_ = true;
- key_handled_ = views::Textfield::OnKeyReleased(e);
- EXPECT_FALSE(key_handled_); // Textfield doesn't override OnKeyReleased.
- return key_handled_;
- }
-
// ui::TextInputClient overrides:
void InsertChar(const ui::KeyEvent& e) override {
views::Textfield::InsertChar(e);
@@ -304,6 +277,25 @@ class TestTextfield : public views::Textfield {
void clear() { key_received_ = key_handled_ = false; }
private:
+ // views::View override:
+ void OnKeyEvent(ui::KeyEvent* event) override {
+ key_received_ = true;
+
+ // Since Textfield::OnKeyPressed() might destroy |this|, get a weak pointer
+ // and verify it isn't null before writing the bool value to key_handled_.
+ base::WeakPtr<TestTextfield> textfield(weak_ptr_factory_.GetWeakPtr());
+ views::View::OnKeyEvent(event);
+
+ if (!textfield)
+ return;
+
+ key_handled_ = event->handled();
+
+ // Currently, Textfield::OnKeyReleased always returns false.
+ if (event->type() == ui::ET_KEY_RELEASED)
+ EXPECT_FALSE(key_handled_);
+ }
+
bool key_handled_;
bool key_received_;
@@ -378,6 +370,9 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
void TearDown() override {
if (widget_)
widget_->Close();
+ // Clear kill buffer used for "Yank" text editing command so that no state
+ // persists between tests.
+ TextfieldModel::ClearKillBuffer();
ViewsTestBase::TearDown();
}
@@ -765,7 +760,19 @@ TEST_F(TextfieldTest, KeyTest) {
EXPECT_STR_EQ("TexT!1!1", textfield_->text());
}
-TEST_F(TextfieldTest, KeysWithModifiersTest) {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_KeysWithModifiersTest KeysWithModifiersTest
+#else
+// TODO(crbug.com/645104): Implement keyboard layout changing for other
+// platforms.
+#define MAYBE_KeysWithModifiersTest DISABLED_KeysWithModifiersTest
+#endif
+
+TEST_F(TextfieldTest, MAYBE_KeysWithModifiersTest) {
+ // Activate U.S. English keyboard layout. Modifier keys in other layouts may
+ // change the text inserted into a texfield and cause this test to fail.
+ ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
+
InitTextfield();
const int ctrl = ui::EF_CONTROL_DOWN;
const int alt = ui::EF_ALT_DOWN;
@@ -829,7 +836,212 @@ TEST_F(TextfieldTest, ControlAndSelectTest) {
SendEndEvent(true);
EXPECT_STR_EQ("two three", textfield_->GetSelectedText());
SendHomeEvent(true);
+
+// On Mac, the existing selection should be extended.
+#if defined(OS_MACOSX)
+ EXPECT_STR_EQ("ZERO two three", textfield_->GetSelectedText());
+#else
EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText());
+#endif
+}
+
+TEST_F(TextfieldTest, WordSelection) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("12 34567 89"));
+
+ // Place the cursor after "5".
+ textfield_->SetSelectionRange(gfx::Range(6));
+
+ // Select word towards right.
+ SendWordEvent(ui::VKEY_RIGHT, true);
+ EXPECT_STR_EQ("67", textfield_->GetSelectedText());
+ SendWordEvent(ui::VKEY_RIGHT, true);
+ EXPECT_STR_EQ("67 89", textfield_->GetSelectedText());
+
+ // Select word towards left.
+ SendWordEvent(ui::VKEY_LEFT, true);
+ EXPECT_STR_EQ("67 ", textfield_->GetSelectedText());
+ SendWordEvent(ui::VKEY_LEFT, true);
+
+// On Mac, the selection should reduce to a caret when the selection direction
+// changes for a word selection.
+#if defined(OS_MACOSX)
+ EXPECT_EQ(gfx::Range(6), textfield_->GetSelectedRange());
+#else
+ EXPECT_STR_EQ("345", textfield_->GetSelectedText());
+ EXPECT_EQ(gfx::Range(6, 3), textfield_->GetSelectedRange());
+#endif
+
+ SendWordEvent(ui::VKEY_LEFT, true);
+#if defined(OS_MACOSX)
+ EXPECT_STR_EQ("345", textfield_->GetSelectedText());
+#else
+ EXPECT_STR_EQ("12 345", textfield_->GetSelectedText());
+#endif
+ EXPECT_TRUE(textfield_->GetSelectedRange().is_reversed());
+
+ SendWordEvent(ui::VKEY_LEFT, true);
+ EXPECT_STR_EQ("12 345", textfield_->GetSelectedText());
+}
+
+TEST_F(TextfieldTest, LineSelection) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("12 34567 89"));
+
+ // Place the cursor after "5".
+ textfield_->SetSelectionRange(gfx::Range(6));
+
+ // Select line towards right.
+ SendEndEvent(true);
+ EXPECT_STR_EQ("67 89", textfield_->GetSelectedText());
+
+ // Select line towards left. On Mac, the existing selection should be extended
+ // to cover the whole line.
+ SendHomeEvent(true);
+#if defined(OS_MACOSX)
+ EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
+#else
+ EXPECT_STR_EQ("12 345", textfield_->GetSelectedText());
+#endif
+ EXPECT_TRUE(textfield_->GetSelectedRange().is_reversed());
+
+ // Select line towards right.
+ SendEndEvent(true);
+#if defined(OS_MACOSX)
+ EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText());
+#else
+ EXPECT_STR_EQ("67 89", textfield_->GetSelectedText());
+#endif
+ EXPECT_FALSE(textfield_->GetSelectedRange().is_reversed());
+}
+
+TEST_F(TextfieldTest, MoveUpDownAndModifySelection) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("12 34567 89"));
+ textfield_->SetSelectionRange(gfx::Range(6));
+
+ // Up/Down keys won't be handled except on Mac where they map to move
+ // commands.
+ SendKeyEvent(ui::VKEY_UP);
+ EXPECT_TRUE(textfield_->key_received());
+#if defined(OS_MACOSX)
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_EQ(gfx::Range(0), textfield_->GetSelectedRange());
+#else
+ EXPECT_FALSE(textfield_->key_handled());
+#endif
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_DOWN);
+ EXPECT_TRUE(textfield_->key_received());
+#if defined(OS_MACOSX)
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_EQ(gfx::Range(11), textfield_->GetSelectedRange());
+#else
+ EXPECT_FALSE(textfield_->key_handled());
+#endif
+ textfield_->clear();
+
+ textfield_->SetSelectionRange(gfx::Range(6));
+
+ // Shift+[Up/Down] on Mac should execute the command
+ // MOVE_[UP/DOWN]_AND_MODIFY_SELECTION. On other platforms, textfield won't
+ // handle these events.
+ SendKeyEvent(ui::VKEY_UP, true /* shift */, false /* command */);
+ EXPECT_TRUE(textfield_->key_received());
+#if defined(OS_MACOSX)
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange());
+#else
+ EXPECT_FALSE(textfield_->key_handled());
+#endif
+ textfield_->clear();
+
+ SendKeyEvent(ui::VKEY_DOWN, true /* shift */, false /* command */);
+ EXPECT_TRUE(textfield_->key_received());
+#if defined(OS_MACOSX)
+ EXPECT_TRUE(textfield_->key_handled());
+ EXPECT_EQ(gfx::Range(6, 11), textfield_->GetSelectedRange());
+#else
+ EXPECT_FALSE(textfield_->key_handled());
+#endif
+ textfield_->clear();
+}
+
+TEST_F(TextfieldTest, MovePageUpDownAndModifySelection) {
+ InitTextfield();
+
+// MOVE_PAGE_[UP/DOWN] and the associated selection commands should only be
+// enabled on Mac.
+#if defined(OS_MACOSX)
+ textfield_->SetText(ASCIIToUTF16("12 34567 89"));
+ textfield_->SetSelectionRange(gfx::Range(6));
+
+ EXPECT_TRUE(
+ textfield_->IsTextEditCommandEnabled(ui::TextEditCommand::MOVE_PAGE_UP));
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_DOWN));
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION));
+ EXPECT_TRUE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION));
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_PAGE_UP);
+ EXPECT_EQ(gfx::Range(0), textfield_->GetSelectedRange());
+
+ test_api_->ExecuteTextEditCommand(ui::TextEditCommand::MOVE_PAGE_DOWN);
+ EXPECT_EQ(gfx::Range(11), textfield_->GetSelectedRange());
+
+ textfield_->SetSelectionRange(gfx::Range(6));
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION);
+ EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange());
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION);
+ EXPECT_EQ(gfx::Range(6, 11), textfield_->GetSelectedRange());
+#else
+ EXPECT_FALSE(
+ textfield_->IsTextEditCommandEnabled(ui::TextEditCommand::MOVE_PAGE_UP));
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_DOWN));
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION));
+ EXPECT_FALSE(textfield_->IsTextEditCommandEnabled(
+ ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION));
+#endif
+}
+
+TEST_F(TextfieldTest, MoveParagraphForwardBackwardAndModifySelection) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("12 34567 89"));
+ textfield_->SetSelectionRange(gfx::Range(6));
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION);
+ EXPECT_EQ(gfx::Range(6, 11), textfield_->GetSelectedRange());
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION);
+// On Mac, the selection should reduce to a caret when the selection direction
+// is reversed for MOVE_PARAGRAPH_[FORWARD/BACKWARD]_AND_MODIFY_SELECTION.
+#if defined(OS_MACOSX)
+ EXPECT_EQ(gfx::Range(6), textfield_->GetSelectedRange());
+#else
+ EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange());
+#endif
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION);
+ EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange());
+
+ test_api_->ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION);
+#if defined(OS_MACOSX)
+ EXPECT_EQ(gfx::Range(6), textfield_->GetSelectedRange());
+#else
+ EXPECT_EQ(gfx::Range(6, 11), textfield_->GetSelectedRange());
+#endif
}
TEST_F(TextfieldTest, InsertionDeletionTest) {
@@ -1049,26 +1261,6 @@ TEST_F(TextfieldTest, OnKeyPress) {
#endif
EXPECT_FALSE(textfield_->key_handled());
textfield_->clear();
-
- // Up/Down keys won't be handled except on Mac where they map to move
- // commands.
- SendKeyEvent(ui::VKEY_UP);
- EXPECT_TRUE(textfield_->key_received());
-#if defined(OS_MACOSX)
- EXPECT_TRUE(textfield_->key_handled());
-#else
- EXPECT_FALSE(textfield_->key_handled());
-#endif
- textfield_->clear();
-
- SendKeyEvent(ui::VKEY_DOWN);
- EXPECT_TRUE(textfield_->key_received());
-#if defined(OS_MACOSX)
- EXPECT_TRUE(textfield_->key_handled());
-#else
- EXPECT_FALSE(textfield_->key_handled());
-#endif
- textfield_->clear();
}
// Tests that default key bindings are handled even with a delegate installed.
@@ -1838,8 +2030,9 @@ TEST_F(TextfieldTest, UndoRedoTest) {
}
// Most platforms support Ctrl+Y as an alternative to Ctrl+Shift+Z, but on Mac
-// that is bound to "Show full history", so is not mapped as an editing
-// command. So, on Mac, send Cmd+Shift+Z.
+// Ctrl+Y is bound to "Yank" and Cmd+Y is bound to "Show full history". So, on
+// Mac, Cmd+Shift+Z is sent for the tests above and the Ctrl+Y test below is
+// skipped.
#if !defined(OS_MACOSX)
// Test that Ctrl+Y works for Redo, as well as Ctrl+Shift+Z.
@@ -1859,6 +2052,69 @@ TEST_F(TextfieldTest, RedoWithCtrlY) {
#endif // !defined(OS_MACOSX)
+// Non-Mac platforms don't have a key binding for Yank. Since this test is only
+// run on Mac, it uses some Mac specific key bindings.
+#if defined(OS_MACOSX)
+
+TEST_F(TextfieldTest, Yank) {
+ InitTextfields(2);
+ textfield_->SetText(ASCIIToUTF16("abcdef"));
+ textfield_->SelectRange(gfx::Range(2, 4));
+
+ // Press Ctrl+Y to yank.
+ SendKeyPress(ui::VKEY_Y, ui::EF_CONTROL_DOWN);
+
+ // Initially the kill buffer should be empty. Hence yanking should delete the
+ // selected text.
+ EXPECT_STR_EQ("abef", textfield_->text());
+ EXPECT_EQ(gfx::Range(2), textfield_->GetSelectedRange());
+
+ // Press Ctrl+K to delete to end of paragraph. This should place the deleted
+ // text in the kill buffer.
+ SendKeyPress(ui::VKEY_K, ui::EF_CONTROL_DOWN);
+
+ EXPECT_STR_EQ("ab", textfield_->text());
+ EXPECT_EQ(gfx::Range(2), textfield_->GetSelectedRange());
+
+ // Yank twice.
+ SendKeyPress(ui::VKEY_Y, ui::EF_CONTROL_DOWN);
+ SendKeyPress(ui::VKEY_Y, ui::EF_CONTROL_DOWN);
+ EXPECT_STR_EQ("abefef", textfield_->text());
+ EXPECT_EQ(gfx::Range(6), textfield_->GetSelectedRange());
+
+ // Verify pressing backspace does not modify the kill buffer.
+ SendKeyEvent(ui::VKEY_BACK);
+ SendKeyPress(ui::VKEY_Y, ui::EF_CONTROL_DOWN);
+ EXPECT_STR_EQ("abefeef", textfield_->text());
+ EXPECT_EQ(gfx::Range(7), textfield_->GetSelectedRange());
+
+ // Move focus to next textfield.
+ widget_->GetFocusManager()->AdvanceFocus(false);
+ EXPECT_EQ(2, GetFocusedView()->id());
+ Textfield* textfield2 = static_cast<Textfield*>(GetFocusedView());
+ EXPECT_TRUE(textfield2->text().empty());
+
+ // Verify yanked text persists across multiple textfields and that yanking
+ // into a password textfield works.
+ textfield2->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ SendKeyPress(ui::VKEY_Y, ui::EF_CONTROL_DOWN);
+ EXPECT_STR_EQ("ef", textfield2->text());
+ EXPECT_EQ(gfx::Range(2), textfield2->GetSelectedRange());
+
+ // Verify deletion in a password textfield does not modify the kill buffer.
+ textfield2->SetText(ASCIIToUTF16("hello"));
+ textfield2->SelectRange(gfx::Range(0));
+ SendKeyPress(ui::VKEY_K, ui::EF_CONTROL_DOWN);
+ EXPECT_TRUE(textfield2->text().empty());
+
+ textfield_->RequestFocus();
+ textfield_->SelectRange(gfx::Range(0));
+ SendKeyPress(ui::VKEY_Y, ui::EF_CONTROL_DOWN);
+ EXPECT_STR_EQ("efabefeef", textfield_->text());
+}
+
+#endif // defined(OS_MACOSX)
+
TEST_F(TextfieldTest, CutCopyPaste) {
InitTextfield();
@@ -2490,6 +2746,46 @@ TEST_F(TextfieldTest, DISABLED_SelectionClipboard) {
EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
}
+
+// Verify that the selection clipboard is not updated for selections on a
+// password textfield. Disabled due to http://crbug.com/396477.
+TEST_F(TextfieldTest, DISABLED_SelectionClipboard_Password) {
+ InitTextfields(2);
+ textfield_->SetText(ASCIIToUTF16("abcd"));
+
+ // Select-all should update the selection clipboard for a non-password
+ // textfield.
+ SendKeyEvent(ui::VKEY_A, false, true);
+ EXPECT_EQ(gfx::Range(0, 4), textfield_->GetSelectedRange());
+ EXPECT_STR_EQ("abcd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard());
+
+ // Move focus to the next textfield.
+ widget_->GetFocusManager()->AdvanceFocus(false);
+ EXPECT_EQ(2, GetFocusedView()->id());
+ Textfield* textfield2 = static_cast<Textfield*>(GetFocusedView());
+
+ // Select-all should not modify the selection clipboard for a password
+ // textfield.
+ textfield2->SetText(ASCIIToUTF16("1234"));
+ textfield2->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
+ SendKeyEvent(ui::VKEY_A, false, true);
+ EXPECT_EQ(gfx::Range(0, 4), textfield2->GetSelectedRange());
+ EXPECT_STR_EQ("abcd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+
+ // Shift-Left/Right should not modify the selection clipboard for a password
+ // textfield.
+ SendKeyEvent(ui::VKEY_LEFT, true, false);
+ EXPECT_EQ(gfx::Range(0, 3), textfield2->GetSelectedRange());
+ EXPECT_STR_EQ("abcd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+
+ SendKeyEvent(ui::VKEY_RIGHT, true, false);
+ EXPECT_EQ(gfx::Range(0, 4), textfield2->GetSelectedRange());
+ EXPECT_STR_EQ("abcd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION));
+ EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard());
+}
#endif
// Long_Press gesture in Textfield can initiate a drag and drop now.
@@ -2544,6 +2840,16 @@ TEST_F(TextfieldTest, DestroyingTextfieldFromOnKeyEvent) {
EXPECT_FALSE(controller.target());
}
+TEST_F(TextfieldTest, CursorBlinkRestartsOnInsertOrReplace) {
+ InitTextfield();
+ textfield_->SetText(ASCIIToUTF16("abc"));
+ EXPECT_TRUE(test_api_->IsCursorBlinkTimerRunning());
+ textfield_->SelectRange(gfx::Range(1, 2));
+ EXPECT_FALSE(test_api_->IsCursorBlinkTimerRunning());
+ textfield_->InsertOrReplaceText(base::ASCIIToUTF16("foo"));
+ EXPECT_TRUE(test_api_->IsCursorBlinkTimerRunning());
+}
+
class TextfieldTouchSelectionTest : public TextfieldTest {
protected:
// Simulates a complete tap.
diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc
index 8a10bbdcef7..a87875e7870 100644
--- a/chromium/ui/views/controls/tree/tree_view.cc
+++ b/chromium/ui/views/controls/tree/tree_view.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/i18n/rtl.h"
+#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/ime/input_method.h"
@@ -25,6 +26,7 @@
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/tree/tree_view_controller.h"
#include "ui/views/resources/grit/views_resources.h"
+#include "ui/views/style/platform_style.h"
using ui::TreeModel;
using ui::TreeModelNode;
@@ -68,6 +70,12 @@ ui::NativeTheme::ColorId text_color_id(bool has_focus, bool is_selected) {
return ui::NativeTheme::kColorId_TreeText;
}
+bool EventIsDoubleTapOrClick(const ui::LocatedEvent& event) {
+ if (event.type() == ui::ET_GESTURE_TAP)
+ return event.AsGestureEvent()->details().tap_count() == 2;
+ return !!(event.flags() & ui::EF_IS_DOUBLE_CLICK);
+}
+
} // namespace
TreeView::TreeView()
@@ -129,7 +137,7 @@ void TreeView::SetModel(TreeModel* model) {
model_->AddObserver(this);
model_->GetIcons(&icons_);
- root_.RemoveAll();
+ root_.DeleteAll();
ConfigureInternalNode(model_->GetRoot(), &root_);
LoadChildren(&root_);
root_.set_is_expanded(true);
@@ -243,7 +251,7 @@ void TreeView::SetSelectedNode(TreeModelNode* model_node) {
}
if (selected_node_)
- ScrollRectToVisible(GetBoundsForNode(selected_node_));
+ ScrollRectToVisible(GetForegroundBoundsForNode(selected_node_));
// Notify controller if the old selection was empty to handle the case of
// remove explicitly resetting selected_node_ before invoking this.
@@ -392,13 +400,7 @@ void TreeView::ShowContextMenu(const gfx::Point& p,
// ContextMenuController) if over a node.
gfx::Point local_point(p);
ConvertPointFromScreen(this, &local_point);
- int row = (local_point.y() - kVerticalInset) / row_height_;
- int depth = 0;
- InternalNode* node = GetNodeByRow(row, &depth);
- if (!node)
- return;
- gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
- if (!bounds.Contains(local_point))
+ if (!GetNodeAtPoint(local_point))
return;
}
View::ShowContextMenu(p, source_type);
@@ -428,9 +430,9 @@ void TreeView::TreeNodesAdded(TreeModel* model,
if (!parent_node || !parent_node->loaded_children())
return;
for (int i = 0; i < count; ++i) {
- InternalNode* child = new InternalNode;
- ConfigureInternalNode(model_->GetChild(parent, start + i), child);
- parent_node->Add(child, start + i);
+ std::unique_ptr<InternalNode> child = base::MakeUnique<InternalNode>();
+ ConfigureInternalNode(model_->GetChild(parent, start + i), child.get());
+ parent_node->Add(std::move(child), start + i);
}
if (IsExpanded(parent))
DrawnNodesChanged();
@@ -449,7 +451,7 @@ void TreeView::TreeNodesRemoved(TreeModel* model,
InternalNode* child_removing = parent_node->GetChild(start);
if (selected_node_ && selected_node_->HasAncestor(child_removing))
reset_selection = true;
- delete parent_node->Remove(child_removing);
+ parent_node->Remove(child_removing);
}
if (reset_selection) {
// selected_node_ is no longer valid (at the time we enter this function
@@ -536,7 +538,7 @@ base::string16 TreeView::GetTextForRow(int row) {
gfx::Point TreeView::GetKeyboardContextMenuLocation() {
int y = height() / 2;
if (selected_node_) {
- gfx::Rect node_bounds(GetBoundsForNode(selected_node_));
+ gfx::Rect node_bounds(GetForegroundBoundsForNode(selected_node_));
gfx::Rect vis_bounds(GetVisibleBounds());
if (node_bounds.y() >= vis_bounds.y() &&
node_bounds.y() < vis_bounds.bottom()) {
@@ -643,39 +645,19 @@ bool TreeView::OnClickOrTap(const ui::LocatedEvent& event) {
CommitEdit();
RequestFocus();
- int row = (event.y() - kVerticalInset) / row_height_;
- int depth = 0;
- InternalNode* node = GetNodeByRow(row, &depth);
- if (node) {
- gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
- if (bounds.Contains(event.location())) {
- int relative_x = event.x() - bounds.x();
- if (base::i18n::IsRTL())
- relative_x = bounds.width() - relative_x;
- if (relative_x < kArrowRegionSize &&
- model_->GetChildCount(node->model_node())) {
- if (node->is_expanded())
- Collapse(node->model_node());
- else
- Expand(node->model_node());
- } else if (relative_x > kArrowRegionSize) {
- SetSelectedNode(node->model_node());
- bool should_toggle = false;
- if (event.type() == ui::ET_GESTURE_TAP) {
- const ui::GestureEvent& gesture =
- static_cast<const ui::GestureEvent&>(event);
- should_toggle = gesture.details().tap_count() == 2;
- } else {
- should_toggle = (event.flags() & ui::EF_IS_DOUBLE_CLICK) != 0;
- }
- if (should_toggle) {
- if (node->is_expanded())
- Collapse(node->model_node());
- else
- Expand(node->model_node());
- }
- }
- }
+ InternalNode* node = GetNodeAtPoint(event.location());
+ if (!node)
+ return true;
+
+ bool hits_arrow = IsPointInExpandControl(node, event.location());
+ if (!hits_arrow)
+ SetSelectedNode(node->model_node());
+
+ if (hits_arrow || EventIsDoubleTapOrClick(event)) {
+ if (node->is_expanded())
+ Collapse(node->model_node());
+ else
+ Expand(node->model_node());
}
return true;
}
@@ -686,9 +668,9 @@ void TreeView::LoadChildren(InternalNode* node) {
node->set_loaded_children(true);
for (int i = 0, child_count = model_->GetChildCount(node->model_node());
i < child_count; ++i) {
- InternalNode* child = new InternalNode;
- ConfigureInternalNode(model_->GetChild(node->model_node(), i), child);
- node->Add(child, node->child_count());
+ std::unique_ptr<InternalNode> child = base::MakeUnique<InternalNode>();
+ ConfigureInternalNode(model_->GetChild(node->model_node(), i), child.get());
+ node->Add(std::move(child), node->child_count());
}
}
@@ -728,7 +710,7 @@ void TreeView::LayoutEditor() {
DCHECK(selected_node_);
// Position the editor so that its text aligns with the text we drew.
- gfx::Rect row_bounds = GetBoundsForNode(selected_node_);
+ gfx::Rect row_bounds = GetForegroundBoundsForNode(selected_node_);
row_bounds.set_x(
GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width()));
row_bounds.set_x(row_bounds.x() + text_offset_);
@@ -745,7 +727,7 @@ void TreeView::LayoutEditor() {
void TreeView::SchedulePaintForNode(InternalNode* node) {
if (!node)
return; // Explicitly allow NULL to be passed in.
- SchedulePaintInRect(GetBoundsForNode(node));
+ SchedulePaintInRect(GetBackgroundBoundsForNode(node));
}
void TreeView::PaintRows(gfx::Canvas* canvas,
@@ -771,7 +753,15 @@ void TreeView::PaintRow(gfx::Canvas* canvas,
InternalNode* node,
int row,
int depth) {
- gfx::Rect bounds(GetBoundsForNodeImpl(node, row, depth));
+ gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth));
+ const SkColor selected_row_bg_color = GetNativeTheme()->GetSystemColor(
+ text_background_color_id(HasFocus() || editing_));
+
+ // Paint the row background.
+ if (PlatformStyle::kTreeViewSelectionPaintsEntireRow &&
+ selected_node_ == node) {
+ canvas->FillRect(GetBackgroundBoundsForNode(node), selected_row_bg_color);
+ }
if (model_->GetChildCount(node->model_node()))
PaintExpandControl(canvas, bounds, node->is_expanded());
@@ -795,29 +785,34 @@ void TreeView::PaintRow(gfx::Canvas* canvas,
icon, icon_x,
bounds.y() + (bounds.height() - icon.height()) / 2);
- if (!editing_ || node != selected_node_) {
- gfx::Rect text_bounds(bounds.x() + text_offset_, bounds.y(),
- bounds.width() - text_offset_, bounds.height());
- if (base::i18n::IsRTL())
- text_bounds.set_x(bounds.x());
- if (node == selected_node_) {
- const SkColor bg_color = GetNativeTheme()->GetSystemColor(
- text_background_color_id(HasFocus()));
- canvas->FillRect(text_bounds, bg_color);
- if (HasFocus())
- canvas->DrawFocusRect(text_bounds);
- }
- const ui::NativeTheme::ColorId color_id =
- text_color_id(HasFocus(), node == selected_node_);
- const gfx::Rect internal_bounds(
- text_bounds.x() + kTextHorizontalPadding,
- text_bounds.y() + kTextVerticalPadding,
- text_bounds.width() - kTextHorizontalPadding * 2,
- text_bounds.height() - kTextVerticalPadding * 2);
- canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_,
- GetNativeTheme()->GetSystemColor(color_id),
- internal_bounds);
+ // Paint the text background and text. In edit mode, the selected node is a
+ // separate editing control, so it does not need to be painted here.
+ if (editing_ && selected_node_ == node)
+ return;
+
+ gfx::Rect text_bounds(GetTextBoundsForNode(node));
+ if (base::i18n::IsRTL())
+ text_bounds.set_x(bounds.x());
+
+ // Paint the background on the selected row.
+ if (!PlatformStyle::kTreeViewSelectionPaintsEntireRow &&
+ node == selected_node_) {
+ canvas->FillRect(text_bounds, selected_row_bg_color);
+ if (HasFocus())
+ canvas->DrawFocusRect(text_bounds);
}
+
+ // Paint the text.
+ const ui::NativeTheme::ColorId color_id =
+ text_color_id(HasFocus(), node == selected_node_);
+ const gfx::Rect internal_bounds(
+ text_bounds.x() + kTextHorizontalPadding,
+ text_bounds.y() + kTextVerticalPadding,
+ text_bounds.width() - kTextHorizontalPadding * 2,
+ text_bounds.height() - kTextVerticalPadding * 2);
+ canvas->DrawStringRect(node->model_node()->GetTitle(), font_list_,
+ GetNativeTheme()->GetSystemColor(color_id),
+ internal_bounds);
}
void TreeView::PaintExpandControl(gfx::Canvas* canvas,
@@ -868,15 +863,31 @@ TreeView::InternalNode* TreeView::GetInternalNodeForModelNode(
model_->GetIndexOf(parent_internal_node->model_node(), model_node));
}
-gfx::Rect TreeView::GetBoundsForNode(InternalNode* node) {
+gfx::Rect TreeView::GetBackgroundBoundsForNode(InternalNode* node) {
+ if (!PlatformStyle::kTreeViewSelectionPaintsEntireRow)
+ return GetForegroundBoundsForNode(node);
+
+ int row, ignored_depth;
+ row = GetRowForInternalNode(node, &ignored_depth);
+ return gfx::Rect(bounds().x(), row * row_height_ + kVerticalInset,
+ bounds().width(), row_height_);
+}
+
+gfx::Rect TreeView::GetForegroundBoundsForNode(InternalNode* node) {
int row, depth;
row = GetRowForInternalNode(node, &depth);
- return GetBoundsForNodeImpl(node, row, depth);
+ return GetForegroundBoundsForNodeImpl(node, row, depth);
}
-gfx::Rect TreeView::GetBoundsForNodeImpl(InternalNode* node,
- int row,
- int depth) {
+gfx::Rect TreeView::GetTextBoundsForNode(InternalNode* node) {
+ gfx::Rect bounds(GetForegroundBoundsForNode(node));
+ bounds.Inset(text_offset_, 0, 0, 0);
+ return bounds;
+}
+
+gfx::Rect TreeView::GetForegroundBoundsForNodeImpl(InternalNode* node,
+ int row,
+ int depth) {
gfx::Rect rect(depth * kIndent + kHorizontalInset,
row * row_height_ + kVerticalInset,
text_offset_ + node->text_width() +
@@ -906,6 +917,21 @@ int TreeView::GetRowForInternalNode(InternalNode* node, int* depth) {
return row;
}
+TreeView::InternalNode* TreeView::GetNodeAtPoint(const gfx::Point& point) {
+ int row = (point.y() - kVerticalInset) / row_height_;
+ int depth = -1;
+ InternalNode* node = GetNodeByRow(row, &depth);
+ if (!node)
+ return nullptr;
+
+ // If the entire row gets a selected background, clicking anywhere in the row
+ // serves to hit this node.
+ if (PlatformStyle::kTreeViewSelectionPaintsEntireRow)
+ return node;
+ gfx::Rect bounds(GetForegroundBoundsForNodeImpl(node, row, depth));
+ return bounds.Contains(point) ? node : nullptr;
+}
+
TreeView::InternalNode* TreeView::GetNodeByRow(int row, int* depth) {
int current_row = root_row();
*depth = 0;
@@ -1010,10 +1036,27 @@ bool TreeView::ExpandImpl(TreeModelNode* model_node) {
PrefixSelector* TreeView::GetPrefixSelector() {
if (!selector_)
- selector_.reset(new PrefixSelector(this));
+ selector_.reset(new PrefixSelector(this, this));
return selector_.get();
}
+bool TreeView::IsPointInExpandControl(InternalNode* node,
+ const gfx::Point& point) {
+ if (!model_->GetChildCount(node->model_node()))
+ return false;
+
+ int depth = -1;
+ int row = GetRowForInternalNode(node, &depth);
+
+ int arrow_dx = depth * kIndent + kHorizontalInset;
+ gfx::Rect arrow_bounds(bounds().x() + arrow_dx,
+ row * row_height_ + kVerticalInset, kArrowRegionSize,
+ row_height_);
+ if (base::i18n::IsRTL())
+ arrow_bounds.set_x(bounds().width() - arrow_dx - kArrowRegionSize);
+ return arrow_bounds.Contains(point);
+}
+
// InternalNode ----------------------------------------------------------------
TreeView::InternalNode::InternalNode()
diff --git a/chromium/ui/views/controls/tree/tree_view.h b/chromium/ui/views/controls/tree/tree_view.h
index 2dc764e7f56..5eb096e3d2f 100644
--- a/chromium/ui/views/controls/tree/tree_view.h
+++ b/chromium/ui/views/controls/tree/tree_view.h
@@ -35,7 +35,8 @@ class PrefixSelector;
// Note on implementation. This implementation doesn't scale well. In particular
// it does not store any row information, but instead calculates it as
// necessary. But it's more than adequate for current uses.
-class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
+class VIEWS_EXPORT TreeView : public View,
+ public ui::TreeModelObserver,
public TextfieldController,
public FocusChangeListener,
public PrefixDelegate {
@@ -294,16 +295,29 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
ui::TreeModelNode* model_node,
GetInternalNodeCreateType create_type);
- // Returns the bounds for a node.
- gfx::Rect GetBoundsForNode(InternalNode* node);
+ // Returns the bounds for a node's background.
+ gfx::Rect GetBackgroundBoundsForNode(InternalNode* node);
- // Implementation of GetBoundsForNode. Separated out as some callers already
- // know the row/depth.
- gfx::Rect GetBoundsForNodeImpl(InternalNode* node, int row, int depth);
+ // Return the bounds for a node's foreground, which is the part containing the
+ // expand/collapse symbol (if any), the icon (if any), and the text label.
+ gfx::Rect GetForegroundBoundsForNode(InternalNode* node);
+
+ // Returns the bounds for a node's text label.
+ gfx::Rect GetTextBoundsForNode(InternalNode* node);
+
+ // Implementation of GetTextBoundsForNode. Separated out as some callers
+ // already know the row/depth.
+ gfx::Rect GetForegroundBoundsForNodeImpl(InternalNode* node,
+ int row,
+ int depth);
// Returns the row and depth of a node.
int GetRowForInternalNode(InternalNode* node, int* depth);
+ // Returns the InternalNode (if any) whose foreground bounds contain |point|.
+ // If no node's foreground contains |point|, this function returns nullptr.
+ InternalNode* GetNodeAtPoint(const gfx::Point& point);
+
// Returns the row and depth of the specified node.
InternalNode* GetNodeByRow(int row, int* depth);
@@ -322,7 +336,7 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
void CollapseOrSelectParent();
// If the selected node is collapsed, it's expanded. Otherwise the first child
- // is seleected.
+ // is selected.
void ExpandOrSelectChild();
// Implementation of Expand(). Returns true if at least one node was expanded
@@ -331,6 +345,10 @@ class VIEWS_EXPORT TreeView : public ui::TreeModelObserver,
PrefixSelector* GetPrefixSelector();
+ // Returns whether |point| is in the bounds of |node|'s expand/collapse
+ // control.
+ bool IsPointInExpandControl(InternalNode* node, const gfx::Point& point);
+
// The model, may be null.
ui::TreeModel* model_;
diff --git a/chromium/ui/views/controls/tree/tree_view_unittest.cc b/chromium/ui/views/controls/tree/tree_view_unittest.cc
index e87956a254e..873f07bf70e 100644
--- a/chromium/ui/views/controls/tree/tree_view_unittest.cc
+++ b/chromium/ui/views/controls/tree/tree_view_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/models/tree_node_model.h"
@@ -39,7 +40,7 @@ class TestNode : public TreeNode<TestNode> {
// 'c'
class TreeViewTest : public ViewsTestBase {
public:
- TreeViewTest() : model_(new TestNode) {
+ TreeViewTest() : model_(base::MakeUnique<TestNode>()) {
static_cast<TestNode*>(model_.GetRoot())->SetTitle(ASCIIToUTF16("root"));
Add(model_.GetRoot(), 0, "a");
Add(Add(model_.GetRoot(), 1, "b"), 0, "b1");
@@ -65,7 +66,7 @@ class TreeViewTest : public ViewsTestBase {
int GetRowCount();
PrefixSelector* selector() { return tree_.GetPrefixSelector(); }
- ui::TreeNodeModel<TestNode > model_;
+ ui::TreeNodeModel<TestNode> model_;
TreeView tree_;
private:
@@ -79,10 +80,9 @@ class TreeViewTest : public ViewsTestBase {
TestNode* TreeViewTest::Add(TestNode* parent,
int index,
const std::string& title) {
- TestNode* new_node = new TestNode;
+ std::unique_ptr<TestNode> new_node = base::MakeUnique<TestNode>();
new_node->SetTitle(ASCIIToUTF16(title));
- model_.Add(parent, new_node, index);
- return new_node;
+ return model_.Add(parent, std::move(new_node), index);
}
std::string TreeViewTest::TreeViewContentsAsString() {
@@ -254,19 +254,19 @@ TEST_F(TreeViewTest, TreeNodesRemoved) {
// effect the tree.
tree_.Expand(GetNodeByTitle("b"));
tree_.Collapse(GetNodeByTitle("b"));
- delete model_.Remove(GetNodeByTitle("b1")->parent(), GetNodeByTitle("b1"));
+ model_.Remove(GetNodeByTitle("b1")->parent(), GetNodeByTitle("b1"));
EXPECT_EQ("root [a b c]", TreeViewContentsAsString());
EXPECT_EQ("root", GetSelectedNodeTitle());
EXPECT_EQ(4, GetRowCount());
// Remove 'b'.
- delete model_.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
+ model_.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
EXPECT_EQ("root [a c]", TreeViewContentsAsString());
EXPECT_EQ("root", GetSelectedNodeTitle());
EXPECT_EQ(3, GetRowCount());
// Remove 'c11', shouldn't visually change anything.
- delete model_.Remove(GetNodeByTitle("c11")->parent(), GetNodeByTitle("c11"));
+ model_.Remove(GetNodeByTitle("c11")->parent(), GetNodeByTitle("c11"));
EXPECT_EQ("root [a c]", TreeViewContentsAsString());
EXPECT_EQ("root", GetSelectedNodeTitle());
EXPECT_EQ(3, GetRowCount());
@@ -274,7 +274,7 @@ TEST_F(TreeViewTest, TreeNodesRemoved) {
// Select 'c1', remove 'c' and make sure selection changes.
tree_.SetSelectedNode(GetNodeByTitle("c1"));
EXPECT_EQ("c1", GetSelectedNodeTitle());
- delete model_.Remove(GetNodeByTitle("c")->parent(), GetNodeByTitle("c"));
+ model_.Remove(GetNodeByTitle("c")->parent(), GetNodeByTitle("c"));
EXPECT_EQ("root [a]", TreeViewContentsAsString());
EXPECT_EQ("root", GetSelectedNodeTitle());
EXPECT_EQ(2, GetRowCount());
@@ -284,7 +284,7 @@ TEST_F(TreeViewTest, TreeNodesRemoved) {
// selection should change to 'a'.
Add(GetNodeByTitle("root"), 1, "b");
tree_.SetSelectedNode(GetNodeByTitle("b"));
- delete model_.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
+ model_.Remove(GetNodeByTitle("b")->parent(), GetNodeByTitle("b"));
EXPECT_EQ("root [a]", TreeViewContentsAsString());
EXPECT_EQ("a", GetSelectedNodeTitle());
EXPECT_EQ(1, GetRowCount());
diff --git a/chromium/ui/views/controls/webview/BUILD.gn b/chromium/ui/views/controls/webview/BUILD.gn
index 2c16f507e1e..b8daeebab2a 100644
--- a/chromium/ui/views/controls/webview/BUILD.gn
+++ b/chromium/ui/views/controls/webview/BUILD.gn
@@ -44,7 +44,7 @@ component("webview") {
}
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
"../../test/webview_test_helper.cc",
diff --git a/chromium/ui/views/controls/webview/webview.gyp b/chromium/ui/views/controls/webview/webview.gyp
deleted file mode 100644
index f814e404aae..00000000000
--- a/chromium/ui/views/controls/webview/webview.gyp
+++ /dev/null
@@ -1,51 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //ui/views/controls/webview
- 'target_name': 'webview',
- 'type': '<(component)',
- 'dependencies': [
- '../../../../base/base.gyp:base',
- '../../../../base/base.gyp:base_i18n',
- '../../../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../../../../content/content.gyp:content_browser',
- '../../../../skia/skia.gyp:skia',
- '../../../../url/url.gyp:url_lib',
- '../../../base/ui_base.gyp:ui_base',
- '../../../content_accelerators/ui_content_accelerators.gyp:ui_content_accelerators',
- '../../../events/events.gyp:events',
- '../../../gfx/gfx.gyp:gfx',
- '../../../gfx/gfx.gyp:gfx_geometry',
- '../../../web_dialogs/web_dialogs.gyp:web_dialogs',
- '../../views.gyp:views',
- ],
- 'defines': [
- 'WEBVIEW_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: file list duplicated in GN build.
- 'unhandled_keyboard_event_handler.cc',
- 'unhandled_keyboard_event_handler.h',
- 'unhandled_keyboard_event_handler_mac.mm',
- 'unhandled_keyboard_event_handler_win.cc',
- 'web_dialog_view.cc',
- 'web_dialog_view.h',
- 'webview.cc',
- 'webview.h',
- 'webview_export.h',
- ],
- 'conditions': [
- ['OS=="linux" or OS=="android"', {
- 'sources': [ 'unhandled_keyboard_event_handler_default.cc', ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/ui/views/controls/webview/webview_tests.gyp b/chromium/ui/views/controls/webview/webview_tests.gyp
deleted file mode 100644
index f85385b415f..00000000000
--- a/chromium/ui/views/controls/webview/webview_tests.gyp
+++ /dev/null
@@ -1,45 +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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //ui/views/controls/webview:test_support
- 'target_name': 'webview_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../../../../base/base.gyp:base',
- '../../../../content/content.gyp:content',
- '../../../../content/content_shell_and_tests.gyp:test_support_content',
- '../../../../ipc/ipc.gyp:test_support_ipc',
- '../../../../skia/skia.gyp:skia',
- '../../../../testing/gtest.gyp:gtest',
- '../../../base/ui_base.gyp:ui_base',
- '../../../events/events.gyp:events',
- '../../../gfx/gfx.gyp:gfx',
- '../../../gfx/gfx.gyp:gfx_geometry',
- '../../views.gyp:views',
- '../../views.gyp:views_test_support',
- 'webview.gyp:webview',
- ],
- 'include_dirs': [
- '../../../..',
- ],
- 'sources': [
- '../../test/webview_test_helper.cc',
- '../../test/webview_test_helper.h',
- ],
- 'conditions': [
- ['use_aura==1', {
- 'dependencies': [
- '../../../aura/aura.gyp:aura',
- ],
- }],
- ],
- },
- ],
-}
diff --git a/chromium/ui/views/corewm/DEPS b/chromium/ui/views/corewm/DEPS
index c50f6946b18..7acdcd1c9c0 100644
--- a/chromium/ui/views/corewm/DEPS
+++ b/chromium/ui/views/corewm/DEPS
@@ -15,6 +15,7 @@ specific_include_rules = {
"tooltip_aura.cc": [
"+ui/views/background.h",
"+ui/views/border.h",
+ "+ui/views/painter.h",
"+ui/views/widget/widget.h",
"+ui/views/view.h",
],
diff --git a/chromium/ui/views/corewm/tooltip_aura.cc b/chromium/ui/views/corewm/tooltip_aura.cc
index e51a87265a5..3c58d0329d5 100644
--- a/chromium/ui/views/corewm/tooltip_aura.cc
+++ b/chromium/ui/views/corewm/tooltip_aura.cc
@@ -18,6 +18,7 @@
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
+#include "ui/views/painter.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -31,6 +32,15 @@ const int kTooltipMaxWidthPixels = 400;
const int kCursorOffsetX = 10;
const int kCursorOffsetY = 15;
+// TODO(varkha): Update if native widget can be transparent on Linux.
+bool CanUseTranslucentTooltipWidget() {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ return false;
+#else
+ return true;
+#endif
+}
+
// Creates a widget of type TYPE_TOOLTIP
views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
views::Widget* widget = new views::Widget;
@@ -42,6 +52,9 @@ views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
DCHECK(params.context);
params.keep_on_top = true;
params.accept_events = false;
+ if (CanUseTranslucentTooltipWidget())
+ params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+ params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
widget->Init(params);
return widget;
}
@@ -57,11 +70,12 @@ class TooltipAura::TooltipView : public views::View {
TooltipView()
: render_text_(gfx::RenderText::CreateInstance()),
max_width_(0) {
- const int kHorizontalPadding = 3;
- const int kVerticalPadding = 2;
- SetBorder(Border::CreateEmptyBorder(
- kVerticalPadding, kHorizontalPadding,
- kVerticalPadding, kHorizontalPadding));
+ const int kHorizontalPadding = 8;
+ const int kVerticalPaddingTop = 4;
+ const int kVerticalPaddingBottom = 5;
+ SetBorder(Border::CreateEmptyBorder(kVerticalPaddingTop, kHorizontalPadding,
+ kVerticalPaddingBottom,
+ kHorizontalPadding));
set_owned_by_client();
render_text_->SetWordWrapBehavior(gfx::WRAP_LONG_WORDS);
@@ -107,6 +121,22 @@ class TooltipAura::TooltipView : public views::View {
render_text_->SetColor(color);
}
+ void SetBackgroundColor(SkColor background_color) {
+ // Corner radius of tooltip background.
+ const float kTooltipCornerRadius = 2.f;
+ views::Background* background =
+ CanUseTranslucentTooltipWidget()
+ ? views::Background::CreateBackgroundPainter(
+ true, views::Painter::CreateSolidRoundRectPainter(
+ background_color, kTooltipCornerRadius))
+ : views::Background::CreateSolidBackground(background_color);
+ set_background(background);
+ // Force the text color to be readable when |background_color| is not
+ // opaque.
+ render_text_->set_subpixel_rendering_suppressed(
+ SkColorGetA(background_color) != 0xFF);
+ }
+
void SetMaxWidth(int width) {
max_width_ = width;
ResetDisplayRect();
@@ -188,10 +218,8 @@ void TooltipAura::SetText(aura::Window* window,
SetTooltipBounds(location, tooltip_view_->GetPreferredSize());
ui::NativeTheme* native_theme = widget_->GetNativeTheme();
- tooltip_view_->set_background(
- views::Background::CreateSolidBackground(
- native_theme->GetSystemColor(
- ui::NativeTheme::kColorId_TooltipBackground)));
+ tooltip_view_->SetBackgroundColor(native_theme->GetSystemColor(
+ ui::NativeTheme::kColorId_TooltipBackground));
tooltip_view_->SetForegroundColor(native_theme->GetSystemColor(
ui::NativeTheme::kColorId_TooltipText));
}
diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn
index 0d3371ddb94..ef70dd3a90d 100644
--- a/chromium/ui/views/examples/BUILD.gn
+++ b/chromium/ui/views/examples/BUILD.gn
@@ -12,12 +12,12 @@ component("views_examples_lib") {
"bubble_example.h",
"button_example.cc",
"button_example.h",
+ "button_sticker_sheet.cc",
+ "button_sticker_sheet.h",
"checkbox_example.cc",
"checkbox_example.h",
"combobox_example.cc",
"combobox_example.h",
- "double_split_view_example.cc",
- "double_split_view_example.h",
"example_base.cc",
"example_base.h",
"example_combobox_model.cc",
@@ -40,8 +40,6 @@ component("views_examples_lib") {
"radio_button_example.h",
"scroll_view_example.cc",
"scroll_view_example.h",
- "single_split_view_example.cc",
- "single_split_view_example.h",
"slider_example.cc",
"slider_example.h",
"tabbed_pane_example.cc",
@@ -54,6 +52,8 @@ component("views_examples_lib") {
"textfield_example.h",
"throbber_example.cc",
"throbber_example.h",
+ "toggle_button_example.cc",
+ "toggle_button_example.h",
"tree_view_example.cc",
"tree_view_example.h",
"vector_example.cc",
@@ -107,6 +107,7 @@ executable("views_examples_exe") {
"//base/test:test_support",
"//build/config/sanitizers:deps",
"//build/win:default_exe_manifest",
+ "//cc/surfaces",
"//ui/base",
"//ui/compositor",
"//ui/compositor:test_support",
diff --git a/chromium/ui/views/examples/DEPS b/chromium/ui/views/examples/DEPS
index 47e7bcdb2eb..dcab1974d68 100644
--- a/chromium/ui/views/examples/DEPS
+++ b/chromium/ui/views/examples/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+cc/surfaces/surface_manager.h",
"+content/public",
"+content/shell",
"+sandbox",
diff --git a/chromium/ui/views/examples/button_example.cc b/chromium/ui/views/examples/button_example.cc
index b3a2f13a4fc..18410cf614a 100644
--- a/chromium/ui/views/examples/button_example.cc
+++ b/chromium/ui/views/examples/button_example.cc
@@ -59,15 +59,15 @@ void ButtonExample::CreateExampleView(View* container) {
container->AddChildView(new BlueButton(this, ASCIIToUTF16("Blue Button")));
- container->AddChildView(MdTextButton::CreateMdButton(
- nullptr, base::ASCIIToUTF16("Material design")));
- MdTextButton* md_button = MdTextButton::CreateMdButton(
- nullptr, base::ASCIIToUTF16("Default"));
+ container->AddChildView(
+ MdTextButton::Create(nullptr, base::ASCIIToUTF16("Material design")));
+ MdTextButton* md_button =
+ MdTextButton::Create(nullptr, base::ASCIIToUTF16("Default"));
md_button->SetIsDefault(true);
container->AddChildView(md_button);
- md_button = MdTextButton::CreateMdButton(
- nullptr, base::ASCIIToUTF16("Call to action"));
- md_button->SetCallToAction(true);
+ md_button =
+ MdTextButton::Create(nullptr, base::ASCIIToUTF16("Call to action"));
+ md_button->SetProminent(true);
container->AddChildView(md_button);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
diff --git a/chromium/ui/views/examples/button_sticker_sheet.cc b/chromium/ui/views/examples/button_sticker_sheet.cc
new file mode 100644
index 00000000000..dc98a833cd2
--- /dev/null
+++ b/chromium/ui/views/examples/button_sticker_sheet.cc
@@ -0,0 +1,131 @@
+// Copyright 2016 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/button_sticker_sheet.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/layout/grid_layout.h"
+
+namespace views {
+namespace examples {
+
+namespace {
+
+// The id of the only ColumnSet in a stretchy grid (see below).
+const int kStretchyGridColumnSetId = 0;
+
+// Creates a stretchy grid layout: there are |ncols| columns, separated from
+// each other by padding columns, and all non-padding columns have equal flex
+// weight and will flex in either dimension as needed. The resulting grid layout
+// has only one ColumnSet (numbered kStretchyGridColumnSetId).
+GridLayout* MakeStretchyGridLayout(View* host, int ncols) {
+ const float kPaddingResizesEqually = 1.0;
+ const int kPaddingWidth = 30;
+ const GridLayout::Alignment kColumnStretchesHorizontally = GridLayout::FILL;
+ const GridLayout::Alignment kColumnStretchesVertically = GridLayout::FILL;
+ const float kColumnDoesNotResize = 0.0;
+ const GridLayout::SizeType kColumnUsesFixedSize = GridLayout::FIXED;
+ const int kColumnWidth = 96;
+
+ GridLayout* layout = new GridLayout(host);
+ ColumnSet* columns = layout->AddColumnSet(kStretchyGridColumnSetId);
+ for (int i = 0; i < ncols; ++i) {
+ if (i != 0)
+ columns->AddPaddingColumn(kPaddingResizesEqually, kPaddingWidth);
+ columns->AddColumn(kColumnStretchesHorizontally, kColumnStretchesVertically,
+ kColumnDoesNotResize, kColumnUsesFixedSize, kColumnWidth,
+ kColumnWidth);
+ }
+ return layout;
+}
+
+View* MakePlainLabel(const std::string& text) {
+ return new Label(base::ASCIIToUTF16(text));
+}
+
+// Add a row containing a label whose text is |label_text| and then all the
+// views in |views| to the supplied GridLayout, with padding between rows.
+void AddLabelledRowToGridLayout(GridLayout* layout,
+ const std::string& label_text,
+ std::vector<View*> views) {
+ const float kRowDoesNotResizeVertically = 0.0;
+ const int kPaddingRowHeight = 8;
+ layout->StartRow(kRowDoesNotResizeVertically, kStretchyGridColumnSetId);
+ layout->AddView(MakePlainLabel(label_text));
+ for (const auto& view : views)
+ layout->AddView(view);
+ // This gets added extraneously after the last row, but it doesn't hurt and
+ // means there's no need to keep track of whether to add it or not.
+ layout->AddPaddingRow(kRowDoesNotResizeVertically, kPaddingRowHeight);
+}
+
+// Constructs a pair of MdTextButtons in the specified |state| with the
+// specified |listener|, and returns them in |*primary| and |*secondary|. The
+// button in |*primary| is a call-to-action button, and the button in
+// |*secondary| is a regular button.
+void MakeButtonsInState(MdTextButton** primary,
+ MdTextButton** secondary,
+ ButtonListener* listener,
+ Button::ButtonState state) {
+ const base::string16 button_text = base::ASCIIToUTF16("Button");
+ *primary = MdTextButton::Create(listener, button_text);
+ (*primary)->SetProminent(true);
+ (*primary)->SetState(state);
+
+ *secondary = MdTextButton::Create(listener, button_text);
+ (*secondary)->SetState(state);
+}
+
+} // namespace
+
+ButtonStickerSheet::ButtonStickerSheet()
+ : ExampleBase("Button (Sticker Sheet)") {}
+
+ButtonStickerSheet::~ButtonStickerSheet() {}
+
+void ButtonStickerSheet::CreateExampleView(View* container) {
+ GridLayout* layout = MakeStretchyGridLayout(container, 3);
+ container->SetLayoutManager(layout);
+
+ if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
+ const char* kNeedsMdWarning =
+ "This will look wrong without --secondary-ui-md.";
+ layout->StartRow(0, 0);
+ layout->AddView(MakePlainLabel(kNeedsMdWarning), 3, 1);
+ }
+
+ // The title row has an empty row label.
+ AddLabelledRowToGridLayout(
+ layout, std::string(),
+ {MakePlainLabel("Primary"), MakePlainLabel("Secondary")});
+
+ MdTextButton* primary = nullptr;
+ MdTextButton* secondary = nullptr;
+
+ MakeButtonsInState(&primary, &secondary, this, Button::STATE_NORMAL);
+ AddLabelledRowToGridLayout(layout, "Default", {primary, secondary});
+ MakeButtonsInState(&primary, &secondary, this, Button::STATE_NORMAL);
+ AddLabelledRowToGridLayout(layout, "Normal", {primary, secondary});
+ MakeButtonsInState(&primary, &secondary, this, Button::STATE_HOVERED);
+ AddLabelledRowToGridLayout(layout, "Hovered", {primary, secondary});
+ MakeButtonsInState(&primary, &secondary, this, Button::STATE_PRESSED);
+ AddLabelledRowToGridLayout(layout, "Pressed", {primary, secondary});
+ MakeButtonsInState(&primary, &secondary, this, Button::STATE_DISABLED);
+ AddLabelledRowToGridLayout(layout, "Disabled", {primary, secondary});
+
+ MakeButtonsInState(&primary, &secondary, this, Button::STATE_NORMAL);
+ primary->OnFocus();
+ secondary->OnFocus();
+ AddLabelledRowToGridLayout(layout, "Focused", {primary, secondary});
+}
+
+void ButtonStickerSheet::ButtonPressed(Button* button, const ui::Event& event) {
+ // Ignore button presses.
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/button_sticker_sheet.h b/chromium/ui/views/examples/button_sticker_sheet.h
new file mode 100644
index 00000000000..3b8888e06ee
--- /dev/null
+++ b/chromium/ui/views/examples/button_sticker_sheet.h
@@ -0,0 +1,38 @@
+// Copyright 2016 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_BUTTON_STICKER_SHEET_H_
+#define UI_VIEWS_EXAMPLES_BUTTON_STICKER_SHEET_H_
+
+#include "base/macros.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views {
+namespace examples {
+
+// An "example" that displays a sticker sheet of all the available material
+// design button styles. This example only looks right with `--secondary-ui-md`.
+// It is designed to be as visually similar to the UI Harmony spec's sticker
+// sheet for buttons as possible.
+class VIEWS_EXAMPLES_EXPORT ButtonStickerSheet : public ExampleBase,
+ public ButtonListener {
+ public:
+ ButtonStickerSheet();
+ ~ButtonStickerSheet() override;
+
+ // ExampleBase:
+ void CreateExampleView(View* container) override;
+
+ // ButtonListener:
+ void ButtonPressed(Button* sender, const ui::Event& event) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ButtonStickerSheet);
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_BUTTON_STICKER_SHEET_H_
diff --git a/chromium/ui/views/examples/combobox_example.cc b/chromium/ui/views/examples/combobox_example.cc
index aedc8fbdef7..790d024e37c 100644
--- a/chromium/ui/views/examples/combobox_example.cc
+++ b/chromium/ui/views/examples/combobox_example.cc
@@ -23,7 +23,7 @@ int ComboboxModelExample::GetItemCount() const {
}
base::string16 ComboboxModelExample::GetItemAt(int index) {
- return base::UTF8ToUTF16(base::StringPrintf("Item %d", index));
+ return base::UTF8ToUTF16(base::StringPrintf("%c item", 'A' + index));
}
ComboboxExample::ComboboxExample() : ExampleBase("Combo Box") {
@@ -56,7 +56,7 @@ void ComboboxExample::CreateExampleView(View* container) {
container->SetLayoutManager(new BoxLayout(
BoxLayout::kVertical,
- 1, 1, 1));
+ 0, 10, 5));
container->AddChildView(combobox_);
container->AddChildView(disabled_combobox_);
container->AddChildView(action_combobox_);
diff --git a/chromium/ui/views/examples/double_split_view_example.cc b/chromium/ui/views/examples/double_split_view_example.cc
deleted file mode 100644
index 78ecfc1d833..00000000000
--- a/chromium/ui/views/examples/double_split_view_example.cc
+++ /dev/null
@@ -1,83 +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/examples/double_split_view_example.h"
-
-#include "base/macros.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/single_split_view.h"
-#include "ui/views/layout/grid_layout.h"
-
-namespace views {
-namespace examples {
-
-namespace {
-
-// DoubleSplitViews's content, which draws gradient color on background.
-class SplittedView : public View {
- public:
- SplittedView();
- ~SplittedView() override;
-
- void SetColor(SkColor from, SkColor to);
-
- // View:
- gfx::Size GetMinimumSize() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SplittedView);
-};
-
-SplittedView::SplittedView() {
- SetColor(SK_ColorRED, SK_ColorGREEN);
-}
-
-SplittedView::~SplittedView() {
-}
-
-void SplittedView::SetColor(SkColor from, SkColor to) {
- set_background(Background::CreateVerticalGradientBackground(from, to));
-}
-
-gfx::Size SplittedView::GetMinimumSize() const {
- return gfx::Size(10, 10);
-}
-
-} // namespace
-
-DoubleSplitViewExample::DoubleSplitViewExample()
- : ExampleBase("Double Split View") {
-}
-
-DoubleSplitViewExample::~DoubleSplitViewExample() {
-}
-
-void DoubleSplitViewExample::CreateExampleView(View* container) {
- SplittedView* splitted_view_1 = new SplittedView();
- SplittedView* splitted_view_2 = new SplittedView();
- SplittedView* splitted_view_3 = new SplittedView();
-
- inner_single_split_view_ = new SingleSplitView(
- splitted_view_1, splitted_view_2,
- SingleSplitView::HORIZONTAL_SPLIT,
- NULL);
-
- outer_single_split_view_ = new SingleSplitView(
- inner_single_split_view_, splitted_view_3,
- SingleSplitView::HORIZONTAL_SPLIT,
- NULL);
-
- GridLayout* layout = new GridLayout(container);
- container->SetLayoutManager(layout);
-
- // Add scroll view.
- ColumnSet* column_set = layout->AddColumnSet(0);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- layout->StartRow(1, 0);
- layout->AddView(outer_single_split_view_);
-}
-
-} // namespace examples
-} // namespace views
diff --git a/chromium/ui/views/examples/double_split_view_example.h b/chromium/ui/views/examples/double_split_view_example.h
deleted file mode 100644
index 231ddc67adc..00000000000
--- a/chromium/ui/views/examples/double_split_view_example.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2011 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_DOUBLE_SPLIT_VIEW_EXAMPLE_H_
-#define UI_VIEWS_EXAMPLES_DOUBLE_SPLIT_VIEW_EXAMPLE_H_
-
-#include "base/macros.h"
-#include "ui/views/examples/example_base.h"
-
-namespace views {
-class SingleSplitView;
-
-namespace examples {
-
-class VIEWS_EXAMPLES_EXPORT DoubleSplitViewExample : public ExampleBase {
- public:
- DoubleSplitViewExample();
- ~DoubleSplitViewExample() override;
-
- // ExampleBase:
- void CreateExampleView(View* container) override;
-
- private:
- // The SingleSplitViews to be embedded.
- SingleSplitView* outer_single_split_view_;
- SingleSplitView* inner_single_split_view_;
-
- DISALLOW_COPY_AND_ASSIGN(DoubleSplitViewExample);
-};
-
-} // namespace examples
-} // namespace views
-
-#endif // UI_VIEWS_EXAMPLES_DOUBLE_SPLIT_VIEW_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/examples.gyp b/chromium/ui/views/examples/examples.gyp
deleted file mode 100644
index 4038d615027..00000000000
--- a/chromium/ui/views/examples/examples.gyp
+++ /dev/null
@@ -1,205 +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.
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //ui/views/examples
- 'target_name': 'views_examples_lib',
- 'type': '<(component)',
- 'dependencies': [
- '../../../base/base.gyp:base',
- '../../../skia/skia.gyp:skia',
- '../../../third_party/icu/icu.gyp:icui18n',
- '../../../third_party/icu/icu.gyp:icuuc',
- '../../base/ui_base.gyp:ui_base',
- '../../events/events.gyp:events',
- '../../gfx/gfx.gyp:gfx',
- '../../gfx/gfx.gyp:gfx_geometry',
- '../../gfx/gfx.gyp:gfx_range',
- '../../gfx/gfx.gyp:gfx_vector_icons',
- '../../resources/ui_resources.gyp:ui_resources',
- '../../resources/ui_resources.gyp:ui_test_pak',
- '../views.gyp:views',
- ],
- 'include_dirs': [
- '../../..',
- ],
- 'defines': [
- 'GFX_VECTOR_ICONS_UNSAFE',
- 'VIEWS_EXAMPLES_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'bubble_example.cc',
- 'bubble_example.h',
- 'button_example.cc',
- 'button_example.h',
- 'checkbox_example.cc',
- 'checkbox_example.h',
- 'combobox_example.cc',
- 'combobox_example.h',
- 'double_split_view_example.cc',
- 'double_split_view_example.h',
- 'example_base.cc',
- 'example_base.h',
- 'example_combobox_model.cc',
- 'example_combobox_model.h',
- 'examples_window.cc',
- 'examples_window.h',
- 'label_example.cc',
- 'label_example.h',
- 'link_example.cc',
- 'link_example.h',
- 'menu_example.cc',
- 'menu_example.h',
- 'message_box_example.cc',
- 'message_box_example.h',
- 'multiline_example.cc',
- 'multiline_example.h',
- 'progress_bar_example.cc',
- 'progress_bar_example.h',
- 'radio_button_example.cc',
- 'radio_button_example.h',
- 'scroll_view_example.cc',
- 'scroll_view_example.h',
- 'single_split_view_example.cc',
- 'single_split_view_example.h',
- 'slider_example.cc',
- 'slider_example.h',
- 'tabbed_pane_example.cc',
- 'tabbed_pane_example.h',
- 'table_example.cc',
- 'table_example.h',
- 'text_example.cc',
- 'text_example.h',
- 'textfield_example.cc',
- 'textfield_example.h',
- 'throbber_example.cc',
- 'throbber_example.h',
- 'tree_view_example.cc',
- 'tree_view_example.h',
- 'views_examples_export.h',
- 'vector_example.cc',
- 'vector_example.h',
- 'widget_example.cc',
- 'widget_example.h',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'include_dirs': [
- '../../../third_party/wtl/include',
- ],
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- }],
- ['use_aura==1', {
- 'dependencies': [
- '../../aura/aura.gyp:aura',
- ],
- }],
- ],
- }, # target_name: views_examples_lib
- {
- # GN version: //ui/views/examples:views_examples_exe
- 'target_name': 'views_examples_exe',
- 'type': 'executable',
- 'dependencies': [
- '../../../base/base.gyp:base',
- '../../../base/base.gyp:base_i18n',
- '../../base/ui_base.gyp:ui_base',
- '../../compositor/compositor.gyp:compositor',
- '../../compositor/compositor.gyp:compositor_test_support',
- '../../gfx/gfx.gyp:gfx',
- '../../resources/ui_resources.gyp:ui_test_pak',
- '../views.gyp:views',
- '../views.gyp:views_test_support',
- 'views_examples_lib',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'examples_main.cc',
- ],
- 'conditions': [
- ['use_aura==1', {
- 'dependencies': [
- '../../aura/aura.gyp:aura',
- ],
- }],
- ],
- }, # target_name: views_examples_exe
- {
- # GN version: //ui/views/examples:views_examples_with_content_lib
- 'target_name': 'views_examples_with_content_lib',
- 'type': '<(component)',
- 'dependencies': [
- '../../../base/base.gyp:base',
- '../../../content/content.gyp:content',
- '../../../skia/skia.gyp:skia',
- '../../../url/url.gyp:url_lib',
- '../../events/events.gyp:events',
- '../controls/webview/webview.gyp:webview',
- '../views.gyp:views',
- 'views_examples_lib',
- ],
- 'defines': [
- 'VIEWS_EXAMPLES_WITH_CONTENT_IMPLEMENTATION',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'examples_window_with_content.cc',
- 'examples_window_with_content.h',
- 'views_examples_with_content_export.h',
- 'webview_example.cc',
- 'webview_example.h',
- ],
- }, # target_name: views_examples_with_content_lib
- {
- # GN version: //ui/views/examples/views_examples_with_content_exe
- 'target_name': 'views_examples_with_content_exe',
- 'type': 'executable',
- 'dependencies': [
- '../resources/views_resources.gyp:views_resources',
- '../../views_content_client/views_content_client.gyp:views_content_client',
- 'views_examples_with_content_lib',
- ],
- 'sources': [
- # Note: sources list duplicated in GN build.
- 'examples_with_content_main_exe.cc',
- ],
- 'conditions': [
- ['component=="shared_library"', {
- 'dependencies': [
- '../../../base/base.gyp:base',
- '../../../content/content.gyp:content',
- ],
- }],
- ['OS=="win"', {
- 'link_settings': {
- 'libraries': [
- '-limm32.lib',
- '-loleacc.lib',
- ]
- },
- 'msvs_settings': {
- 'VCManifestTool': {
- 'AdditionalManifestFiles': [
- 'views_examples.exe.manifest',
- ],
- },
- 'VCLinkerTool': {
- 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
- },
- },
- 'dependencies': [
- '../../../sandbox/sandbox.gyp:sandbox',
- '../../../content/content.gyp:sandbox_helper_win',
- ],
- }],
- ],
- }, # target_name: views_examples_with_content_exe
- ],
-}
diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc
index bb074a0dabe..98f73c0c3b8 100644
--- a/chromium/ui/views/examples/examples_main.cc
+++ b/chromium/ui/views/examples/examples_main.cc
@@ -16,6 +16,7 @@
#include "base/run_loop.h"
#include "base/test/test_discardable_memory_allocator.h"
#include "build/build_config.h"
+#include "cc/surfaces/surface_manager.h"
#include "ui/base/ime/input_method_initializer.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
@@ -67,8 +68,10 @@ int main(int argc, char** argv) {
// The ContextFactory must exist before any Compositors are created.
bool context_factory_for_test = false;
+ cc::SurfaceManager surface_manager;
std::unique_ptr<ui::InProcessContextFactory> context_factory(
- new ui::InProcessContextFactory(context_factory_for_test, nullptr));
+ new ui::InProcessContextFactory(context_factory_for_test,
+ &surface_manager));
context_factory->set_use_test_surface(false);
base::MessageLoopForUI message_loop;
@@ -109,9 +112,8 @@ int main(int argc, char** argv) {
display::Screen::SetScreenInstance(desktop_screen.get());
#endif
- views::examples::ShowExamplesWindow(
- views::examples::QUIT_ON_CLOSE, nullptr,
- std::unique_ptr<ScopedVector<views::examples::ExampleBase>>());
+ views::examples::ShowExamplesWindow(views::examples::QUIT_ON_CLOSE, nullptr,
+ nullptr);
base::RunLoop().Run();
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index 57be047069c..3809c2fbf9f 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/scoped_vector.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"
@@ -18,9 +19,9 @@
#include "ui/views/controls/label.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/double_split_view_example.h"
#include "ui/views/examples/label_example.h"
#include "ui/views/examples/link_example.h"
#include "ui/views/examples/menu_example.h"
@@ -29,13 +30,13 @@
#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/single_split_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"
@@ -56,9 +57,9 @@ ScopedExamples CreateExamples() {
ScopedExamples examples(new ScopedVector<ExampleBase>);
examples->push_back(new BubbleExample);
examples->push_back(new ButtonExample);
+ examples->push_back(new ButtonStickerSheet);
examples->push_back(new CheckboxExample);
examples->push_back(new ComboboxExample);
- examples->push_back(new DoubleSplitViewExample);
examples->push_back(new LabelExample);
examples->push_back(new LinkExample);
examples->push_back(new MenuExample);
@@ -67,12 +68,12 @@ ScopedExamples CreateExamples() {
examples->push_back(new ProgressBarExample);
examples->push_back(new RadioButtonExample);
examples->push_back(new ScrollViewExample);
- examples->push_back(new SingleSplitViewExample);
examples->push_back(new SliderExample);
examples->push_back(new TabbedPaneExample);
examples->push_back(new TableExample);
examples->push_back(new TextExample);
examples->push_back(new TextfieldExample);
+ examples->push_back(new ToggleButtonExample);
examples->push_back(new ThrobberExample);
examples->push_back(new TreeViewExample);
examples->push_back(new VectorExample);
@@ -182,7 +183,6 @@ class ExamplesWindowContents : public WidgetDelegateView,
base::string16 GetWindowTitle() const override {
return base::ASCIIToUTF16("Views Examples");
}
- View* GetContentsView() override { return this; }
void WindowClosing() override {
instance_ = NULL;
if (operation_ == QUIT_ON_CLOSE)
diff --git a/chromium/ui/views/examples/menu_example.cc b/chromium/ui/views/examples/menu_example.cc
index 378c90a76bc..c8c8368a73f 100644
--- a/chromium/ui/views/examples/menu_example.cc
+++ b/chromium/ui/views/examples/menu_example.cc
@@ -31,8 +31,6 @@ class ExampleMenuModel : public ui::SimpleMenuModel,
// ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
- bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) override;
void ExecuteCommand(int command_id, int event_flags) override;
private:
@@ -119,13 +117,6 @@ bool ExampleMenuModel::IsCommandIdEnabled(int command_id) const {
return command_id != COMMAND_GO_HOME;
}
-bool ExampleMenuModel::GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) {
- // We don't use this in the example.
- return false;
-}
-
void ExampleMenuModel::ExecuteCommand(int command_id, int event_flags) {
switch (command_id) {
case COMMAND_DO_SOMETHING: {
@@ -188,16 +179,12 @@ ExampleMenuButton::~ExampleMenuButton() {
void ExampleMenuButton::OnMenuButtonClicked(MenuButton* source,
const gfx::Point& point,
const ui::Event* event) {
- menu_runner_.reset(new MenuRunner(GetMenuModel(), MenuRunner::HAS_MNEMONICS));
-
- if (menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
- this,
- gfx::Rect(point, gfx::Size()),
- MENU_ANCHOR_TOPRIGHT,
- ui::MENU_SOURCE_NONE) ==
- MenuRunner::MENU_DELETED) {
- return;
- }
+ menu_runner_.reset(new MenuRunner(
+ GetMenuModel(), MenuRunner::HAS_MNEMONICS | MenuRunner::ASYNC));
+
+ menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), this,
+ gfx::Rect(point, gfx::Size()), MENU_ANCHOR_TOPRIGHT,
+ ui::MENU_SOURCE_NONE);
}
ui::SimpleMenuModel* ExampleMenuButton::GetMenuModel() {
diff --git a/chromium/ui/views/examples/progress_bar_example.cc b/chromium/ui/views/examples/progress_bar_example.cc
index 8a860f212af..4cb75a156e7 100644
--- a/chromium/ui/views/examples/progress_bar_example.cc
+++ b/chromium/ui/views/examples/progress_bar_example.cc
@@ -7,7 +7,7 @@
#include <algorithm>
#include "base/strings/utf_string_conversions.h"
-#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/view.h"
@@ -27,11 +27,10 @@ namespace examples {
ProgressBarExample::ProgressBarExample()
: ExampleBase("Progress Bar"),
- minus_button_(NULL),
- plus_button_(NULL),
- progress_bar_(NULL),
- current_percent_(0.0) {
-}
+ minus_button_(nullptr),
+ plus_button_(nullptr),
+ progress_bar_(nullptr),
+ current_percent_(0.0) {}
ProgressBarExample::~ProgressBarExample() {
}
@@ -41,22 +40,35 @@ void ProgressBarExample::CreateExampleView(View* container) {
container->SetLayoutManager(layout);
ColumnSet* column_set = layout->AddColumnSet(0);
- column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL,
- 0, GridLayout::USE_PREF, 0, 0);
+ column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, 8);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL,
- 1, GridLayout::USE_PREF, 0, 0);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::FIXED, 200, 0);
column_set->AddPaddingColumn(0, 8);
- column_set->AddColumn(GridLayout::TRAILING, GridLayout::FILL,
- 0, GridLayout::USE_PREF, 0, 0);
+ column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
- minus_button_ = new LabelButton(this, base::ASCIIToUTF16("-"));
+ minus_button_ = MdTextButton::Create(this, base::ASCIIToUTF16("-"));
layout->AddView(minus_button_);
progress_bar_ = new ProgressBar();
layout->AddView(progress_bar_);
- plus_button_ = new LabelButton(this, base::ASCIIToUTF16("+"));
+ plus_button_ = MdTextButton::Create(this, base::ASCIIToUTF16("+"));
layout->AddView(plus_button_);
+
+ layout->StartRowWithPadding(0, 0, 0, 10);
+ layout->AddView(new Label(base::ASCIIToUTF16("Infinite loader:")));
+ ProgressBar* infinite_bar = new ProgressBar();
+ infinite_bar->SetValue(-1);
+ layout->AddView(infinite_bar);
+
+ layout->StartRowWithPadding(0, 0, 0, 10);
+ layout->AddView(
+ new Label(base::ASCIIToUTF16("Infinite loader (very short):")));
+ ProgressBar* shorter_bar = new ProgressBar(2);
+ shorter_bar->SetValue(-1);
+ layout->AddView(shorter_bar);
}
void ProgressBarExample::ButtonPressed(Button* sender, const ui::Event& event) {
diff --git a/chromium/ui/views/examples/single_split_view_example.cc b/chromium/ui/views/examples/single_split_view_example.cc
deleted file mode 100644
index 8f3deac15c5..00000000000
--- a/chromium/ui/views/examples/single_split_view_example.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2011 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/single_split_view_example.h"
-
-#include "base/macros.h"
-#include "ui/views/background.h"
-#include "ui/views/controls/single_split_view.h"
-#include "ui/views/layout/grid_layout.h"
-
-namespace views {
-namespace examples {
-namespace {
-
-// SingleSplitView's content, which draws gradient color on background.
-class SplittedView : public View {
- public:
- SplittedView();
- ~SplittedView() override;
-
- void SetColor(SkColor from, SkColor to);
-
- private:
- // View:
- gfx::Size GetPreferredSize() const override;
- gfx::Size GetMinimumSize() const override;
- void Layout() override;
-
- DISALLOW_COPY_AND_ASSIGN(SplittedView);
-};
-
-SplittedView::SplittedView() {
- SetColor(SK_ColorRED, SK_ColorGREEN);
-}
-
-SplittedView::~SplittedView() {
-}
-
-void SplittedView::SetColor(SkColor from, SkColor to) {
- set_background(Background::CreateVerticalGradientBackground(from, to));
-}
-
-gfx::Size SplittedView::GetPreferredSize() const {
- return gfx::Size(width(), height());
-}
-
-gfx::Size SplittedView::GetMinimumSize() const {
- return gfx::Size(10, 10);
-}
-
-void SplittedView::Layout() {
- SizeToPreferredSize();
-}
-
-} // namespace
-
-SingleSplitViewExample::SingleSplitViewExample()
- : ExampleBase("Single Split View") {
-}
-
-SingleSplitViewExample::~SingleSplitViewExample() {
-}
-
-void SingleSplitViewExample::CreateExampleView(View* container) {
- SplittedView* splitted_view_1 = new SplittedView;
- SplittedView* splitted_view_2 = new SplittedView;
-
- splitted_view_1->SetColor(SK_ColorYELLOW, SK_ColorCYAN);
-
- single_split_view_ = new SingleSplitView(
- splitted_view_1, splitted_view_2,
- SingleSplitView::HORIZONTAL_SPLIT,
- this);
-
- GridLayout* layout = new GridLayout(container);
- container->SetLayoutManager(layout);
-
- ColumnSet* column_set = layout->AddColumnSet(0);
- column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
- GridLayout::USE_PREF, 0, 0);
- layout->StartRow(1, 0);
- layout->AddView(single_split_view_);
-}
-
-bool SingleSplitViewExample::SplitHandleMoved(SingleSplitView* sender) {
- PrintStatus("Splitter moved");
- return true;
-}
-
-} // namespace examples
-} // namespace views
diff --git a/chromium/ui/views/examples/single_split_view_example.h b/chromium/ui/views/examples/single_split_view_example.h
deleted file mode 100644
index 8f2d50664f9..00000000000
--- a/chromium/ui/views/examples/single_split_view_example.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2011 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_SINGLE_SPLIT_VIEW_EXAMPLE_H_
-#define UI_VIEWS_EXAMPLES_SINGLE_SPLIT_VIEW_EXAMPLE_H_
-
-#include "base/macros.h"
-#include "ui/views/controls/single_split_view_listener.h"
-#include "ui/views/examples/example_base.h"
-
-namespace views {
-namespace examples {
-
-class VIEWS_EXAMPLES_EXPORT SingleSplitViewExample
- : public ExampleBase,
- public SingleSplitViewListener {
- public:
- SingleSplitViewExample();
- ~SingleSplitViewExample() override;
-
- // ExampleBase:
- void CreateExampleView(View* container) override;
-
- private:
- // SingleSplitViewListener:
- bool SplitHandleMoved(SingleSplitView* sender) override;
-
- SingleSplitView* single_split_view_;
-
- DISALLOW_COPY_AND_ASSIGN(SingleSplitViewExample);
-};
-
-} // namespace examples
-} // namespace views
-
-#endif // UI_VIEWS_EXAMPLES_SINGLE_SPLIT_VIEW_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/slider_example.cc b/chromium/ui/views/examples/slider_example.cc
index 89f78568e23..9367d120c78 100644
--- a/chromium/ui/views/examples/slider_example.cc
+++ b/chromium/ui/views/examples/slider_example.cc
@@ -7,6 +7,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/views/controls/label.h"
+#include "ui/views/controls/slider.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/view.h"
@@ -24,7 +25,8 @@ SliderExample::~SliderExample() {
void SliderExample::CreateExampleView(View* container) {
label_ = new Label();
- slider_ = new Slider(this, Slider::HORIZONTAL);
+ // Create a material design slider in this example.
+ slider_ = Slider::CreateSlider(true /** is_material_design **/, this);
slider_->SetValue(0.5);
diff --git a/chromium/ui/views/examples/textfield_example.cc b/chromium/ui/views/examples/textfield_example.cc
index ffcf464e9e5..5b3144455d4 100644
--- a/chromium/ui/views/examples/textfield_example.cc
+++ b/chromium/ui/views/examples/textfield_example.cc
@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/events/event.h"
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/render_text.h"
#include "ui/views/controls/button/label_button.h"
@@ -24,14 +25,15 @@ namespace examples {
TextfieldExample::TextfieldExample()
: ExampleBase("Textfield"),
- name_(NULL),
- password_(NULL),
- read_only_(NULL),
- show_password_(NULL),
- clear_all_(NULL),
- append_(NULL),
- set_(NULL),
- set_style_(NULL) {
+ name_(nullptr),
+ password_(nullptr),
+ disabled_(nullptr),
+ read_only_(nullptr),
+ show_password_(nullptr),
+ clear_all_(nullptr),
+ append_(nullptr),
+ set_(nullptr),
+ set_style_(nullptr) {
}
TextfieldExample::~TextfieldExample() {
@@ -42,10 +44,15 @@ void TextfieldExample::CreateExampleView(View* container) {
password_ = new Textfield();
password_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
password_->set_placeholder_text(ASCIIToUTF16("password"));
+ disabled_ = new Textfield();
+ disabled_->SetEnabled(false);
+ disabled_->SetText(ASCIIToUTF16("disabled"));
read_only_ = new Textfield();
read_only_->SetReadOnly(true);
read_only_->SetText(ASCIIToUTF16("read only"));
show_password_ = new LabelButton(this, ASCIIToUTF16("Show password"));
+ set_background_ =
+ new LabelButton(this, ASCIIToUTF16("Set non-default background"));
clear_all_ = new LabelButton(this, ASCIIToUTF16("Clear All"));
append_ = new LabelButton(this, ASCIIToUTF16("Append"));
set_ = new LabelButton(this, ASCIIToUTF16("Set"));
@@ -61,25 +68,24 @@ void TextfieldExample::CreateExampleView(View* container) {
0.2f, GridLayout::USE_PREF, 0, 0);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL,
0.8f, GridLayout::USE_PREF, 0, 0);
- layout->StartRow(0, 0);
- layout->AddView(new Label(ASCIIToUTF16("Name:")));
- layout->AddView(name_);
- layout->StartRow(0, 0);
- layout->AddView(new Label(ASCIIToUTF16("Password:")));
- layout->AddView(password_);
- layout->StartRow(0, 0);
- layout->AddView(new Label(ASCIIToUTF16("Read Only:")));
- layout->AddView(read_only_);
- layout->StartRow(0, 0);
- layout->AddView(show_password_);
- layout->StartRow(0, 0);
- layout->AddView(clear_all_);
- layout->StartRow(0, 0);
- layout->AddView(append_);
- layout->StartRow(0, 0);
- layout->AddView(set_);
- layout->StartRow(0, 0);
- layout->AddView(set_style_);
+
+ auto MakeRow = [layout](View* view1, View* view2) {
+ layout->StartRowWithPadding(0, 0, 0, 5);
+ layout->AddView(view1);
+ if (view2)
+ layout->AddView(view2);
+ };
+ MakeRow(new Label(ASCIIToUTF16("Name:")), name_);
+ MakeRow(new Label(ASCIIToUTF16("Password:")), password_);
+ MakeRow(new Label(ASCIIToUTF16("Disabled:")), disabled_);
+ MakeRow(new Label(ASCIIToUTF16("Read Only:")), read_only_);
+ MakeRow(new Label(ASCIIToUTF16("Name:")), nullptr);
+ MakeRow(show_password_, nullptr);
+ MakeRow(set_background_, nullptr);
+ MakeRow(clear_all_, nullptr);
+ MakeRow(append_, nullptr);
+ MakeRow(set_, nullptr);
+ MakeRow(set_style_, nullptr);
}
void TextfieldExample::ContentsChanged(Textfield* sender,
@@ -88,8 +94,8 @@ void TextfieldExample::ContentsChanged(Textfield* sender,
PrintStatus("Name [%s]", UTF16ToUTF8(new_contents).c_str());
} else if (sender == password_) {
PrintStatus("Password [%s]", UTF16ToUTF8(new_contents).c_str());
- } else if (sender == read_only_) {
- PrintStatus("Read Only [%s]", UTF16ToUTF8(new_contents).c_str());
+ } else {
+ NOTREACHED();
}
}
@@ -107,18 +113,23 @@ bool TextfieldExample::HandleMouseEvent(Textfield* sender,
void TextfieldExample::ButtonPressed(Button* sender, const ui::Event& event) {
if (sender == show_password_) {
PrintStatus("Password [%s]", UTF16ToUTF8(password_->text()).c_str());
+ } else if (sender == set_background_) {
+ password_->SetBackgroundColor(gfx::kGoogleRed300);
} else if (sender == clear_all_) {
base::string16 empty;
name_->SetText(empty);
password_->SetText(empty);
+ disabled_->SetText(empty);
read_only_->SetText(empty);
} else if (sender == append_) {
name_->AppendText(ASCIIToUTF16("[append]"));
password_->AppendText(ASCIIToUTF16("[append]"));
+ disabled_->SetText(ASCIIToUTF16("[append]"));
read_only_->AppendText(ASCIIToUTF16("[append]"));
} else if (sender == set_) {
name_->SetText(ASCIIToUTF16("[set]"));
password_->SetText(ASCIIToUTF16("[set]"));
+ disabled_->SetText(ASCIIToUTF16("[set]"));
read_only_->SetText(ASCIIToUTF16("[set]"));
} else if (sender == set_style_) {
if (!name_->text().empty()) {
diff --git a/chromium/ui/views/examples/textfield_example.h b/chromium/ui/views/examples/textfield_example.h
index 90ec331b4a3..c40e3743625 100644
--- a/chromium/ui/views/examples/textfield_example.h
+++ b/chromium/ui/views/examples/textfield_example.h
@@ -44,10 +44,12 @@ class VIEWS_EXAMPLES_EXPORT TextfieldExample : public ExampleBase,
// Textfields for name and password.
Textfield* name_;
Textfield* password_;
+ Textfield* disabled_;
Textfield* read_only_;
// Various buttons to control textfield.
LabelButton* show_password_;
+ LabelButton* set_background_;
LabelButton* clear_all_;
LabelButton* append_;
LabelButton* set_;
diff --git a/chromium/ui/views/examples/throbber_example.cc b/chromium/ui/views/examples/throbber_example.cc
index 5a1981219c1..c17cbb03cd6 100644
--- a/chromium/ui/views/examples/throbber_example.cc
+++ b/chromium/ui/views/examples/throbber_example.cc
@@ -16,25 +16,40 @@ namespace {
class ThrobberView : public View {
public:
- ThrobberView() : throbber_(new Throbber()) {
+ ThrobberView() : throbber_(new Throbber()), is_checked_(false) {
AddChildView(throbber_);
throbber_->Start();
}
+ // View::
gfx::Size GetPreferredSize() const override {
return gfx::Size(width(), height());
}
void Layout() override {
- int diameter = 64;
+ int diameter = 16;
throbber_->SetBounds((width() - diameter) / 2,
(height() - diameter) / 2,
diameter, diameter);
SizeToPreferredSize();
}
+ bool OnMousePressed(const ui::MouseEvent& event) override {
+ if (GetEventHandlerForPoint(event.location()) != throbber_)
+ return false;
+
+ if (is_checked_)
+ throbber_->Start();
+ else
+ throbber_->Stop();
+ throbber_->SetChecked(!is_checked_);
+ is_checked_ = !is_checked_;
+ return true;
+ }
+
private:
Throbber* throbber_;
+ bool is_checked_;
DISALLOW_COPY_AND_ASSIGN(ThrobberView);
};
diff --git a/chromium/ui/views/examples/toggle_button_example.cc b/chromium/ui/views/examples/toggle_button_example.cc
new file mode 100644
index 00000000000..903fef24666
--- /dev/null
+++ b/chromium/ui/views/examples/toggle_button_example.cc
@@ -0,0 +1,34 @@
+// Copyright 2016 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/toggle_button_example.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/views/controls/button/toggle_button.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace views {
+namespace examples {
+
+ToggleButtonExample::ToggleButtonExample()
+ : ExampleBase("Toggle button"), button_(nullptr), count_(0) {}
+
+ToggleButtonExample::~ToggleButtonExample() {}
+
+void ToggleButtonExample::CreateExampleView(View* container) {
+ button_ = new ToggleButton(this);
+ BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 0, 0, 0);
+ layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
+ container->SetLayoutManager(layout);
+ container->AddChildView(button_);
+}
+
+void ToggleButtonExample::ButtonPressed(Button* sender,
+ const ui::Event& event) {
+ PrintStatus("Pressed! count: %d", ++count_);
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/toggle_button_example.h b/chromium/ui/views/examples/toggle_button_example.h
new file mode 100644
index 00000000000..50c4b9f6787
--- /dev/null
+++ b/chromium/ui/views/examples/toggle_button_example.h
@@ -0,0 +1,42 @@
+// Copyright 2016 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_TOGGLE_BUTTON_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_TOGGLE_BUTTON_EXAMPLE_H_
+
+#include "base/macros.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views {
+class ToggleButton;
+
+namespace examples {
+
+// ToggleButtonExample exercises a ToggleButton control.
+class VIEWS_EXAMPLES_EXPORT ToggleButtonExample : public ExampleBase,
+ public ButtonListener {
+ public:
+ ToggleButtonExample();
+ ~ToggleButtonExample() override;
+
+ // ExampleBase:
+ void CreateExampleView(View* container) override;
+
+ private:
+ // ButtonListener:
+ void ButtonPressed(Button* sender, const ui::Event& event) override;
+
+ // The only control in this test.
+ ToggleButton* button_;
+
+ int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ToggleButtonExample);
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_TOGGLE_BUTTON_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/tree_view_example.cc b/chromium/ui/views/examples/tree_view_example.cc
index 68f99e2fa8c..14d3dce2ac9 100644
--- a/chromium/ui/views/examples/tree_view_example.cc
+++ b/chromium/ui/views/examples/tree_view_example.cc
@@ -4,6 +4,7 @@
#include "ui/views/examples/tree_view_example.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
@@ -18,30 +19,27 @@ namespace examples {
TreeViewExample::TreeViewExample()
: ExampleBase("Tree View"),
- tree_view_(NULL),
- model_(new NodeType(ASCIIToUTF16("root"), 1)) {
-}
+ model_(base::MakeUnique<NodeType>(ASCIIToUTF16("root"), 1)) {}
TreeViewExample::~TreeViewExample() {
// Delete the view before the model.
- delete tree_view_;
- tree_view_ = NULL;
+ tree_view_.reset();
}
void TreeViewExample::CreateExampleView(View* container) {
// Add some sample data.
- NodeType* colors_node = new NodeType(ASCIIToUTF16("colors"), 1);
- model_.GetRoot()->Add(colors_node, 0);
- colors_node->Add(new NodeType(ASCIIToUTF16("red"), 1), 0);
- colors_node->Add(new NodeType(ASCIIToUTF16("green"), 1), 1);
- colors_node->Add(new NodeType(ASCIIToUTF16("blue"), 1), 2);
-
- NodeType* sheep_node = new NodeType(ASCIIToUTF16("sheep"), 1);
- model_.GetRoot()->Add(sheep_node, 0);
- sheep_node->Add(new NodeType(ASCIIToUTF16("Sheep 1"), 1), 0);
- sheep_node->Add(new NodeType(ASCIIToUTF16("Sheep 2"), 1), 1);
-
- tree_view_ = new TreeView();
+ NodeType* colors_node = model_.GetRoot()->Add(
+ base::MakeUnique<NodeType>(ASCIIToUTF16("colors"), 1), 0);
+ colors_node->Add(base::MakeUnique<NodeType>(ASCIIToUTF16("red"), 1), 0);
+ colors_node->Add(base::MakeUnique<NodeType>(ASCIIToUTF16("green"), 1), 1);
+ colors_node->Add(base::MakeUnique<NodeType>(ASCIIToUTF16("blue"), 1), 2);
+
+ NodeType* sheep_node = model_.GetRoot()->Add(
+ base::MakeUnique<NodeType>(ASCIIToUTF16("sheep"), 1), 0);
+ sheep_node->Add(base::MakeUnique<NodeType>(ASCIIToUTF16("Sheep 1"), 1), 0);
+ sheep_node->Add(base::MakeUnique<NodeType>(ASCIIToUTF16("Sheep 2"), 1), 1);
+
+ tree_view_ = base::MakeUnique<TreeView>();
tree_view_->set_context_menu_controller(this);
tree_view_->SetRootShown(false);
tree_view_->SetModel(&model_);
@@ -85,8 +83,9 @@ void TreeViewExample::AddNewNode() {
static_cast<NodeType*>(tree_view_->GetSelectedNode());
if (!selected_node)
selected_node = model_.GetRoot();
- NodeType* new_node = new NodeType(selected_node->GetTitle(), 1);
- model_.Add(selected_node, new_node, selected_node->child_count());
+ NodeType* new_node = model_.Add(
+ selected_node, base::MakeUnique<NodeType>(selected_node->GetTitle(), 1),
+ selected_node->child_count());
tree_view_->SetSelectedNode(new_node);
}
@@ -130,19 +129,15 @@ bool TreeViewExample::CanEdit(TreeView* tree_view,
void TreeViewExample::ShowContextMenuForView(View* source,
const gfx::Point& point,
ui::MenuSourceType source_type) {
- ui::SimpleMenuModel context_menu_model(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_runner_.reset(new MenuRunner(&context_menu_model, 0));
- if (context_menu_runner_->RunMenuAt(source->GetWidget(),
- NULL,
- gfx::Rect(point, gfx::Size()),
- MENU_ANCHOR_TOPLEFT,
- source_type) ==
- MenuRunner::MENU_DELETED) {
- return;
- }
+ context_menu_model_.reset(new 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_runner_.reset(
+ new MenuRunner(context_menu_model_.get(), MenuRunner::ASYNC));
+ context_menu_runner_->RunMenuAt(source->GetWidget(), nullptr,
+ gfx::Rect(point, gfx::Size()),
+ MENU_ANCHOR_TOPLEFT, source_type);
}
bool TreeViewExample::IsCommandIdChecked(int command_id) const {
@@ -153,12 +148,6 @@ bool TreeViewExample::IsCommandIdEnabled(int command_id) const {
return const_cast<TreeViewExample*>(this)->IsCommandIdEnabled(command_id);
}
-bool TreeViewExample::GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) {
- return false;
-}
-
void TreeViewExample::ExecuteCommand(int command_id, int event_flags) {
NodeType* selected_node =
static_cast<NodeType*>(tree_view_->GetSelectedNode());
diff --git a/chromium/ui/views/examples/tree_view_example.h b/chromium/ui/views/examples/tree_view_example.h
index fb0ccf93db6..9ec5e1058fd 100644
--- a/chromium/ui/views/examples/tree_view_example.h
+++ b/chromium/ui/views/examples/tree_view_example.h
@@ -13,6 +13,10 @@
#include "ui/views/controls/tree/tree_view_controller.h"
#include "ui/views/examples/example_base.h"
+namespace ui {
+class SimpleMenuModel;
+}
+
namespace views {
class LabelButton;
@@ -63,12 +67,10 @@ class VIEWS_EXAMPLES_EXPORT TreeViewExample
// SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
- bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) override;
void ExecuteCommand(int command_id, int event_flags) override;
// The tree view to be tested.
- TreeView* tree_view_;
+ std::unique_ptr<TreeView> tree_view_;
// Control buttons to modify the model.
LabelButton* add_;
@@ -79,6 +81,7 @@ class VIEWS_EXAMPLES_EXPORT TreeViewExample
ui::TreeNodeModel<NodeType> model_;
+ std::unique_ptr<ui::SimpleMenuModel> context_menu_model_;
std::unique_ptr<MenuRunner> context_menu_runner_;
DISALLOW_COPY_AND_ASSIGN(TreeViewExample);
diff --git a/chromium/ui/views/examples/vector_example.cc b/chromium/ui/views/examples/vector_example.cc
index 94f89729564..9802acffd82 100644
--- a/chromium/ui/views/examples/vector_example.cc
+++ b/chromium/ui/views/examples/vector_example.cc
@@ -4,8 +4,6 @@
#include "ui/views/examples/vector_example.h"
-#include <stddef.h>
-
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/macros.h"
@@ -15,8 +13,8 @@
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icons_public.h"
#include "ui/views/border.h"
-#include "ui/views/controls/button/blue_button.h"
#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
@@ -39,7 +37,8 @@ class VectorIconGallery : public View,
size_input_(new Textfield()),
color_input_(new Textfield()),
file_chooser_(new Textfield()),
- file_go_button_(new BlueButton(this, base::ASCIIToUTF16("Render"))),
+ file_go_button_(
+ MdTextButton::Create(this, base::ASCIIToUTF16("Render"))),
vector_id_(0),
// 36dp is one of the natural sizes for MD icons, and corresponds
// roughly to a 32dp usable area.
@@ -99,7 +98,7 @@ class VectorIconGallery : public View,
void ContentsChanged(Textfield* sender,
const base::string16& new_contents) override {
if (sender == size_input_) {
- if (base::StringToSizeT(new_contents, &size_))
+ if (base::StringToInt(new_contents, &size_) && (size_ > 0))
UpdateImage();
else
size_input_->SetText(base::string16());
@@ -128,6 +127,12 @@ class VectorIconGallery : public View,
base::FilePath path(file_chooser_->text());
#endif
base::ReadFileToString(path, &contents);
+ // Skip over comments.
+ for (size_t slashes = contents.find("//"); slashes != std::string::npos;
+ slashes = contents.find("//")) {
+ size_t eol = contents.find("\n", slashes);
+ contents.erase(slashes, eol - slashes);
+ }
image_view_->SetImage(
gfx::CreateVectorIconFromSource(contents, size_, color_));
}
@@ -147,7 +152,7 @@ class VectorIconGallery : public View,
Button* file_go_button_;
int vector_id_;
- size_t size_;
+ int size_;
SkColor color_;
DISALLOW_COPY_AND_ASSIGN(VectorIconGallery);
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index da6ededa69e..a655eafcc45 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -15,7 +15,6 @@
#include "ui/base/accelerators/accelerator.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/accessible_pane_view.h"
-#include "ui/views/controls/button/label_button.h"
#include "ui/views/focus/focus_manager_factory.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/test/focus_manager_test.h"
@@ -482,21 +481,6 @@ class FocusManagerDtorTest : public FocusManagerTest {
DISALLOW_COPY_AND_ASSIGN(TestFocusManagerFactory);
};
- class LabelButtonDtorTracked : public LabelButton {
- public:
- LabelButtonDtorTracked(const base::string16& text,
- DtorTrackVector* dtor_tracker)
- : LabelButton(NULL, text),
- dtor_tracker_(dtor_tracker) {
- SetStyle(STYLE_BUTTON);
- };
- ~LabelButtonDtorTracked() override {
- dtor_tracker_->push_back("LabelButtonDtorTracked");
- }
-
- DtorTrackVector* dtor_tracker_;
- };
-
class WindowDtorTracked : public Widget {
public:
explicit WindowDtorTracked(DtorTrackVector* dtor_tracker)
diff --git a/chromium/ui/views/focus/focus_traversal_unittest.cc b/chromium/ui/views/focus/focus_traversal_unittest.cc
index 4bc43614590..823904576c7 100644
--- a/chromium/ui/views/focus/focus_traversal_unittest.cc
+++ b/chromium/ui/views/focus/focus_traversal_unittest.cc
@@ -13,6 +13,7 @@
#include "ui/views/border.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/button/radio_button.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/label.h"
@@ -375,8 +376,7 @@ void FocusTraversalTest::InitContentView() {
y += label_height + gap_between_labels;
- LabelButton* button = new LabelButton(NULL, ASCIIToUTF16("Click me"));
- button->SetStyle(Button::STYLE_BUTTON);
+ LabelButton* button = MdTextButton::Create(NULL, ASCIIToUTF16("Click me"));
button->SetBounds(label_x, y + 10, 80, 30);
button->set_id(kFruitButtonID);
left_container_->AddChildView(button);
@@ -471,22 +471,19 @@ void FocusTraversalTest::InitContentView() {
y = 250;
int width = 60;
- button = new LabelButton(NULL, ASCIIToUTF16("OK"));
- button->SetStyle(Button::STYLE_BUTTON);
+ button = MdTextButton::Create(NULL, ASCIIToUTF16("OK"));
button->set_id(kOKButtonID);
button->SetIsDefault(true);
GetContentsView()->AddChildView(button);
button->SetBounds(150, y, width, 30);
- button = new LabelButton(NULL, ASCIIToUTF16("Cancel"));
- button->SetStyle(Button::STYLE_BUTTON);
+ button = MdTextButton::Create(NULL, ASCIIToUTF16("Cancel"));
button->set_id(kCancelButtonID);
GetContentsView()->AddChildView(button);
button->SetBounds(220, y, width, 30);
- button = new LabelButton(NULL, ASCIIToUTF16("Help"));
- button->SetStyle(Button::STYLE_BUTTON);
+ button = MdTextButton::Create(NULL, ASCIIToUTF16("Help"));
button->set_id(kHelpButtonID);
GetContentsView()->AddChildView(button);
button->SetBounds(290, y, width, 30);
@@ -539,8 +536,7 @@ void FocusTraversalTest::InitContentView() {
text_field->SetBounds(10, 10, 100, 20);
text_field->set_id(kSearchTextfieldID);
- button = new LabelButton(NULL, ASCIIToUTF16("Search"));
- button->SetStyle(Button::STYLE_BUTTON);
+ button = MdTextButton::Create(NULL, ASCIIToUTF16("Search"));
contents->AddChildView(button);
button->SetBounds(112, 5, 60, 30);
button->set_id(kSearchButtonID);
@@ -563,13 +559,11 @@ void FocusTraversalTest::InitContentView() {
contents->SetFocusBehavior(View::FocusBehavior::ALWAYS);
contents->set_background(Background::CreateSolidBackground(SK_ColorBLUE));
contents->set_id(kThumbnailContainerID);
- button = new LabelButton(NULL, ASCIIToUTF16("Star"));
- button->SetStyle(Button::STYLE_BUTTON);
+ button = MdTextButton::Create(NULL, ASCIIToUTF16("Star"));
contents->AddChildView(button);
button->SetBounds(5, 5, 50, 30);
button->set_id(kThumbnailStarID);
- button = new LabelButton(NULL, ASCIIToUTF16("SuperStar"));
- button->SetStyle(Button::STYLE_BUTTON);
+ button = MdTextButton::Create(NULL, ASCIIToUTF16("SuperStar"));
contents->AddChildView(button);
button->SetBounds(60, 5, 100, 30);
button->set_id(kThumbnailSuperStarID);
diff --git a/chromium/ui/views/focus/view_storage.cc b/chromium/ui/views/focus/view_storage.cc
index 204b31d0892..4c519f3f8cb 100644
--- a/chromium/ui/views/focus/view_storage.cc
+++ b/chromium/ui/views/focus/view_storage.cc
@@ -8,7 +8,6 @@
#include "base/logging.h"
#include "base/memory/singleton.h"
-#include "base/stl_util.h"
namespace views {
@@ -20,10 +19,7 @@ ViewStorage* ViewStorage::GetInstance() {
ViewStorage::ViewStorage() : view_storage_next_id_(0) {
}
-ViewStorage::~ViewStorage() {
- STLDeleteContainerPairSecondPointers(view_to_ids_.begin(),
- view_to_ids_.end());
-}
+ViewStorage::~ViewStorage() {}
int ViewStorage::CreateStorageID() {
return view_storage_next_id_++;
@@ -31,31 +27,20 @@ int ViewStorage::CreateStorageID() {
void ViewStorage::StoreView(int storage_id, View* view) {
DCHECK(view);
- std::map<int, View*>::iterator iter = id_to_view_.find(storage_id);
- if (iter != id_to_view_.end()) {
+ if (id_to_view_.find(storage_id) != id_to_view_.end()) {
NOTREACHED();
RemoveView(storage_id);
}
id_to_view_[storage_id] = view;
-
- std::vector<int>* ids = NULL;
- std::map<View*, std::vector<int>*>::iterator id_iter =
- view_to_ids_.find(view);
- if (id_iter == view_to_ids_.end()) {
- ids = new std::vector<int>();
- view_to_ids_[view] = ids;
- } else {
- ids = id_iter->second;
- }
- ids->push_back(storage_id);
+ view_to_ids_[view].push_back(storage_id);
}
View* ViewStorage::RetrieveView(int storage_id) {
- std::map<int, View*>::iterator iter = id_to_view_.find(storage_id);
+ auto iter = id_to_view_.find(storage_id);
if (iter == id_to_view_.end())
- return NULL;
+ return nullptr;
return iter->second;
}
@@ -65,22 +50,21 @@ void ViewStorage::RemoveView(int storage_id) {
void ViewStorage::ViewRemoved(View* removed) {
// Let's first retrieve the ids for that view.
- std::map<View*, std::vector<int>*>::iterator ids_iter =
- view_to_ids_.find(removed);
+ auto ids_iter = view_to_ids_.find(removed);
if (ids_iter == view_to_ids_.end()) {
// That view is not in the view storage.
return;
}
- std::vector<int>* ids = ids_iter->second;
- DCHECK(!ids->empty());
- EraseView((*ids)[0], true);
+ const std::vector<int>& ids = ids_iter->second;
+ DCHECK(!ids.empty());
+ EraseView(ids[0], true);
}
void ViewStorage::EraseView(int storage_id, bool remove_all_ids) {
// Remove the view from id_to_view_location_.
- std::map<int, View*>::iterator view_iter = id_to_view_.find(storage_id);
+ auto view_iter = id_to_view_.find(storage_id);
if (view_iter == id_to_view_.end())
return;
@@ -88,28 +72,20 @@ void ViewStorage::EraseView(int storage_id, bool remove_all_ids) {
id_to_view_.erase(view_iter);
// Also update view_to_ids_.
- std::map<View*, std::vector<int>*>::iterator ids_iter =
- view_to_ids_.find(view);
+ auto ids_iter = view_to_ids_.find(view);
DCHECK(ids_iter != view_to_ids_.end());
- std::vector<int>* ids = ids_iter->second;
+ std::vector<int>& ids = ids_iter->second;
if (remove_all_ids) {
- for (size_t i = 0; i < ids->size(); ++i) {
- view_iter = id_to_view_.find((*ids)[i]);
- if (view_iter != id_to_view_.end())
- id_to_view_.erase(view_iter);
- }
- ids->clear();
- } else {
- std::vector<int>::iterator id_iter =
- std::find(ids->begin(), ids->end(), storage_id);
- DCHECK(id_iter != ids->end());
- ids->erase(id_iter);
- }
-
- if (ids->empty()) {
- delete ids;
+ for (int id : ids)
+ id_to_view_.erase(id);
view_to_ids_.erase(ids_iter);
+ } else if (ids.size() == 1) {
+ view_to_ids_.erase(ids_iter);
+ } else {
+ auto id_iter = std::find(ids.begin(), ids.end(), storage_id);
+ DCHECK(id_iter != ids.end());
+ ids.erase(id_iter);
}
}
diff --git a/chromium/ui/views/focus/view_storage.h b/chromium/ui/views/focus/view_storage.h
index d543415e490..73235c1c3f7 100644
--- a/chromium/ui/views/focus/view_storage.h
+++ b/chromium/ui/views/focus/view_storage.h
@@ -69,7 +69,7 @@ class VIEWS_EXPORT ViewStorage {
std::map<int, View*> id_to_view_;
// Association View to id, used to speed up view notification removal.
- std::map<View*, std::vector<int>*> view_to_ids_;
+ std::map<View*, std::vector<int>> view_to_ids_;
DISALLOW_COPY_AND_ASSIGN(ViewStorage);
};
diff --git a/chromium/ui/views/layout/grid_layout.cc b/chromium/ui/views/layout/grid_layout.cc
index c79b600ffef..77a567ca514 100644
--- a/chromium/ui/views/layout/grid_layout.cc
+++ b/chromium/ui/views/layout/grid_layout.cc
@@ -374,7 +374,7 @@ ColumnSet::ColumnSet(int id) : id_(id) {
}
ColumnSet::~ColumnSet() {
- STLDeleteElements(&columns_);
+ base::STLDeleteElements(&columns_);
}
void ColumnSet::AddPaddingColumn(float resize_percent, int width) {
@@ -662,9 +662,9 @@ GridLayout::GridLayout(View* host)
}
GridLayout::~GridLayout() {
- STLDeleteElements(&column_sets_);
- STLDeleteElements(&view_states_);
- STLDeleteElements(&rows_);
+ base::STLDeleteElements(&column_sets_);
+ base::STLDeleteElements(&view_states_);
+ base::STLDeleteElements(&rows_);
}
// static
@@ -937,8 +937,8 @@ void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
LayoutElement::CalculateLocationsFromSize(&rows_);
// We now know the preferred height, set it here.
- pref->set_height(rows_[rows_.size() - 1]->Location() +
- rows_[rows_.size() - 1]->Size() + insets_.height());
+ pref->set_height(rows_.back()->Location() + rows_.back()->Size() +
+ insets_.height());
if (layout && height != pref->height()) {
// We're doing a layout, and the height differs from the preferred height,
diff --git a/chromium/ui/views/layout/grid_layout.h b/chromium/ui/views/layout/grid_layout.h
index 856fb6f1a44..c82f3a8db6a 100644
--- a/chromium/ui/views/layout/grid_layout.h
+++ b/chromium/ui/views/layout/grid_layout.h
@@ -18,7 +18,7 @@
// define the structure of the Grid first, then add the Views.
// The following creates a trivial grid with two columns separated by
// a column with padding:
-// ColumnSet* columns = layout->AddColumnSet(0); // Give this column an
+// ColumnSet* columns = layout->AddColumnSet(0); // Give this column set an
// // identifier of 0.
// columns->AddColumn(FILL, // Views are horizontally resized to fill column.
// FILL, // Views starting in this column are vertically
diff --git a/chromium/ui/views/linux_ui/linux_ui.gyp b/chromium/ui/views/linux_ui/linux_ui.gyp
deleted file mode 100644
index 5ba78e52baf..00000000000
--- a/chromium/ui/views/linux_ui/linux_ui.gyp
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- 'target_name': 'linux_ui',
- 'type': '<(component)',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../../skia/skia.gyp:skia',
- '../base/ui_base.gyp:ui_base',
- '../native_theme/native_theme.gyp:native_theme',
- '../resources/ui_resources.gyp:ui_resources',
- ],
- 'defines': [
- 'LINUX_UI_IMPLEMENTATION',
- ],
- 'sources': [
- 'linux_ui.cc',
- 'linux_ui.h',
- 'linux_ui_export.h',
- 'status_icon_linux.cc',
- 'status_icon_linux.h',
- ],
- },
- ],
-}
diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h
index 86a3d5a1bb0..bbbaf572b72 100644
--- a/chromium/ui/views/linux_ui/linux_ui.h
+++ b/chromium/ui/views/linux_ui/linux_ui.h
@@ -84,11 +84,8 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
// unconditionally.
virtual void MaterialDesignControllerReady() = 0;
- // Returns a themed image per theme_provider.h
- virtual gfx::Image GetThemeImageNamed(int id) const = 0;
virtual bool GetTint(int id, color_utils::HSL* tint) const = 0;
virtual bool GetColor(int id, SkColor* color) const = 0;
- virtual bool HasCustomImage(int id) const = 0;
// Returns the preferences that we pass to WebKit.
virtual SkColor GetFocusRingColor() const = 0;
diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn
index ff5631e3242..94d53fb62c4 100644
--- a/chromium/ui/views/mus/BUILD.gn
+++ b/chromium/ui/views/mus/BUILD.gn
@@ -4,15 +4,11 @@
import("//build/config/features.gni")
import("//build/config/ui.gni")
-import("//mojo/public/mojo_application.gni")
-import("//mojo/public/mojo_application_manifest.gni")
+import("//services/shell/public/cpp/service.gni")
+import("//services/shell/public/service_manifest.gni")
import("//testing/test.gni")
import("//tools/grit/repack.gni")
-gypi = exec_script("//build/gypi_to_gn.py",
- [ rebase_path("../views.gyp") ],
- "scope",
- [ "../views.gyp" ])
component("mus") {
output_name = "ui_views_mus_lib"
@@ -21,20 +17,26 @@ component("mus") {
"aura_init.h",
"clipboard_mus.cc",
"clipboard_mus.h",
- "display_list.cc",
- "display_list.h",
+ "drag_drop_client_mus.cc",
+ "drag_drop_client_mus.h",
+ "drop_target_mus.cc",
+ "drop_target_mus.h",
"input_method_mus.cc",
"input_method_mus.h",
"mus_export.h",
"native_widget_mus.cc",
"native_widget_mus.h",
+ "os_exchange_data_provider_mus.cc",
+ "os_exchange_data_provider_mus.h",
+ "pointer_watcher_event_router.cc",
+ "pointer_watcher_event_router.h",
"screen_mus.cc",
"screen_mus.h",
"screen_mus_delegate.h",
- "surface_binding.cc",
- "surface_binding.h",
"surface_context_factory.cc",
"surface_context_factory.h",
+ "text_input_client_impl.cc",
+ "text_input_client_impl.h",
"window_manager_connection.cc",
"window_manager_connection.h",
"window_manager_constants_converters.cc",
@@ -49,7 +51,7 @@ component("mus") {
public_deps = [
":resources",
- "//components/mus/public/cpp",
+ "//services/ui/public/cpp",
"//ui/aura",
]
deps = [
@@ -58,22 +60,19 @@ component("mus") {
"//base/third_party/dynamic_annotations",
"//cc",
"//cc/surfaces",
- "//components/bitmap_uploader",
- "//components/mus/common:mus_common",
- "//components/mus/gles2:lib",
- "//components/mus/public/cpp",
- "//components/mus/public/interfaces",
"//mojo/common",
"//mojo/public/cpp/bindings",
+ "//net",
"//services/catalog/public/cpp",
"//services/shell/public/cpp",
"//services/shell/public/interfaces",
+ "//services/ui/public/cpp",
+ "//services/ui/public/interfaces",
"//skia",
"//third_party/icu",
"//ui/aura",
"//ui/compositor",
"//ui/display",
- "//ui/display/mojo",
"//ui/events",
"//ui/events:events_base",
"//ui/gfx",
@@ -118,7 +117,7 @@ group("for_mojo_application") {
]
}
-source_set("test_support") {
+static_library("test_support") {
testonly = true
sources = [
@@ -131,10 +130,10 @@ source_set("test_support") {
":mus",
"//base",
"//base/test:test_support",
- "//components/mus/common:mus_common",
"//services/shell/background:lib",
"//services/shell/background/tests:test_support",
"//services/shell/public/cpp:sources",
+ "//services/ui/common:mus_common",
"//testing/gtest",
"//ui/aura",
"//ui/gl:test_support",
@@ -152,33 +151,16 @@ source_set("test_support") {
test("views_mus_unittests") {
testonly = true
- configs += [ "//build/config:precompiled_headers" ]
-
sources = [
- "display_list_unittest.cc",
+ "input_method_mus_unittest.cc",
"native_widget_mus_unittest.cc",
+ "os_exchange_data_provider_mus_unittest.cc",
+ "pointer_watcher_event_router_unittest.cc",
"run_all_unittests_mus.cc",
"screen_mus_unittest.cc",
- "window_manager_connection_unittest.cc",
]
- sources += rebase_path(gypi.views_unittests_sources, ".", "//ui/views")
- sources += rebase_path(gypi.views_unittests_aura_sources, ".", "//ui/views")
-
- sources -= [
- # Mus has its own runner.
- "../run_all_unittests_main.cc",
-
- # EventGenerator doesn't work well with IME in mus.
- # crbug.com/615033 crbug.com/548407
- "../controls/textfield/textfield_unittest.cc",
-
- # Tooltips. crbug.com/599558
- "../corewm/tooltip_controller_unittest.cc",
-
- # Some of the tests need drag-drop support. crbug.com/614037
- "../touchui/touch_selection_controller_impl_unittest.cc",
- ]
+ configs += [ "//build/config:precompiled_headers" ]
deps = [
":mus",
@@ -187,10 +169,11 @@ test("views_mus_unittests") {
"//base:i18n",
"//base/test:test_support",
"//cc",
- "//components/mus/public/cpp",
- "//components/mus/public/cpp/tests:unittest_support",
- "//components/mus/public/interfaces",
+ "//net",
"//services/shell/background:main", # Provides main().
+ "//services/ui/public/cpp",
+ "//services/ui/public/cpp/tests:unittest_support",
+ "//services/ui/public/interfaces",
"//skia",
"//testing/gtest",
"//third_party/icu",
@@ -212,13 +195,15 @@ test("views_mus_unittests") {
"//ui/touch_selection",
"//ui/views",
"//ui/views:test_support_internal",
+ "//ui/views:views_unittests_sources",
"//ui/wm",
"//url",
]
data_deps = [
":unittests_manifest",
- "//components/mus/test_wm",
+ "//services/ui/ime/test_ime_driver",
+ "//services/ui/test_wm",
]
if (is_win) {
@@ -252,8 +237,6 @@ test("views_mus_unittests") {
test("views_mus_interactive_ui_tests") {
testonly = true
- configs += [ "//build/config:precompiled_headers" ]
-
sources = [
"../widget/widget_interactive_uitest.cc",
"clipboard_unittest.cc",
@@ -281,7 +264,7 @@ test("views_mus_interactive_ui_tests") {
data_deps = [
":interactive_ui_tests_manifest",
- "//components/mus/test_wm",
+ "//services/ui/test_wm",
]
if (is_win) {
@@ -298,14 +281,14 @@ test("views_mus_interactive_ui_tests") {
}
}
-mojo_application_manifest("unittests_manifest") {
+service_manifest("unittests_manifest") {
type = "exe"
- application_name = "views_mus_unittests"
+ name = "views_mus_unittests"
source = "unittests_manifest.json"
}
-mojo_application_manifest("interactive_ui_tests_manifest") {
+service_manifest("interactive_ui_tests_manifest") {
type = "exe"
- application_name = "views_mus_interactive_ui_tests"
+ name = "views_mus_interactive_ui_tests"
source = "interactive_ui_tests_manifest.json"
}
diff --git a/chromium/ui/views/mus/DEPS b/chromium/ui/views/mus/DEPS
index 84766d2fe9a..83723b80ea5 100644
--- a/chromium/ui/views/mus/DEPS
+++ b/chromium/ui/views/mus/DEPS
@@ -2,15 +2,15 @@ include_rules = [
"+cc",
"-cc/blink",
"+components/font_service/public",
- "+components/bitmap_uploader",
"+components/gpu",
- "+components/mus",
+ "+net",
"+mojo/cc",
"+mojo/common",
"+mojo/converters",
"+mojo/public",
"+services/catalog/public",
"+services/shell/public",
+ "+services/ui",
"+skia",
"+ui/aura",
"+ui/base",
diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc
index 5335188700b..7499e8629f0 100644
--- a/chromium/ui/views/mus/aura_init.cc
+++ b/chromium/ui/views/mus/aura_init.cc
@@ -19,7 +19,7 @@
#include "ui/base/ui_base_paths.h"
#include "ui/views/views_delegate.h"
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
+#if defined(OS_LINUX)
#include "components/font_service/public/cpp/font_loader.h"
#endif
@@ -27,12 +27,6 @@ namespace views {
namespace {
-std::set<std::string> GetResourcePaths(const std::string& resource_file) {
- std::set<std::string> paths;
- paths.insert(resource_file);
- return paths;
-}
-
class MusViewsDelegate : public ViewsDelegate {
public:
MusViewsDelegate() {}
@@ -52,18 +46,30 @@ class MusViewsDelegate : public ViewsDelegate {
} // namespace
AuraInit::AuraInit(shell::Connector* connector,
- const std::string& resource_file)
+ const std::string& resource_file,
+ const std::string& resource_file_200)
: resource_file_(resource_file),
+ resource_file_200_(resource_file_200),
env_(aura::Env::CreateInstance()),
views_delegate_(new MusViewsDelegate) {
ui::MaterialDesignController::Initialize();
InitializeResources(connector);
+// Initialize the skia font code to go ask fontconfig underneath.
+#if defined(OS_LINUX)
+ font_loader_ = sk_make_sp<font_service::FontLoader>(connector);
+ SkFontConfigInterface::SetGlobal(font_loader_.get());
+#endif
+
+ // There is a bunch of static state in gfx::Font, by running this now,
+ // before any other apps load, we ensure all the state is set up.
+ gfx::Font();
+
ui::InitializeInputMethodForTesting();
}
AuraInit::~AuraInit() {
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
+#if defined(OS_LINUX)
if (font_loader_.get()) {
SkFontConfigInterface::SetGlobal(nullptr);
// FontLoader is ref counted. We need to explicitly shutdown the background
@@ -75,13 +81,19 @@ AuraInit::~AuraInit() {
}
void AuraInit::InitializeResources(shell::Connector* connector) {
+ // Resources may have already been initialized (e.g. when 'chrome --mash' is
+ // used to launch the current app).
if (ui::ResourceBundle::HasSharedInstance())
return;
+
+ std::set<std::string> resource_paths({resource_file_});
+ if (!resource_file_200_.empty())
+ resource_paths.insert(resource_file_200_);
+
catalog::ResourceLoader loader;
filesystem::mojom::DirectoryPtr directory;
- connector->ConnectToInterface("mojo:catalog", &directory);
- CHECK(loader.OpenFiles(std::move(directory),
- GetResourcePaths(resource_file_)));
+ connector->ConnectToInterface("service:catalog", &directory);
+ CHECK(loader.OpenFiles(std::move(directory), resource_paths));
ui::RegisterPathProvider();
base::File pak_file = loader.TakeFile(resource_file_);
base::File pak_file_2 = pak_file.Duplicate();
@@ -89,16 +101,9 @@ void AuraInit::InitializeResources(shell::Connector* connector) {
std::move(pak_file), base::MemoryMappedFile::Region::kWholeFile);
ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
std::move(pak_file_2), ui::SCALE_FACTOR_100P);
-
-// Initialize the skia font code to go ask fontconfig underneath.
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
- font_loader_ = sk_make_sp<font_service::FontLoader>(connector);
- SkFontConfigInterface::SetGlobal(font_loader_.get());
-#endif
-
- // There is a bunch of static state in gfx::Font, by running this now,
- // before any other apps load, we ensure all the state is set up.
- gfx::Font();
+ if (!resource_file_200_.empty())
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
+ loader.TakeFile(resource_file_200_), ui::SCALE_FACTOR_200P);
}
} // namespace views
diff --git a/chromium/ui/views/mus/aura_init.h b/chromium/ui/views/mus/aura_init.h
index 9330845f17b..ac828327e98 100644
--- a/chromium/ui/views/mus/aura_init.h
+++ b/chromium/ui/views/mus/aura_init.h
@@ -32,17 +32,24 @@ class ViewsDelegate;
// |resource_file| is the path to the apk file containing the resources.
class VIEWS_MUS_EXPORT AuraInit {
public:
- AuraInit(shell::Connector* connector, const std::string& resource_file);
+ // |resource_file| is the file to load strings and 1x icons from.
+ // |resource_file_200| can be an empty string, otherwise it is the file to
+ // load 2x icons from.
+ AuraInit(shell::Connector* connector,
+ const std::string& resource_file,
+ const std::string& resource_file_200 = std::string());
+
~AuraInit();
private:
void InitializeResources(shell::Connector* connector);
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
+#if defined(OS_LINUX)
sk_sp<font_service::FontLoader> font_loader_;
#endif
const std::string resource_file_;
+ const std::string resource_file_200_;
std::unique_ptr<aura::Env> env_;
std::unique_ptr<ViewsDelegate> views_delegate_;
diff --git a/chromium/ui/views/mus/clipboard_mus.cc b/chromium/ui/views/mus/clipboard_mus.cc
index 7561c42db49..5738e932f09 100644
--- a/chromium/ui/views/mus/clipboard_mus.cc
+++ b/chromium/ui/views/mus/clipboard_mus.cc
@@ -4,6 +4,10 @@
#include "ui/views/mus/clipboard_mus.h"
+#include <string>
+#include <utility>
+#include <vector>
+
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -17,18 +21,19 @@
namespace views {
namespace {
-mus::mojom::Clipboard::Type GetType(ui::ClipboardType type) {
+ui::mojom::Clipboard::Type GetType(ui::ClipboardType type) {
switch (type) {
case ui::CLIPBOARD_TYPE_COPY_PASTE:
- return mus::mojom::Clipboard::Type::COPY_PASTE;
+ return ui::mojom::Clipboard::Type::COPY_PASTE;
case ui::CLIPBOARD_TYPE_SELECTION:
- return mus::mojom::Clipboard::Type::SELECTION;
+ return ui::mojom::Clipboard::Type::SELECTION;
case ui::CLIPBOARD_TYPE_DRAG:
- return mus::mojom::Clipboard::Type::DRAG;
+ // Only OSX uses a drag clipboard.
+ break;
}
NOTREACHED();
- return mus::mojom::Clipboard::Type::COPY_PASTE;
+ return ui::mojom::Clipboard::Type::COPY_PASTE;
}
// The source URL of copied HTML.
@@ -41,7 +46,7 @@ ClipboardMus::ClipboardMus() {}
ClipboardMus::~ClipboardMus() {}
void ClipboardMus::Init(shell::Connector* connector) {
- connector->ConnectToInterface("mojo:mus", &clipboard_);
+ connector->ConnectToInterface("service:ui", &clipboard_);
}
// TODO(erg): This isn't optimal. It would be better to move the entire
@@ -49,19 +54,19 @@ void ClipboardMus::Init(shell::Connector* connector) {
// change.
mojo::String ClipboardMus::GetMimeTypeFor(const FormatType& format) {
if (format.Equals(GetUrlFormatType()) || format.Equals(GetUrlWFormatType()))
- return mus::mojom::kMimeTypeURIList;
+ return ui::mojom::kMimeTypeURIList;
if (format.Equals(GetMozUrlFormatType()))
- return mus::mojom::kMimeTypeMozillaURL;
+ return ui::mojom::kMimeTypeMozillaURL;
if (format.Equals(GetPlainTextFormatType()) ||
format.Equals(GetPlainTextWFormatType())) {
- return mus::mojom::kMimeTypeText;
+ return ui::mojom::kMimeTypeText;
}
if (format.Equals(GetHtmlFormatType()))
- return mus::mojom::kMimeTypeHTML;
+ return ui::mojom::kMimeTypeHTML;
if (format.Equals(GetRtfFormatType()))
- return mus::mojom::kMimeTypeRTF;
+ return ui::mojom::kMimeTypeRTF;
if (format.Equals(GetBitmapFormatType()))
- return mus::mojom::kMimeTypePNG;
+ return ui::mojom::kMimeTypePNG;
if (format.Equals(GetWebKitSmartPasteFormatType()))
return kMimeTypeWebkitSmartPaste;
if (format.Equals(GetWebCustomDataFormatType()))
@@ -78,7 +83,7 @@ mojo::String ClipboardMus::GetMimeTypeFor(const FormatType& format) {
bool ClipboardMus::HasMimeType(const mojo::Array<mojo::String>& available_types,
const std::string& type) const {
- return ContainsValue(available_types, type);
+ return base::ContainsValue(available_types, type);
}
uint64_t ClipboardMus::GetSequenceNumber(ui::ClipboardType type) const {
@@ -98,7 +103,7 @@ bool ClipboardMus::IsFormatAvailable(const FormatType& format,
&available_types);
mojo::String format_in_mime = GetMimeTypeFor(format);
- return ContainsValue(available_types, format_in_mime);
+ return base::ContainsValue(available_types, format_in_mime);
}
void ClipboardMus::Clear(ui::ClipboardType type) {
@@ -120,14 +125,14 @@ void ClipboardMus::ReadAvailableTypes(ui::ClipboardType type,
&available_types);
types->clear();
- if (HasMimeType(available_types, mus::mojom::kMimeTypeText))
- types->push_back(base::UTF8ToUTF16(mus::mojom::kMimeTypeText));
- if (HasMimeType(available_types, mus::mojom::kMimeTypeHTML))
- types->push_back(base::UTF8ToUTF16(mus::mojom::kMimeTypeHTML));
- if (HasMimeType(available_types, mus::mojom::kMimeTypeRTF))
- types->push_back(base::UTF8ToUTF16(mus::mojom::kMimeTypeRTF));
- if (HasMimeType(available_types, mus::mojom::kMimeTypePNG))
- types->push_back(base::UTF8ToUTF16(mus::mojom::kMimeTypePNG));
+ if (HasMimeType(available_types, ui::mojom::kMimeTypeText))
+ types->push_back(base::UTF8ToUTF16(ui::mojom::kMimeTypeText));
+ if (HasMimeType(available_types, ui::mojom::kMimeTypeHTML))
+ types->push_back(base::UTF8ToUTF16(ui::mojom::kMimeTypeHTML));
+ if (HasMimeType(available_types, ui::mojom::kMimeTypeRTF))
+ types->push_back(base::UTF8ToUTF16(ui::mojom::kMimeTypeRTF));
+ if (HasMimeType(available_types, ui::mojom::kMimeTypePNG))
+ types->push_back(base::UTF8ToUTF16(ui::mojom::kMimeTypePNG));
if (HasMimeType(available_types, kMimeTypeWebCustomData)) {
mojo::Array<uint8_t> custom_data;
@@ -147,7 +152,7 @@ void ClipboardMus::ReadText(ui::ClipboardType type,
mojo::Array<uint8_t> text_data;
uint64_t sequence_number = 0;
if (clipboard_->ReadClipboardData(GetType(type),
- mojo::String(mus::mojom::kMimeTypeText),
+ mojo::String(ui::mojom::kMimeTypeText),
&sequence_number, &text_data)) {
std::string text = text_data.To<std::string>();
*result = base::UTF8ToUTF16(text);
@@ -160,7 +165,7 @@ void ClipboardMus::ReadAsciiText(ui::ClipboardType type,
mojo::Array<uint8_t> text_data;
uint64_t sequence_number = 0;
if (clipboard_->ReadClipboardData(GetType(type),
- mojo::String(mus::mojom::kMimeTypeText),
+ mojo::String(ui::mojom::kMimeTypeText),
&sequence_number, &text_data)) {
*result = text_data.To<std::string>();
}
@@ -181,7 +186,7 @@ void ClipboardMus::ReadHTML(ui::ClipboardType type,
mojo::Array<uint8_t> html_data;
uint64_t sequence_number = 0;
if (clipboard_->ReadClipboardData(GetType(type),
- mojo::String(mus::mojom::kMimeTypeHTML),
+ mojo::String(ui::mojom::kMimeTypeHTML),
&sequence_number, &html_data)) {
*markup = base::UTF8ToUTF16(html_data.To<std::string>());
*fragment_end = static_cast<uint32_t>(markup->length());
@@ -200,9 +205,9 @@ void ClipboardMus::ReadRTF(ui::ClipboardType type, std::string* result) const {
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
mojo::Array<uint8_t> rtf_data;
uint64_t sequence_number = 0;
- if (clipboard_->ReadClipboardData(
- GetType(type), mojo::String(mus::mojom::kMimeTypeRTF),
- &sequence_number, &rtf_data)) {
+ if (clipboard_->ReadClipboardData(GetType(type),
+ mojo::String(ui::mojom::kMimeTypeRTF),
+ &sequence_number, &rtf_data)) {
*result = rtf_data.To<std::string>();
}
}
@@ -211,9 +216,9 @@ SkBitmap ClipboardMus::ReadImage(ui::ClipboardType type) const {
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
mojo::Array<uint8_t> data;
uint64_t sequence_number = 0;
- if (clipboard_->ReadClipboardData(
- GetType(type), mojo::String(mus::mojom::kMimeTypePNG),
- &sequence_number, &data)) {
+ if (clipboard_->ReadClipboardData(GetType(type),
+ mojo::String(ui::mojom::kMimeTypePNG),
+ &sequence_number, &data)) {
SkBitmap bitmap;
if (gfx::PNGCodec::Decode(&data.front(), data.size(), &bitmap))
return SkBitmap(bitmap);
@@ -246,16 +251,17 @@ void ClipboardMus::ReadData(const FormatType& format,
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
mojo::Array<uint8_t> data;
uint64_t sequence_number = 0;
- if (clipboard_->ReadClipboardData(mus::mojom::Clipboard::Type::COPY_PASTE,
- GetMimeTypeFor(format),
- &sequence_number, &data)) {
+ if (clipboard_->ReadClipboardData(ui::mojom::Clipboard::Type::COPY_PASTE,
+ GetMimeTypeFor(format), &sequence_number,
+ &data)) {
*result = data.To<std::string>();
}
}
void ClipboardMus::WriteObjects(ui::ClipboardType type,
const ObjectMap& objects) {
- current_clipboard_.reset(new mojo::Map<mojo::String, mojo::Array<uint8_t>>);
+ current_clipboard_ =
+ base::MakeUnique<mojo::Map<mojo::String, mojo::Array<uint8_t>>>();
for (const auto& p : objects)
DispatchObject(static_cast<ObjectType>(p.first), p.second);
@@ -270,7 +276,7 @@ void ClipboardMus::WriteObjects(ui::ClipboardType type,
void ClipboardMus::WriteText(const char* text_data, size_t text_len) {
DCHECK(current_clipboard_);
current_clipboard_->insert(
- mus::mojom::kMimeTypeText,
+ ui::mojom::kMimeTypeText,
mojo::Array<uint8_t>::From(base::StringPiece(text_data, text_len)));
}
@@ -280,7 +286,7 @@ void ClipboardMus::WriteHTML(const char* markup_data,
size_t url_len) {
DCHECK(current_clipboard_);
current_clipboard_->insert(
- mus::mojom::kMimeTypeHTML,
+ ui::mojom::kMimeTypeHTML,
mojo::Array<uint8_t>::From(base::StringPiece(markup_data, markup_len)));
if (url_len > 0) {
current_clipboard_->insert(
@@ -292,7 +298,7 @@ void ClipboardMus::WriteHTML(const char* markup_data,
void ClipboardMus::WriteRTF(const char* rtf_data, size_t data_len) {
DCHECK(current_clipboard_);
current_clipboard_->insert(
- mus::mojom::kMimeTypeRTF,
+ ui::mojom::kMimeTypeRTF,
mojo::Array<uint8_t>::From(base::StringPiece(rtf_data, data_len)));
}
@@ -307,7 +313,7 @@ void ClipboardMus::WriteBookmark(const char* title_data,
base::UTF8ToUTF16(base::StringPiece(title_data, title_len));
DCHECK(current_clipboard_);
- current_clipboard_->insert(mus::mojom::kMimeTypeMozillaURL,
+ current_clipboard_->insert(ui::mojom::kMimeTypeMozillaURL,
mojo::Array<uint8_t>::From(bookmark));
}
@@ -321,7 +327,7 @@ void ClipboardMus::WriteBitmap(const SkBitmap& bitmap) {
// Encode the bitmap as a PNG for transport.
std::vector<unsigned char> output;
if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) {
- current_clipboard_->insert(mus::mojom::kMimeTypePNG,
+ current_clipboard_->insert(ui::mojom::kMimeTypePNG,
mojo::Array<uint8_t>::From(output));
}
}
diff --git a/chromium/ui/views/mus/clipboard_mus.h b/chromium/ui/views/mus/clipboard_mus.h
index ddfa9fa6d1b..9781a9a6753 100644
--- a/chromium/ui/views/mus/clipboard_mus.h
+++ b/chromium/ui/views/mus/clipboard_mus.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_MUS_CLIPBOARD_MUS_H_
#define UI_VIEWS_MUS_CLIPBOARD_MUS_H_
-#include "components/mus/public/interfaces/clipboard.mojom.h"
+#include "services/ui/public/interfaces/clipboard.mojom.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/views/mus/mus_export.h"
@@ -70,7 +70,7 @@ class VIEWS_MUS_EXPORT ClipboardMus : public ui::Clipboard {
static mojo::String GetMimeTypeFor(const FormatType& format);
- mus::mojom::ClipboardPtr clipboard_;
+ ui::mojom::ClipboardPtr clipboard_;
// Internal buffer used to accumulate data types. The public interface is
// WriteObjects(), which then calls our base class DispatchObject() which
diff --git a/chromium/ui/views/mus/display_list.cc b/chromium/ui/views/mus/display_list.cc
deleted file mode 100644
index 5be844ca52f..00000000000
--- a/chromium/ui/views/mus/display_list.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2016 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/mus/display_list.h"
-
-#include "ui/display/display_finder.h"
-#include "ui/display/display_observer.h"
-
-namespace views {
-
-DisplayList::DisplayList() {}
-
-DisplayList::~DisplayList() {}
-
-void DisplayList::AddObserver(display::DisplayObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void DisplayList::RemoveObserver(display::DisplayObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-DisplayList::Displays::const_iterator DisplayList::FindDisplayById(
- int64_t id) const {
- for (auto iter = displays_.begin(); iter != displays_.end(); ++iter) {
- if (iter->id() == id)
- return iter;
- }
- return displays_.end();
-}
-
-DisplayList::Displays::iterator DisplayList::FindDisplayById(int64_t id) {
- for (auto iter = displays_.begin(); iter != displays_.end(); ++iter) {
- if (iter->id() == id)
- return iter;
- }
- return displays_.end();
-}
-
-DisplayList::Displays::const_iterator DisplayList::GetPrimaryDisplayIterator()
- const {
- return primary_display_index_ == -1
- ? displays_.end()
- : displays_.begin() + primary_display_index_;
-}
-
-void DisplayList::UpdateDisplay(const display::Display& display, Type type) {
- auto iter = FindDisplayById(display.id());
- DCHECK(iter != displays_.end());
-
- display::Display* local_display = &(*iter);
- uint32_t changed_values = 0;
- if (type == Type::PRIMARY &&
- static_cast<int>(iter - displays_.begin()) !=
- static_cast<int>(GetPrimaryDisplayIterator() - displays_.begin())) {
- primary_display_index_ = static_cast<int>(iter - displays_.begin());
- // ash::DisplayManager only notifies for the Display gaining primary, not
- // the one losing it.
- changed_values |= display::DisplayObserver::DISPLAY_METRIC_PRIMARY;
- }
- if (local_display->bounds() != display.bounds()) {
- local_display->set_bounds(display.bounds());
- changed_values |= display::DisplayObserver::DISPLAY_METRIC_BOUNDS;
- }
- if (local_display->work_area() != display.work_area()) {
- local_display->set_work_area(display.work_area());
- changed_values |= display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
- }
- if (local_display->rotation() != display.rotation()) {
- local_display->set_rotation(display.rotation());
- changed_values |= display::DisplayObserver::DISPLAY_METRIC_ROTATION;
- }
- if (local_display->device_scale_factor() != display.device_scale_factor()) {
- local_display->set_device_scale_factor(display.device_scale_factor());
- changed_values |=
- display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
- }
- FOR_EACH_OBSERVER(display::DisplayObserver, observers_,
- OnDisplayMetricsChanged(*local_display, changed_values));
-}
-
-void DisplayList::AddDisplay(const display::Display& display, Type type) {
- DCHECK(displays_.end() == FindDisplayById(display.id()));
- displays_.push_back(display);
- if (type == Type::PRIMARY)
- primary_display_index_ = static_cast<int>(displays_.size()) - 1;
- FOR_EACH_OBSERVER(display::DisplayObserver, observers_,
- OnDisplayAdded(display));
-}
-
-void DisplayList::RemoveDisplay(int64_t id) {
- auto iter = FindDisplayById(id);
- DCHECK(displays_.end() != iter);
- if (primary_display_index_ == static_cast<int>(iter - displays_.begin())) {
- // We expect the primary to change before removing it. The only case we
- // allow removal of the primary is if it is the list display.
- DCHECK_EQ(1u, displays_.size());
- primary_display_index_ = -1;
- } else if (primary_display_index_ >
- static_cast<int>(iter - displays_.begin())) {
- primary_display_index_--;
- }
- const display::Display display = *iter;
- displays_.erase(iter);
- FOR_EACH_OBSERVER(display::DisplayObserver, observers_,
- OnDisplayRemoved(display));
-}
-} // namespace views
diff --git a/chromium/ui/views/mus/display_list.h b/chromium/ui/views/mus/display_list.h
deleted file mode 100644
index 19b0ac97f11..00000000000
--- a/chromium/ui/views/mus/display_list.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2016 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_MUS_DISPLAY_LIST_H_
-#define UI_VIEWS_MUS_DISPLAY_LIST_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/observer_list.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/display/display.h"
-#include "ui/views/mus/mus_export.h"
-
-namespace display {
-class Display;
-class DisplayObserver;
-}
-
-namespace views {
-
-// Maintains an ordered list of display::Displays as well as operations to add,
-// remove and update said list. Additionally maintains display::DisplayObservers
-// and updates them as appropriate.
-class VIEWS_MUS_EXPORT DisplayList {
- public:
- using Displays = std::vector<display::Display>;
-
- enum class Type {
- PRIMARY,
- NOT_PRIMARY,
- };
-
- DisplayList();
- ~DisplayList();
-
- void AddObserver(display::DisplayObserver* observer);
- void RemoveObserver(display::DisplayObserver* observer);
-
- const Displays& displays() const { return displays_; }
-
- Displays::const_iterator FindDisplayById(int64_t id) const;
- Displays::iterator FindDisplayById(int64_t id);
-
- Displays::const_iterator GetPrimaryDisplayIterator() const;
-
- // Updates the cached id based on display.id() as well as whether the Display
- // is the primary display.
- void UpdateDisplay(const display::Display& display, Type type);
-
- // Adds a new Display.
- void AddDisplay(const display::Display& display, Type type);
-
- // Removes the Display with the specified id.
- void RemoveDisplay(int64_t id);
-
- private:
- std::vector<display::Display> displays_;
- int primary_display_index_ = -1;
- base::ObserverList<display::DisplayObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayList);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_MUS_DISPLAY_LIST_H_
diff --git a/chromium/ui/views/mus/display_list_unittest.cc b/chromium/ui/views/mus/display_list_unittest.cc
deleted file mode 100644
index 93cdc81e608..00000000000
--- a/chromium/ui/views/mus/display_list_unittest.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2016 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/mus/display_list.h"
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string_number_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/display/display.h"
-#include "ui/display/display_observer.h"
-
-using display::Display;
-
-namespace views {
-namespace {
-
-class DisplayObserverImpl : public display::DisplayObserver {
- public:
- DisplayObserverImpl() {}
- ~DisplayObserverImpl() override {}
-
- std::string GetAndClearChanges() {
- std::string changes;
- std::swap(changes, changes_);
- return changes;
- }
-
- private:
- static void AddPartChange(uint32_t changed,
- uint32_t part,
- const std::string& description,
- std::string* changed_string) {
- if ((changed & part) != part)
- return;
-
- *changed_string += " ";
- *changed_string += description;
- }
-
- void AddChange(const std::string& change) {
- if (!changes_.empty())
- changes_ += "\n";
- changes_ += change;
- }
-
- void OnDisplayAdded(const Display& new_display) override {
- AddChange("Added id=" + base::Int64ToString(new_display.id()));
- }
- void OnDisplayRemoved(const Display& old_display) override {
- AddChange("Removed id=" + base::Int64ToString(old_display.id()));
- }
- void OnDisplayMetricsChanged(const Display& display,
- uint32_t changed_metrics) override {
- std::string parts;
- AddPartChange(changed_metrics, DISPLAY_METRIC_BOUNDS, "bounds", &parts);
- AddPartChange(changed_metrics, DISPLAY_METRIC_WORK_AREA, "work_area",
- &parts);
- AddPartChange(changed_metrics, DISPLAY_METRIC_DEVICE_SCALE_FACTOR,
- "scale_factor", &parts);
- AddPartChange(changed_metrics, DISPLAY_METRIC_ROTATION, "rotation", &parts);
- AddPartChange(changed_metrics, DISPLAY_METRIC_PRIMARY, "primary", &parts);
-
- AddChange("Changed id=" + base::Int64ToString(display.id()) + parts);
- }
-
- std::string changes_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayObserverImpl);
-};
-
-TEST(DisplayListTest, AddUpdateRemove) {
- DisplayList display_list;
- DisplayObserverImpl observer;
- display_list.AddObserver(&observer);
- display_list.AddDisplay(display::Display(2, gfx::Rect(0, 0, 801, 802)),
- DisplayList::Type::PRIMARY);
- EXPECT_EQ("Added id=2", observer.GetAndClearChanges());
-
- // Update the bounds.
- {
- display::Display updated_display = *(display_list.displays().begin());
- updated_display.set_bounds(gfx::Rect(0, 0, 803, 802));
- display_list.UpdateDisplay(updated_display, DisplayList::Type::PRIMARY);
- EXPECT_EQ("Changed id=2 bounds", observer.GetAndClearChanges());
- }
-
- // Add another.
- display_list.AddDisplay(display::Display(3, gfx::Rect(0, 0, 809, 802)),
- DisplayList::Type::NOT_PRIMARY);
- EXPECT_EQ("Added id=3", observer.GetAndClearChanges());
- ASSERT_EQ(2u, display_list.displays().size());
- EXPECT_EQ(2, display_list.displays()[0].id());
- EXPECT_EQ(3, display_list.displays()[1].id());
- EXPECT_EQ(2, display_list.GetPrimaryDisplayIterator()->id());
-
- // Make the second the primary.
- display_list.UpdateDisplay(display_list.displays()[1],
- DisplayList::Type::PRIMARY);
- EXPECT_EQ("Changed id=3 primary", observer.GetAndClearChanges());
- EXPECT_EQ(3, display_list.GetPrimaryDisplayIterator()->id());
-
- // Delete the first.
- display_list.RemoveDisplay(2);
- ASSERT_EQ(1u, display_list.displays().size());
- EXPECT_EQ("Removed id=2", observer.GetAndClearChanges());
- EXPECT_EQ(3, display_list.GetPrimaryDisplayIterator()->id());
-}
-
-} // namespace
-} // namespace views
diff --git a/chromium/ui/views/mus/drag_drop_client_mus.cc b/chromium/ui/views/mus/drag_drop_client_mus.cc
new file mode 100644
index 00000000000..d4d65cf9fbf
--- /dev/null
+++ b/chromium/ui/views/mus/drag_drop_client_mus.cc
@@ -0,0 +1,92 @@
+// Copyright 2016 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/mus/drag_drop_client_mus.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "services/ui/public/cpp/window.h"
+#include "ui/aura/window.h"
+#include "ui/views/mus/os_exchange_data_provider_mus.h"
+
+namespace views {
+namespace {
+
+DragDropClientMus* current_dragging_client = nullptr;
+
+} // namespace
+
+DragDropClientMus::DragDropClientMus(ui::Window* ui_window)
+ : ui_window_(ui_window) {}
+
+DragDropClientMus::~DragDropClientMus() {}
+
+int DragDropClientMus::StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int drag_operations,
+ ui::DragDropTypes::DragEventSource source) {
+ std::map<std::string, std::vector<uint8_t>> drag_data =
+ static_cast<const OSExchangeDataProviderMus&>(data.provider()).GetData();
+
+ // TODO(erg): Right now, I'm passing the cursor_location, but maybe I want to
+ // pass OSExchangeData::GetDragImageOffset() instead?
+
+ bool success = false;
+ gfx::Point cursor_location = screen_location;
+ uint32_t action_taken = ui::mojom::kDropEffectNone;
+ current_dragging_client = this;
+ ui_window_->PerformDragDrop(
+ drag_data, drag_operations, cursor_location,
+ *data.provider().GetDragImage().bitmap(),
+ base::Bind(&DragDropClientMus::OnMoveLoopEnd, base::Unretained(this),
+ &success, &action_taken));
+
+ base::MessageLoop* loop = base::MessageLoop::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
+ base::RunLoop run_loop;
+
+ runloop_quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+ current_dragging_client = nullptr;
+
+ return action_taken;
+}
+
+void DragDropClientMus::DragUpdate(aura::Window* target,
+ const ui::LocatedEvent& event) {
+ // Only called on OSX.
+ NOTREACHED();
+}
+
+void DragDropClientMus::Drop(aura::Window* target,
+ const ui::LocatedEvent& event) {
+ // Only called on OSX.
+ NOTREACHED();
+}
+
+void DragDropClientMus::DragCancel() {
+ ui_window_->CancelDragDrop();
+}
+
+bool DragDropClientMus::IsDragDropInProgress() {
+ return !!current_dragging_client;
+}
+
+void DragDropClientMus::OnMoveLoopEnd(bool* out_success,
+ uint32_t* out_action,
+ bool in_success,
+ uint32_t in_action) {
+ *out_success = in_success;
+ *out_action = in_action;
+ runloop_quit_closure_.Run();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/drag_drop_client_mus.h b/chromium/ui/views/mus/drag_drop_client_mus.h
new file mode 100644
index 00000000000..bb0b2954591
--- /dev/null
+++ b/chromium/ui/views/mus/drag_drop_client_mus.h
@@ -0,0 +1,59 @@
+// Copyright 2016 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_MUS_DRAG_DROP_CLIENT_MUS_H_
+#define UI_VIEWS_MUS_DRAG_DROP_CLIENT_MUS_H_
+
+#include "base/callback.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/wm/public/drag_drop_client.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+class LocatedEvent;
+class OSExchangeData;
+class Window;
+}
+
+namespace views {
+
+// An aura client object that translates aura dragging methods to their
+// remote ui::Window equivalents.
+class DragDropClientMus : public aura::client::DragDropClient {
+ public:
+ DragDropClientMus(ui::Window* ui_window);
+ ~DragDropClientMus() override;
+
+ // Overridden from aura::client::DragDropClient:
+ int StartDragAndDrop(const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& screen_location,
+ int drag_operations,
+ ui::DragDropTypes::DragEventSource source) override;
+ void DragUpdate(aura::Window* target, const ui::LocatedEvent& event) override;
+ void Drop(aura::Window* target, const ui::LocatedEvent& event) override;
+ void DragCancel() override;
+ bool IsDragDropInProgress() override;
+
+ private:
+ // Callback for StartDragAndDrop().
+ void OnMoveLoopEnd(bool* out_success,
+ uint32_t* out_action,
+ bool in_success,
+ uint32_t in_action);
+
+ ui::Window* ui_window_;
+
+ base::Closure runloop_quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(DragDropClientMus);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_DRAG_DROP_CLIENT_MUS_H_
diff --git a/chromium/ui/views/mus/drop_target_mus.cc b/chromium/ui/views/mus/drop_target_mus.cc
new file mode 100644
index 00000000000..85f6b2446b9
--- /dev/null
+++ b/chromium/ui/views/mus/drop_target_mus.cc
@@ -0,0 +1,146 @@
+// Copyright 2016 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/mus/drop_target_mus.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/drop_target_event.h"
+#include "ui/views/mus/os_exchange_data_provider_mus.h"
+#include "ui/wm/public/drag_drop_client.h"
+#include "ui/wm/public/drag_drop_delegate.h"
+
+namespace views {
+
+static_assert(ui::DragDropTypes::DRAG_NONE == ui::mojom::kDropEffectNone,
+ "Drag constants must be the same");
+static_assert(ui::DragDropTypes::DRAG_MOVE == ui::mojom::kDropEffectMove,
+ "Drag constants must be the same");
+static_assert(ui::DragDropTypes::DRAG_COPY == ui::mojom::kDropEffectCopy,
+ "Drag constants must be the same");
+static_assert(ui::DragDropTypes::DRAG_LINK == ui::mojom::kDropEffectLink,
+ "Drag constants must be the same");
+
+DropTargetMus::DropTargetMus(aura::Window* root_window)
+ : root_window_(root_window), target_window_(nullptr) {}
+
+DropTargetMus::~DropTargetMus() {}
+
+void DropTargetMus::Translate(uint32_t key_state,
+ const gfx::Point& screen_location,
+ uint32_t effect,
+ std::unique_ptr<ui::DropTargetEvent>* event,
+ aura::client::DragDropDelegate** delegate) {
+ gfx::Point location = screen_location;
+ gfx::Point root_location = location;
+ root_window_->GetHost()->ConvertPointFromNativeScreen(&root_location);
+ aura::Window* target_window =
+ root_window_->GetEventHandlerForPoint(root_location);
+ bool target_window_changed = false;
+ if (target_window != target_window_) {
+ if (target_window_)
+ NotifyDragExited();
+ target_window_ = target_window;
+ if (target_window_)
+ target_window_->AddObserver(this);
+ target_window_changed = true;
+ }
+ *delegate = nullptr;
+ if (!target_window_)
+ return;
+ *delegate = aura::client::GetDragDropDelegate(target_window_);
+ if (!*delegate)
+ return;
+
+ location = root_location;
+ aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
+ *event = base::MakeUnique<ui::DropTargetEvent>(
+ *(os_exchange_data_.get()), location, root_location, effect);
+ (*event)->set_flags(key_state);
+ if (target_window_changed)
+ (*delegate)->OnDragEntered(*event->get());
+}
+
+void DropTargetMus::NotifyDragExited() {
+ if (!target_window_)
+ return;
+
+ aura::client::DragDropDelegate* delegate =
+ aura::client::GetDragDropDelegate(target_window_);
+ if (delegate)
+ delegate->OnDragExited();
+
+ target_window_->RemoveObserver(this);
+ target_window_ = nullptr;
+}
+
+void DropTargetMus::OnDragDropStart(
+ std::map<std::string, std::vector<uint8_t>> mime_data) {
+ // We store the mime data here because we need to access it during each phase
+ // of the drag, but we also don't move the data cross-process multiple times.
+ os_exchange_data_ = base::MakeUnique<ui::OSExchangeData>(
+ base::MakeUnique<OSExchangeDataProviderMus>(std::move(mime_data)));
+}
+
+uint32_t DropTargetMus::OnDragEnter(uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask) {
+ std::unique_ptr<ui::DropTargetEvent> event;
+ aura::client::DragDropDelegate* delegate = nullptr;
+ // Translate will call OnDragEntered.
+ Translate(key_state, position, effect_bitmask, &event, &delegate);
+ return ui::mojom::kDropEffectNone;
+}
+
+uint32_t DropTargetMus::OnDragOver(uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect) {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ std::unique_ptr<ui::DropTargetEvent> event;
+ aura::client::DragDropDelegate* delegate = nullptr;
+
+ Translate(key_state, position, effect, &event, &delegate);
+ if (delegate)
+ drag_operation = delegate->OnDragUpdated(*event);
+ return drag_operation;
+}
+
+void DropTargetMus::OnDragLeave() {
+ NotifyDragExited();
+}
+
+uint32_t DropTargetMus::OnCompleteDrop(uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect) {
+ int drag_operation = ui::DragDropTypes::DRAG_NONE;
+ std::unique_ptr<ui::DropTargetEvent> event;
+ aura::client::DragDropDelegate* delegate = nullptr;
+ Translate(key_state, position, effect, &event, &delegate);
+ if (delegate)
+ drag_operation = delegate->OnPerformDrop(*event);
+ if (target_window_) {
+ target_window_->RemoveObserver(this);
+ target_window_ = nullptr;
+ }
+
+ return drag_operation;
+}
+
+void DropTargetMus::OnDragDropDone() {
+ os_exchange_data_.reset();
+}
+
+void DropTargetMus::OnWindowDestroyed(aura::Window* window) {
+ DCHECK_EQ(window, target_window_);
+ target_window_ = nullptr;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/drop_target_mus.h b/chromium/ui/views/mus/drop_target_mus.h
new file mode 100644
index 00000000000..12cb3ff0bbf
--- /dev/null
+++ b/chromium/ui/views/mus/drop_target_mus.h
@@ -0,0 +1,93 @@
+// Copyright 2016 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_MUS_DROP_TARGET_MUS_H_
+#define UI_VIEWS_MUS_DROP_TARGET_MUS_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "services/ui/public/cpp/window_drop_target.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+
+namespace client {
+class DragDropDelegate;
+}
+}
+
+namespace ui {
+class DropTargetEvent;
+class OSExchangeData;
+}
+
+namespace views {
+
+// An adapter class which takes signals from mus' WindowDropTarget, performs
+// targeting on the underlying aura::Window tree, and dispatches them to the
+// aura DragDropDelegate of the targeted aura::Window.
+class DropTargetMus : public ui::WindowDropTarget, public aura::WindowObserver {
+ public:
+ explicit DropTargetMus(aura::Window* root_window);
+ ~DropTargetMus() override;
+
+ private:
+ // Common functionality for the WindowDropTarget methods to translate from
+ // mus data types to Aura ones. This method takes in mus messages and
+ // performs the common tasks of keeping track of which aura window (along
+ // with enter/leave messages at that layer), doing coordinate translation,
+ // and creation of ui layer event objects that get dispatched to aura/views.
+ void Translate(uint32_t key_state,
+ const gfx::Point& screen_location,
+ uint32_t effect_bitmask,
+ std::unique_ptr<ui::DropTargetEvent>* event,
+ aura::client::DragDropDelegate** delegate);
+
+ void NotifyDragExited();
+
+ // Overridden from ui::WindowDropTarget:
+ void OnDragDropStart(
+ std::map<std::string, std::vector<uint8_t>> mime_data) override;
+ uint32_t OnDragEnter(uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask) override;
+ uint32_t OnDragOver(uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask) override;
+ void OnDragLeave() override;
+ uint32_t OnCompleteDrop(uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask) override;
+ void OnDragDropDone() override;
+
+ // Overridden from aura::WindowObserver:
+ void OnWindowDestroyed(aura::Window* window) override;
+
+ // The root window associated with this drop target.
+ aura::Window* root_window_;
+
+ // The Aura window that is currently under the cursor. We need to manually
+ // keep track of this because mus will only call our drag enter method once
+ // when the user enters the associated mus::Window. But inside mus there
+ // could be multiple aura windows, so we need to generate drag enter events
+ // for them.
+ aura::Window* target_window_;
+
+ // The entire drag data payload. We receive this during the drag enter event
+ // and cache it so we don't send this multiple times. We reset this value on
+ // leave or drop.
+ std::unique_ptr<ui::OSExchangeData> os_exchange_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropTargetMus);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_DROP_TARGET_MUS_H_
diff --git a/chromium/ui/views/mus/input_method_mus.cc b/chromium/ui/views/mus/input_method_mus.cc
index 352c53869c3..8d5bb8b2cfa 100644
--- a/chromium/ui/views/mus/input_method_mus.cc
+++ b/chromium/ui/views/mus/input_method_mus.cc
@@ -6,44 +6,52 @@
#include <utility>
-#include "components/mus/public/cpp/window.h"
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/interfaces/ime.mojom.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/events/event.h"
#include "ui/platform_window/mojo/ime_type_converters.h"
#include "ui/platform_window/mojo/text_input_state.mojom.h"
+#include "ui/views/mus/text_input_client_impl.h"
namespace views {
////////////////////////////////////////////////////////////////////////////////
-// InputMethodMUS, public:
+// InputMethodMus, public:
-InputMethodMUS::InputMethodMUS(ui::internal::InputMethodDelegate* delegate,
- mus::Window* window)
+InputMethodMus::InputMethodMus(ui::internal::InputMethodDelegate* delegate,
+ ui::Window* window)
: window_(window) {
SetDelegate(delegate);
}
-InputMethodMUS::~InputMethodMUS() {}
+InputMethodMus::~InputMethodMus() {}
+
+void InputMethodMus::Init(shell::Connector* connector) {
+ connector->ConnectToInterface("service:ui", &ime_server_);
+}
////////////////////////////////////////////////////////////////////////////////
-// InputMethodMUS, ui::InputMethod implementation:
+// InputMethodMus, ui::InputMethod implementation:
-void InputMethodMUS::OnFocus() {
+void InputMethodMus::OnFocus() {
InputMethodBase::OnFocus();
UpdateTextInputType();
}
-void InputMethodMUS::OnBlur() {
+void InputMethodMus::OnBlur() {
InputMethodBase::OnBlur();
UpdateTextInputType();
}
-bool InputMethodMUS::OnUntranslatedIMEMessage(const base::NativeEvent& event,
+bool InputMethodMus::OnUntranslatedIMEMessage(const base::NativeEvent& event,
NativeEventResult* result) {
+ // This method is not called on non-Windows platforms. See the comments for
+ // ui::InputMethod::OnUntranslatedIMEMessage().
return false;
}
-void InputMethodMUS::DispatchKeyEvent(ui::KeyEvent* event) {
+void InputMethodMus::DispatchKeyEvent(ui::KeyEvent* event) {
DCHECK(event->type() == ui::ET_KEY_PRESSED ||
event->type() == ui::ET_KEY_RELEASED);
@@ -53,12 +61,14 @@ void InputMethodMUS::DispatchKeyEvent(ui::KeyEvent* event) {
return;
}
- // Here is where we change the differ from our base class's logic. Instead of
- // always dispatching a key down event, and then sending a synthesized
- // character event, we instead check to see if this is a character event and
- // send out the key if it is. (We fallback to normal dispatch if it isn't.)
+ // TODO(moshayedi): crbug.com/641355. Currently if we stop propagation of
+ // non-char events here, accelerators ddn't work. This is because we send the
+ // event ack too early in NativeWidgetMus. We should send both char and
+ // non-char events to the IME driver once we fix this.
if (event->is_char()) {
- GetTextInputClient()->InsertChar(*event);
+ // IME driver will notify the text input client if it is not interested in
+ // event, which in turn will call DispatchKeyEventPostIME().
+ input_method_->ProcessKeyEvent(ui::Event::Clone(*event));
event->StopPropagation();
return;
}
@@ -66,41 +76,59 @@ void InputMethodMUS::DispatchKeyEvent(ui::KeyEvent* event) {
ignore_result(DispatchKeyEventPostIME(event));
}
-void InputMethodMUS::OnTextInputTypeChanged(const ui::TextInputClient* client) {
+void InputMethodMus::OnTextInputTypeChanged(const ui::TextInputClient* client) {
if (IsTextInputClientFocused(client))
UpdateTextInputType();
InputMethodBase::OnTextInputTypeChanged(client);
-}
-void InputMethodMUS::OnCaretBoundsChanged(const ui::TextInputClient* client) {}
+ if (input_method_) {
+ input_method_->OnTextInputTypeChanged(
+ static_cast<ui::mojom::TextInputType>(client->GetTextInputType()));
+ }
+}
-void InputMethodMUS::CancelComposition(const ui::TextInputClient* client) {}
+void InputMethodMus::OnCaretBoundsChanged(const ui::TextInputClient* client) {
+ if (input_method_)
+ input_method_->OnCaretBoundsChanged(client->GetCaretBounds());
+}
-void InputMethodMUS::OnInputLocaleChanged() {}
+void InputMethodMus::CancelComposition(const ui::TextInputClient* client) {
+ if (input_method_)
+ input_method_->CancelComposition();
+}
-std::string InputMethodMUS::GetInputLocale() {
- return "";
+void InputMethodMus::OnInputLocaleChanged() {
+ // TODO(moshayedi): crbug.com/637418. Not supported in ChromeOS. Investigate
+ // whether we want to support this or not.
}
-bool InputMethodMUS::IsCandidatePopupOpen() const {
+bool InputMethodMus::IsCandidatePopupOpen() const {
+ // TODO(moshayedi): crbug.com/637416. Implement this properly when we have a
+ // mean for displaying candidate list popup.
return false;
}
-void InputMethodMUS::OnDidChangeFocusedClient(
+void InputMethodMus::OnDidChangeFocusedClient(
ui::TextInputClient* focused_before,
ui::TextInputClient* focused) {
InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
UpdateTextInputType();
+
+ text_input_client_ = base::MakeUnique<TextInputClientImpl>(focused, this);
+ ime_server_->StartSession(text_input_client_->CreateInterfacePtrAndBind(),
+ GetProxy(&input_method_));
}
-void InputMethodMUS::UpdateTextInputType() {
+void InputMethodMus::UpdateTextInputType() {
ui::TextInputType type = GetTextInputType();
mojo::TextInputStatePtr state = mojo::TextInputState::New();
state->type = mojo::ConvertTo<mojo::TextInputType>(type);
- if (type != ui::TEXT_INPUT_TYPE_NONE)
- window_->SetImeVisibility(true, std::move(state));
- else
- window_->SetTextInputState(std::move(state));
+ if (window_) {
+ if (type != ui::TEXT_INPUT_TYPE_NONE)
+ window_->SetImeVisibility(true, std::move(state));
+ else
+ window_->SetTextInputState(std::move(state));
+ }
}
} // namespace views
diff --git a/chromium/ui/views/mus/input_method_mus.h b/chromium/ui/views/mus/input_method_mus.h
index e5188a3aac0..aa5dd5d2efc 100644
--- a/chromium/ui/views/mus/input_method_mus.h
+++ b/chromium/ui/views/mus/input_method_mus.h
@@ -8,21 +8,27 @@
#define UI_VIEWS_MUS_INPUT_METHOD_MUS_H_
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/ui/public/interfaces/ime.mojom.h"
#include "ui/views/mus/mus_export.h"
-namespace mus {
+namespace ui {
class Window;
} // namespace mojo
namespace views {
-class VIEWS_MUS_EXPORT InputMethodMUS : public ui::InputMethodBase {
+class TextInputClientImpl;
+
+class VIEWS_MUS_EXPORT InputMethodMus : public ui::InputMethodBase {
public:
- InputMethodMUS(ui::internal::InputMethodDelegate* delegate,
- mus::Window* window);
- ~InputMethodMUS() override;
+ InputMethodMus(ui::internal::InputMethodDelegate* delegate,
+ ui::Window* window);
+ ~InputMethodMus() override;
+
+ void Init(shell::Connector* connector);
- private:
// Overridden from ui::InputMethod:
void OnFocus() override;
void OnBlur() override;
@@ -33,19 +39,26 @@ class VIEWS_MUS_EXPORT InputMethodMUS : public ui::InputMethodBase {
void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
void CancelComposition(const ui::TextInputClient* client) override;
void OnInputLocaleChanged() override;
- std::string GetInputLocale() override;
bool IsCandidatePopupOpen() const override;
+ private:
+ friend TextInputClientImpl;
+
// Overridden from ui::InputMethodBase:
void OnDidChangeFocusedClient(ui::TextInputClient* focused_before,
ui::TextInputClient* focused) override;
void UpdateTextInputType();
- // The toplevel window which is not owned by this class.
- mus::Window* window_;
+ // The toplevel window which is not owned by this class. This may be null
+ // for tests.
+ ui::Window* window_;
+
+ ui::mojom::IMEServerPtr ime_server_;
+ ui::mojom::InputMethodPtr input_method_;
+ std::unique_ptr<TextInputClientImpl> text_input_client_;
- DISALLOW_COPY_AND_ASSIGN(InputMethodMUS);
+ DISALLOW_COPY_AND_ASSIGN(InputMethodMus);
};
} // namespace views
diff --git a/chromium/ui/views/mus/input_method_mus_unittest.cc b/chromium/ui/views/mus/input_method_mus_unittest.cc
new file mode 100644
index 00000000000..1e312529cfb
--- /dev/null
+++ b/chromium/ui/views/mus/input_method_mus_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright 2016 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/mus/input_method_mus.h"
+
+#include <memory>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/dummy_text_input_client.h"
+#include "ui/base/ime/input_method_delegate.h"
+#include "ui/events/event.h"
+#include "ui/views/mus/window_manager_connection.h"
+#include "ui/views/test/scoped_views_test_helper.h"
+
+namespace views {
+namespace {
+
+class TestInputMethodDelegate : public ui::internal::InputMethodDelegate {
+ public:
+ TestInputMethodDelegate() {}
+ ~TestInputMethodDelegate() override {}
+
+ // ui::internal::InputMethodDelegate:
+ ui::EventDispatchDetails DispatchKeyEventPostIME(
+ ui::KeyEvent* key_event) override {
+ return ui::EventDispatchDetails();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestInputMethodDelegate);
+};
+
+class TestTextInputClient : public ui::DummyTextInputClient {
+ public:
+ TestTextInputClient() {}
+ ~TestTextInputClient() override {}
+
+ ui::KeyEvent* WaitUntilInputReceieved() {
+ run_loop_ = base::MakeUnique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+
+ return received_event_->AsKeyEvent();
+ }
+
+ // ui::DummyTextInputClient:
+ void InsertChar(const ui::KeyEvent& event) override {
+ received_event_ = ui::Event::Clone(event);
+ run_loop_->Quit();
+ }
+
+ private:
+ std::unique_ptr<base::RunLoop> run_loop_;
+ std::unique_ptr<ui::Event> received_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTextInputClient);
+};
+
+} // namespace
+
+class InputMethodMusTest : public testing::Test {
+ public:
+ InputMethodMusTest() : message_loop_(base::MessageLoop::TYPE_UI) {}
+ ~InputMethodMusTest() override {}
+
+ shell::Connector* connector() {
+ return WindowManagerConnection::Get()->connector();
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ ScopedViewsTestHelper helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputMethodMusTest);
+};
+
+TEST_F(InputMethodMusTest, DispatchKeyEvent) {
+ // test_ime_driver will register itself as the current IMEDriver. It echoes
+ // back the character key events it receives.
+ EXPECT_TRUE(connector()->Connect("service:test_ime_driver"));
+
+ TestInputMethodDelegate input_method_delegate;
+ InputMethodMus input_method(&input_method_delegate, nullptr);
+ input_method.Init(connector());
+
+ TestTextInputClient text_input_client;
+ input_method.SetFocusedTextInputClient(&text_input_client);
+
+ ui::KeyEvent key_event('A', ui::VKEY_A, 0);
+ input_method.DispatchKeyEvent(&key_event);
+
+ ui::KeyEvent* received_event = text_input_client.WaitUntilInputReceieved();
+ EXPECT_EQ(ui::ET_KEY_PRESSED, received_event->type());
+ EXPECT_TRUE(received_event->is_char());
+ EXPECT_EQ(key_event.GetCharacter(), received_event->GetCharacter());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/interactive_ui_tests_manifest.json b/chromium/ui/views/mus/interactive_ui_tests_manifest.json
index a0b81fcb72e..0c326823637 100644
--- a/chromium/ui/views/mus/interactive_ui_tests_manifest.json
+++ b/chromium/ui/views/mus/interactive_ui_tests_manifest.json
@@ -1,6 +1,6 @@
{
"manifest_version": 1,
- "name": "mojo:views_mus_interactive_ui_tests",
+ "name": "service:views_mus_interactive_ui_tests",
"display_name": "Views Mus Interactive UI Tests",
"capabilities": {
"required": {
diff --git a/chromium/ui/views/mus/native_widget_mus.cc b/chromium/ui/views/mus/native_widget_mus.cc
index 9bed4cca17d..4024de71b40 100644
--- a/chromium/ui/views/mus/native_widget_mus.cc
+++ b/chromium/ui/views/mus/native_widget_mus.cc
@@ -2,31 +2,36 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This has to be before any other includes, else default is picked up.
+// See base/logging for details on this.
+#define NOTIMPLEMENTED_POLICY 5
+
#include "ui/views/mus/native_widget_mus.h"
+#include <utility>
+#include <vector>
+
#include "base/callback.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/bitmap_uploader/bitmap_uploader.h"
-#include "components/mus/public/cpp/property_type_converters.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_property.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/interfaces/cursor.mojom.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "components/mus/public/interfaces/window_manager_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
+#include "services/ui/public/cpp/property_type_converters.h"
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/cpp/window_observer.h"
+#include "services/ui/public/cpp/window_property.h"
+#include "services/ui/public/cpp/window_tree_client.h"
+#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/window_manager.mojom.h"
+#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/mus/mus_util.h"
#include "ui/aura/window.h"
#include "ui/aura/window_property.h"
#include "ui/base/hit_test.h"
-#include "ui/base/view_prop.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
@@ -34,10 +39,14 @@
#include "ui/gfx/path.h"
#include "ui/native_theme/native_theme_aura.h"
#include "ui/platform_window/platform_window_delegate.h"
-#include "ui/views/mus/surface_context_factory.h"
+#include "ui/views/drag_utils.h"
+#include "ui/views/mus/drag_drop_client_mus.h"
+#include "ui/views/mus/drop_target_mus.h"
+#include "ui/views/mus/window_manager_connection.h"
#include "ui/views/mus/window_manager_constants_converters.h"
#include "ui/views/mus/window_manager_frame_values.h"
#include "ui/views/mus/window_tree_host_mus.h"
+#include "ui/views/widget/drop_helper.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/custom_frame_view.h"
@@ -48,14 +57,14 @@
#include "ui/wm/core/focus_controller.h"
#include "ui/wm/core/native_cursor_manager.h"
-DECLARE_WINDOW_PROPERTY_TYPE(mus::Window*);
+DECLARE_WINDOW_PROPERTY_TYPE(ui::Window*);
-using mus::mojom::EventResult;
+using ui::mojom::EventResult;
namespace views {
namespace {
-DEFINE_WINDOW_PROPERTY_KEY(mus::Window*, kMusWindow, nullptr);
+DEFINE_WINDOW_PROPERTY_KEY(ui::Window*, kMusWindow, nullptr);
MUS_DEFINE_WINDOW_PROPERTY_KEY(NativeWidgetMus*, kNativeWidgetMusKey, nullptr);
@@ -77,7 +86,7 @@ class FocusRulesImpl : public wm::BaseFocusRules {
// This makes sure that an aura::Window focused (or activated) through the
// aura::client::FocusClient (or ActivationClient) focuses (or activates) the
-// corresponding mus::Window too.
+// corresponding ui::Window too.
class FocusControllerMus : public wm::FocusController {
public:
explicit FocusControllerMus(wm::FocusRules* rules) : FocusController(rules) {}
@@ -87,8 +96,7 @@ class FocusControllerMus : public wm::FocusController {
void FocusWindow(aura::Window* window) override {
FocusController::FocusWindow(window);
if (window) {
- mus::Window* mus_window =
- window->GetRootWindow()->GetProperty(kMusWindow);
+ ui::Window* mus_window = window->GetRootWindow()->GetProperty(kMusWindow);
if (mus_window)
mus_window->SetFocus();
}
@@ -99,9 +107,9 @@ class FocusControllerMus : public wm::FocusController {
class ContentWindowLayoutManager : public aura::LayoutManager {
public:
- ContentWindowLayoutManager(aura::Window* outer, aura::Window* inner)
+ ContentWindowLayoutManager(aura::Window* outer, aura::Window* inner)
: outer_(outer), inner_(inner) {}
- ~ContentWindowLayoutManager() override {}
+ ~ContentWindowLayoutManager() override {}
private:
// aura::LayoutManager:
@@ -147,10 +155,10 @@ class NativeWidgetMusWindowTreeClient : public aura::client::WindowTreeClient {
DISALLOW_COPY_AND_ASSIGN(NativeWidgetMusWindowTreeClient);
};
-// A screen position client that applies the offset of the mus::Window.
+// A screen position client that applies the offset of the ui::Window.
class ScreenPositionClientMus : public wm::DefaultScreenPositionClient {
public:
- explicit ScreenPositionClientMus(mus::Window* mus_window)
+ explicit ScreenPositionClientMus(ui::Window* mus_window)
: mus_window_(mus_window) {}
~ScreenPositionClientMus() override {}
@@ -169,14 +177,14 @@ class ScreenPositionClientMus : public wm::DefaultScreenPositionClient {
}
private:
- mus::Window* mus_window_;
+ ui::Window* mus_window_;
DISALLOW_COPY_AND_ASSIGN(ScreenPositionClientMus);
};
class NativeCursorManagerMus : public wm::NativeCursorManager {
public:
- explicit NativeCursorManagerMus(mus::Window* mus_window)
+ explicit NativeCursorManagerMus(ui::Window* mus_window)
: mus_window_(mus_window) {}
~NativeCursorManagerMus() override {}
@@ -188,7 +196,7 @@ class NativeCursorManagerMus : public wm::NativeCursorManager {
void SetCursor(gfx::NativeCursor cursor,
wm::NativeCursorManagerDelegate* delegate) override {
- mus_window_->SetPredefinedCursor(mus::mojom::Cursor(cursor.native_type()));
+ mus_window_->SetPredefinedCursor(ui::mojom::Cursor(cursor.native_type()));
delegate->CommitCursor(cursor);
}
@@ -199,7 +207,7 @@ class NativeCursorManagerMus : public wm::NativeCursorManager {
if (visible)
SetCursor(delegate->GetCursor(), delegate);
else
- mus_window_->SetPredefinedCursor(mus::mojom::Cursor::NONE);
+ mus_window_->SetPredefinedCursor(ui::mojom::Cursor::NONE);
}
void SetCursorSet(ui::CursorSetType cursor_set,
@@ -224,7 +232,7 @@ class NativeCursorManagerMus : public wm::NativeCursorManager {
}
private:
- mus::Window* mus_window_;
+ ui::Window* mus_window_;
DISALLOW_COPY_AND_ASSIGN(NativeCursorManagerMus);
};
@@ -248,11 +256,16 @@ class ClientSideNonClientFrameView : public NonClientFrameView {
// NonClientFrameView:
gfx::Rect GetBoundsForClientView() const override {
gfx::Rect result(GetLocalBounds());
+ if (widget_->IsFullscreen())
+ return result;
result.Inset(GetDefaultWindowManagerInsets(widget_->IsMaximized()));
return result;
}
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override {
+ if (widget_->IsFullscreen())
+ return client_bounds;
+
const gfx::Insets insets(
GetDefaultWindowManagerInsets(widget_->IsMaximized()));
return gfx::Rect(client_bounds.x() - insets.left(),
@@ -305,15 +318,15 @@ class ClientSideNonClientFrameView : public NonClientFrameView {
int ResizeBehaviorFromDelegate(WidgetDelegate* delegate) {
if (!delegate)
- return mus::mojom::kResizeBehaviorNone;
+ return ui::mojom::kResizeBehaviorNone;
- int32_t behavior = mus::mojom::kResizeBehaviorNone;
+ int32_t behavior = ui::mojom::kResizeBehaviorNone;
if (delegate->CanResize())
- behavior |= mus::mojom::kResizeBehaviorCanResize;
+ behavior |= ui::mojom::kResizeBehaviorCanResize;
if (delegate->CanMaximize())
- behavior |= mus::mojom::kResizeBehaviorCanMaximize;
+ behavior |= ui::mojom::kResizeBehaviorCanMaximize;
if (delegate->CanMinimize())
- behavior |= mus::mojom::kResizeBehaviorCanMinimize;
+ behavior |= ui::mojom::kResizeBehaviorCanMinimize;
return behavior;
}
@@ -328,7 +341,7 @@ SkBitmap AppIconFromDelegate(WidgetDelegate* delegate) {
return app_icon.GetRepresentation(1.f).sk_bitmap();
}
-// Handles acknowledgement of an input event, either immediately when a nested
+// Handles acknowledgment of an input event, either immediately when a nested
// message loop starts, or upon destruction.
class EventAckHandler : public base::MessageLoop::NestingObserver {
public:
@@ -366,13 +379,31 @@ class EventAckHandler : public base::MessageLoop::NestingObserver {
DISALLOW_COPY_AND_ASSIGN(EventAckHandler);
};
+void OnMoveLoopEnd(bool* out_success,
+ base::Closure quit_closure,
+ bool in_success) {
+ *out_success = in_success;
+ quit_closure.Run();
+}
+
+ui::mojom::ShowState GetShowState(const ui::Window* window) {
+ if (!window ||
+ !window->HasSharedProperty(
+ ui::mojom::WindowManager::kShowState_Property)) {
+ return ui::mojom::ShowState::DEFAULT;
+ }
+
+ return static_cast<ui::mojom::ShowState>(window->GetSharedProperty<int32_t>(
+ ui::mojom::WindowManager::kShowState_Property));
+}
+
} // namespace
-class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver {
+class NativeWidgetMus::MusWindowObserver : public ui::WindowObserver {
public:
explicit MusWindowObserver(NativeWidgetMus* native_widget_mus)
: native_widget_mus_(native_widget_mus),
- show_state_(mus::mojom::ShowState::DEFAULT) {
+ show_state_(ui::mojom::ShowState::DEFAULT) {
mus_window()->AddObserver(this);
}
@@ -380,77 +411,73 @@ class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver {
mus_window()->RemoveObserver(this);
}
- mus::mojom::ShowState show_state() { return show_state_; }
-
- // mus::WindowObserver:
- void OnWindowVisibilityChanging(mus::Window* window) override {
- native_widget_mus_->OnMusWindowVisibilityChanging(window);
+ // ui::WindowObserver:
+ void OnWindowVisibilityChanging(ui::Window* window, bool visible) override {
+ native_widget_mus_->OnMusWindowVisibilityChanging(window, visible);
}
- void OnWindowVisibilityChanged(mus::Window* window) override {
- native_widget_mus_->OnMusWindowVisibilityChanged(window);
+ void OnWindowVisibilityChanged(ui::Window* window, bool visible) override {
+ native_widget_mus_->OnMusWindowVisibilityChanged(window, visible);
}
- void OnWindowPredefinedCursorChanged(mus::Window* window,
- mus::mojom::Cursor cursor) override {
+ void OnWindowPredefinedCursorChanged(ui::Window* window,
+ ui::mojom::Cursor cursor) override {
DCHECK_EQ(window, mus_window());
native_widget_mus_->set_last_cursor(cursor);
}
void OnWindowSharedPropertyChanged(
- mus::Window* window,
+ ui::Window* window,
const std::string& name,
const std::vector<uint8_t>* old_data,
const std::vector<uint8_t>* new_data) override {
- if (name != mus::mojom::WindowManager::kShowState_Property)
+ if (name != ui::mojom::WindowManager::kShowState_Property)
return;
- mus::mojom::ShowState show_state =
- static_cast<mus::mojom::ShowState>(window->GetSharedProperty<int32_t>(
- mus::mojom::WindowManager::kShowState_Property));
+ const ui::mojom::ShowState show_state = GetShowState(window);
if (show_state == show_state_)
return;
show_state_ = show_state;
ui::PlatformWindowState state = ui::PLATFORM_WINDOW_STATE_UNKNOWN;
switch (show_state_) {
- case mus::mojom::ShowState::MINIMIZED:
+ case ui::mojom::ShowState::MINIMIZED:
state = ui::PLATFORM_WINDOW_STATE_MINIMIZED;
break;
- case mus::mojom::ShowState::MAXIMIZED:
+ case ui::mojom::ShowState::MAXIMIZED:
state = ui::PLATFORM_WINDOW_STATE_MAXIMIZED;
break;
- case mus::mojom::ShowState::DEFAULT:
- case mus::mojom::ShowState::INACTIVE:
- case mus::mojom::ShowState::NORMAL:
- case mus::mojom::ShowState::DOCKED:
+ case ui::mojom::ShowState::DEFAULT:
+ case ui::mojom::ShowState::INACTIVE:
+ case ui::mojom::ShowState::NORMAL:
+ case ui::mojom::ShowState::DOCKED:
// TODO(sky): support docked.
state = ui::PLATFORM_WINDOW_STATE_NORMAL;
break;
- case mus::mojom::ShowState::FULLSCREEN:
+ case ui::mojom::ShowState::FULLSCREEN:
state = ui::PLATFORM_WINDOW_STATE_FULLSCREEN;
break;
}
platform_window_delegate()->OnWindowStateChanged(state);
}
- void OnWindowDestroyed(mus::Window* window) override {
+ void OnWindowDestroyed(ui::Window* window) override {
DCHECK_EQ(mus_window(), window);
platform_window_delegate()->OnClosed();
}
- void OnWindowBoundsChanging(mus::Window* window,
+ void OnWindowBoundsChanging(ui::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) override {
DCHECK_EQ(window, mus_window());
window_tree_host()->SetBounds(new_bounds);
}
- void OnWindowFocusChanged(mus::Window* gained_focus,
- mus::Window* lost_focus) override {
+ void OnWindowFocusChanged(ui::Window* gained_focus,
+ ui::Window* lost_focus) override {
if (gained_focus == mus_window())
platform_window_delegate()->OnActivationChanged(true);
else if (lost_focus == mus_window())
platform_window_delegate()->OnActivationChanged(false);
}
- void OnRequestClose(mus::Window* window) override {
+ void OnRequestClose(ui::Window* window) override {
platform_window_delegate()->OnCloseRequest();
}
private:
- mus::Window* mus_window() { return native_widget_mus_->window(); }
+ ui::Window* mus_window() { return native_widget_mus_->window(); }
WindowTreeHostMus* window_tree_host() {
return native_widget_mus_->window_tree_host();
}
@@ -459,7 +486,7 @@ class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver {
}
NativeWidgetMus* native_widget_mus_;
- mus::mojom::ShowState show_state_;
+ ui::mojom::ShowState show_state_;
DISALLOW_COPY_AND_ASSIGN(MusWindowObserver);
};
@@ -467,10 +494,12 @@ class NativeWidgetMus::MusWindowObserver : public mus::WindowObserver {
class NativeWidgetMus::MusCaptureClient
: public aura::client::DefaultCaptureClient {
public:
- MusCaptureClient(aura::Window* root_window, aura::Window* aura_window,
- mus::Window* mus_window)
+ MusCaptureClient(aura::Window* root_window,
+ aura::Window* aura_window,
+ ui::Window* mus_window)
: aura::client::DefaultCaptureClient(root_window),
- aura_window_(aura_window), mus_window_(mus_window) {}
+ aura_window_(aura_window),
+ mus_window_(mus_window) {}
~MusCaptureClient() override {}
// aura::client::DefaultCaptureClient:
@@ -487,7 +516,7 @@ class NativeWidgetMus::MusCaptureClient
private:
aura::Window* aura_window_;
- mus::Window* mus_window_;
+ ui::Window* mus_window_;
DISALLOW_COPY_AND_ASSIGN(MusCaptureClient);
};
@@ -496,52 +525,24 @@ class NativeWidgetMus::MusCaptureClient
// NativeWidgetMus, public:
NativeWidgetMus::NativeWidgetMus(internal::NativeWidgetDelegate* delegate,
- shell::Connector* connector,
- mus::Window* window,
- mus::mojom::SurfaceType surface_type)
+ ui::Window* window,
+ ui::mojom::SurfaceType surface_type)
: window_(window),
- last_cursor_(mus::mojom::Cursor::CURSOR_NULL),
+ last_cursor_(ui::mojom::Cursor::CURSOR_NULL),
native_widget_delegate_(delegate),
surface_type_(surface_type),
- show_state_before_fullscreen_(mus::mojom::ShowState::DEFAULT),
+ show_state_before_fullscreen_(ui::mojom::ShowState::DEFAULT),
ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
content_(new aura::Window(this)),
+ last_drop_operation_(ui::DragDropTypes::DRAG_NONE),
close_widget_factory_(this) {
window_->set_input_event_handler(this);
- mus_window_observer_.reset(new MusWindowObserver(this));
+ mus_window_observer_ = base::MakeUnique<MusWindowObserver>(this);
// TODO(fsamuel): Figure out lifetime of |window_|.
aura::SetMusWindow(content_, window_);
window->SetLocalProperty(kNativeWidgetMusKey, this);
-
- // WindowTreeHost creates the compositor using the ContextFactory from
- // aura::Env. Install |context_factory_| there so that |context_factory_| is
- // picked up.
- ui::ContextFactory* default_context_factory =
- aura::Env::GetInstance()->context_factory();
- // For Chrome, we need the GpuProcessTransportFactory so that renderer and
- // browser pixels are composited into a single backing SoftwareOutputDeviceMus
- // (which also requires the BitmapUploader).
- bool needs_bitmap_uploader = false;
- if (!default_context_factory) {
- context_factory_.reset(
- new SurfaceContextFactory(connector, window_, surface_type_));
- aura::Env::GetInstance()->set_context_factory(context_factory_.get());
- } else {
- needs_bitmap_uploader = true;
- }
-
- window_tree_host_.reset(new WindowTreeHostMus(this, window_));
- if (needs_bitmap_uploader) {
- bitmap_uploader_.reset(new bitmap_uploader::BitmapUploader(window));
- bitmap_uploader_->Init(connector);
- prop_.reset(
- new ui::ViewProp(window_tree_host_->GetAcceleratedWidget(),
- bitmap_uploader::kBitmapUploaderForAcceleratedWidget,
- bitmap_uploader_.get()));
- }
-
- aura::Env::GetInstance()->set_context_factory(default_context_factory);
+ window_tree_host_ = base::MakeUnique<WindowTreeHostMus>(this, window_);
}
NativeWidgetMus::~NativeWidgetMus() {
@@ -556,8 +557,8 @@ NativeWidgetMus::~NativeWidgetMus() {
}
// static
-void NativeWidgetMus::NotifyFrameChanged(mus::WindowTreeClient* client) {
- for (mus::Window* window : client->GetRoots()) {
+void NativeWidgetMus::NotifyFrameChanged(ui::WindowTreeClient* client) {
+ for (ui::Window* window : client->GetRoots()) {
NativeWidgetMus* native_widget =
window->GetLocalProperty(kNativeWidgetMusKey);
if (native_widget && native_widget->GetWidget()->non_client_view()) {
@@ -570,11 +571,16 @@ void NativeWidgetMus::NotifyFrameChanged(mus::WindowTreeClient* client) {
}
// static
-Widget* NativeWidgetMus::GetWidgetForWindow(mus::Window* window) {
- if (!window)
- return nullptr;
+NativeWidgetMus* NativeWidgetMus::GetForWindow(ui::Window* window) {
+ DCHECK(window);
NativeWidgetMus* native_widget =
window->GetLocalProperty(kNativeWidgetMusKey);
+ return native_widget;
+}
+
+// static
+Widget* NativeWidgetMus::GetWidgetForWindow(ui::Window* window) {
+ NativeWidgetMus* native_widget = GetForWindow(window);
if (!native_widget)
return nullptr;
return native_widget->GetWidget();
@@ -619,6 +625,9 @@ void NativeWidgetMus::OnActivationChanged(bool active) {
}
void NativeWidgetMus::UpdateClientArea() {
+ if (is_parallel_widget_in_window_manager())
+ return;
+
NonClientView* non_client_view =
native_widget_delegate_->AsWidget()->non_client_view();
if (!non_client_view || !non_client_view->client_view())
@@ -641,28 +650,32 @@ void NativeWidgetMus::ConfigurePropertiesForNewWindow(
properties->insert(init_params.mus_properties.begin(),
init_params.mus_properties.end());
if (!init_params.bounds.IsEmpty()) {
- (*properties)[mus::mojom::WindowManager::kUserSetBounds_Property] =
+ (*properties)[ui::mojom::WindowManager::kUserSetBounds_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(init_params.bounds);
}
if (!init_params.name.empty()) {
- (*properties)[mus::mojom::WindowManager::kName_Property] =
+ (*properties)[ui::mojom::WindowManager::kName_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(init_params.name);
}
- (*properties)[mus::mojom::WindowManager::kAlwaysOnTop_Property] =
+ (*properties)[ui::mojom::WindowManager::kAlwaysOnTop_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(init_params.keep_on_top);
if (!Widget::RequiresNonClientView(init_params.type))
return;
- (*properties)[mus::mojom::WindowManager::kWindowType_Property] =
+ (*properties)[ui::mojom::WindowManager::kWindowType_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(static_cast<int32_t>(
- mojo::ConvertTo<mus::mojom::WindowType>(init_params.type)));
- (*properties)[mus::mojom::WindowManager::kResizeBehavior_Property] =
- mojo::ConvertTo<std::vector<uint8_t>>(
- ResizeBehaviorFromDelegate(init_params.delegate));
+ mojo::ConvertTo<ui::mojom::WindowType>(init_params.type)));
+ if (init_params.delegate &&
+ properties->count(ui::mojom::WindowManager::kResizeBehavior_Property) ==
+ 0) {
+ (*properties)[ui::mojom::WindowManager::kResizeBehavior_Property] =
+ mojo::ConvertTo<std::vector<uint8_t>>(
+ ResizeBehaviorFromDelegate(init_params.delegate));
+ }
SkBitmap app_icon = AppIconFromDelegate(init_params.delegate);
if (!app_icon.isNull()) {
- (*properties)[mus::mojom::WindowManager::kWindowAppIcon_Property] =
+ (*properties)[ui::mojom::WindowManager::kWindowAppIcon_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(app_icon);
}
}
@@ -681,34 +694,51 @@ void NativeWidgetMus::InitNativeWidget(const Widget::InitParams& params) {
ownership_ = params.ownership;
window_->SetCanFocus(params.activatable ==
Widget::InitParams::ACTIVATABLE_YES);
+ window_->SetCanAcceptEvents(params.accept_events);
window_tree_host_->AddObserver(this);
window_tree_host_->InitHost();
hosted_window->SetProperty(kMusWindow, window_);
- focus_client_.reset(
- new FocusControllerMus(new FocusRulesImpl(hosted_window)));
+ // TODO(moshayedi): crbug.com/641039. Investigate whether there are any cases
+ // where we need input method but don't have the WindowManagerConnection here.
+ if (WindowManagerConnection::Exists()) {
+ window_tree_host_->InitInputMethod(
+ WindowManagerConnection::Get()->connector());
+ }
+
+ focus_client_ =
+ base::MakeUnique<FocusControllerMus>(new FocusRulesImpl(hosted_window));
aura::client::SetFocusClient(hosted_window, focus_client_.get());
aura::client::SetActivationClient(hosted_window, focus_client_.get());
- screen_position_client_.reset(new ScreenPositionClientMus(window_));
+ screen_position_client_ = base::MakeUnique<ScreenPositionClientMus>(window_);
aura::client::SetScreenPositionClient(hosted_window,
screen_position_client_.get());
- // TODO(erg): Remove this check when ash/mus/frame/move_event_handler.cc's
- // direct usage of mus::Window::SetPredefinedCursor() is switched to a
+ drag_drop_client_ = base::MakeUnique<DragDropClientMus>(window_);
+ aura::client::SetDragDropClient(hosted_window, drag_drop_client_.get());
+ drop_target_ = base::MakeUnique<DropTargetMus>(content_);
+ window_->SetCanAcceptDrops(drop_target_.get());
+ drop_helper_ = base::MakeUnique<DropHelper>(GetWidget()->GetRootView());
+ aura::client::SetDragDropDelegate(content_, this);
+
+ // TODO(erg): Remove this check when ash/mus/move_event_handler.cc's
+ // direct usage of ui::Window::SetPredefinedCursor() is switched to a
// private method on WindowManagerClient.
- if (surface_type_ == mus::mojom::SurfaceType::DEFAULT) {
- cursor_manager_.reset(new wm::CursorManager(
- base::WrapUnique(new NativeCursorManagerMus(window_))));
+ if (!is_parallel_widget_in_window_manager()) {
+ cursor_manager_ = base::MakeUnique<wm::CursorManager>(
+ base::MakeUnique<NativeCursorManagerMus>(window_));
aura::client::SetCursorClient(hosted_window, cursor_manager_.get());
}
- window_tree_client_.reset(new NativeWidgetMusWindowTreeClient(hosted_window));
+ window_tree_client_ =
+ base::MakeUnique<NativeWidgetMusWindowTreeClient>(hosted_window);
hosted_window->AddPreTargetHandler(focus_client_.get());
hosted_window->SetLayoutManager(
new ContentWindowLayoutManager(hosted_window, content_));
- capture_client_.reset(new MusCaptureClient(hosted_window, content_, window_));
+ capture_client_ =
+ base::MakeUnique<MusCaptureClient>(hosted_window, content_, window_);
content_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
content_->Init(params.layer_type);
@@ -716,12 +746,13 @@ void NativeWidgetMus::InitNativeWidget(const Widget::InitParams& params) {
content_->Show();
content_->SetTransparent(true);
content_->SetFillsBoundsCompletely(false);
+ content_->set_ignore_events(!params.accept_events);
hosted_window->AddChild(content_);
// Set-up transiency if appropriate.
if (params.parent && !params.child) {
aura::Window* parent_root = params.parent->GetRootWindow();
- mus::Window* parent_mus = parent_root->GetProperty(kMusWindow);
+ ui::Window* parent_mus = parent_root->GetProperty(kMusWindow);
if (parent_mus)
parent_mus->AddTransientWindow(window_);
}
@@ -742,23 +773,23 @@ void NativeWidgetMus::OnWidgetInitDone() {
// The client area is calculated from the NonClientView. During
// InitNativeWidget() the NonClientView has not been created. When this
// function is called the NonClientView has been created, so that we can
- // correctly calculate the client area and push it to the mus::Window.
+ // correctly calculate the client area and push it to the ui::Window.
UpdateClientArea();
UpdateHitTestMask();
}
bool NativeWidgetMus::ShouldUseNativeFrame() const {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
return false;
}
bool NativeWidgetMus::ShouldWindowContentsBeTransparent() const {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
return true;
}
void NativeWidgetMus::FrameTypeChanged() {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
Widget* NativeWidgetMus::GetWidget() {
@@ -790,11 +821,11 @@ const ui::Layer* NativeWidgetMus::GetLayer() const {
}
void NativeWidgetMus::ReorderNativeViews() {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
void NativeWidgetMus::ViewRemoved(View* view) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
// These methods are wrong in mojo. They're not usually used to associate
@@ -804,14 +835,14 @@ void NativeWidgetMus::ViewRemoved(View* view) {
// used safely in a world where we separate things with mojo. They should be
// removed; not ported.
void NativeWidgetMus::SetNativeWindowProperty(const char* name, void* value) {
- // TODO(beng): push properties to mus::Window.
- // NOTIMPLEMENTED();
+ native_window_properties_[name] = value;
}
void* NativeWidgetMus::GetNativeWindowProperty(const char* name) const {
- // TODO(beng): pull properties to mus::Window.
- // NOTIMPLEMENTED();
- return nullptr;
+ auto it = native_window_properties_.find(name);
+ if (it == native_window_properties_.end())
+ return nullptr;
+ return it->second;
}
TooltipManager* NativeWidgetMus::GetTooltipManager() const {
@@ -838,9 +869,11 @@ ui::InputMethod* NativeWidgetMus::GetInputMethod() {
}
void NativeWidgetMus::CenterWindow(const gfx::Size& size) {
+ if (is_parallel_widget_in_window_manager())
+ return;
// TODO(beng): clear user-placed property and set preferred size property.
window_->SetSharedProperty<gfx::Size>(
- mus::mojom::WindowManager::kPreferredSize_Property, size);
+ ui::mojom::WindowManager::kPreferredSize_Property, size);
gfx::Rect bounds = display::Screen::GetScreen()
->GetDisplayNearestWindow(content_)
@@ -852,14 +885,14 @@ void NativeWidgetMus::CenterWindow(const gfx::Size& size) {
void NativeWidgetMus::GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* maximized) const {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
bool NativeWidgetMus::SetWindowTitle(const base::string16& title) {
- if (!window_)
+ if (!window_ || is_parallel_widget_in_window_manager())
return false;
const char* kWindowTitle_Property =
- mus::mojom::WindowManager::kWindowTitle_Property;
+ ui::mojom::WindowManager::kWindowTitle_Property;
const base::string16 current_title =
window_->HasSharedProperty(kWindowTitle_Property)
? window_->GetSharedProperty<base::string16>(kWindowTitle_Property)
@@ -872,8 +905,11 @@ bool NativeWidgetMus::SetWindowTitle(const base::string16& title) {
void NativeWidgetMus::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
+ if (is_parallel_widget_in_window_manager())
+ return;
+
const char* const kWindowAppIcon_Property =
- mus::mojom::WindowManager::kWindowAppIcon_Property;
+ ui::mojom::WindowManager::kWindowAppIcon_Property;
if (!app_icon.isNull()) {
// Send the app icon 1x bitmap to the window manager.
@@ -892,7 +928,22 @@ void NativeWidgetMus::InitModalType(ui::ModalType modal_type) {
}
gfx::Rect NativeWidgetMus::GetWindowBoundsInScreen() const {
- return window_ ? window_->GetBoundsInRoot() : gfx::Rect();
+ if (!window_)
+ return gfx::Rect();
+
+ // Correct for the origin of the display.
+ const int64_t window_display_id = window_->GetRoot()->display_id();
+ for (display::Display display :
+ display::Screen::GetScreen()->GetAllDisplays()) {
+ if (display.id() == window_display_id) {
+ gfx::Point display_origin = display.bounds().origin();
+ gfx::Rect bounds_in_screen = window_->GetBoundsInRoot();
+ bounds_in_screen.Offset(display_origin.x(), display_origin.y());
+ return bounds_in_screen;
+ }
+ }
+ // Unknown display, assume primary display at 0,0.
+ return window_->GetBoundsInRoot();
}
gfx::Rect NativeWidgetMus::GetClientAreaBoundsInScreen() const {
@@ -908,7 +959,7 @@ gfx::Rect NativeWidgetMus::GetRestoredBounds() const {
// not in either state.
if (IsMinimized() || IsMaximized() || IsFullscreen()) {
const char* kRestoreBounds_Property =
- mus::mojom::WindowManager::kRestoreBounds_Property;
+ ui::mojom::WindowManager::kRestoreBounds_Property;
if (window_->HasSharedProperty(kRestoreBounds_Property))
return window_->GetSharedProperty<gfx::Rect>(kRestoreBounds_Property);
}
@@ -919,17 +970,26 @@ std::string NativeWidgetMus::GetWorkspace() const {
return std::string();
}
-void NativeWidgetMus::SetBounds(const gfx::Rect& bounds) {
+void NativeWidgetMus::SetBounds(const gfx::Rect& bounds_in_screen) {
if (!(window_ && window_tree_host_))
return;
- gfx::Size size(bounds.size());
+ // TODO(jamescook): Needs something like aura::ScreenPositionClient so higher
+ // level code can move windows between displays. crbug.com/645291
+ gfx::Point origin(bounds_in_screen.origin());
+ const gfx::Point display_origin = display::Screen::GetScreen()
+ ->GetDisplayMatching(bounds_in_screen)
+ .bounds()
+ .origin();
+ origin.Offset(-display_origin.x(), -display_origin.y());
+
+ gfx::Size size(bounds_in_screen.size());
const gfx::Size min_size = GetMinimumSize();
const gfx::Size max_size = GetMaximumSize();
if (!max_size.IsEmpty())
size.SetToMin(max_size);
size.SetToMax(min_size);
- window_->SetBounds(gfx::Rect(bounds.origin(), size));
+ window_->SetBounds(gfx::Rect(origin, size));
// Observer on |window_tree_host_| expected to synchronously update bounds.
DCHECK(window_->bounds() == window_tree_host_->GetBounds());
}
@@ -943,19 +1003,15 @@ void NativeWidgetMus::SetSize(const gfx::Size& size) {
}
void NativeWidgetMus::StackAbove(gfx::NativeView native_view) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
void NativeWidgetMus::StackAtTop() {
- // NOTIMPLEMENTED();
-}
-
-void NativeWidgetMus::StackBelow(gfx::NativeView native_view) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
-void NativeWidgetMus::SetShape(SkRegion* shape) {
- // NOTIMPLEMENTED();
+void NativeWidgetMus::SetShape(std::unique_ptr<SkRegion> shape) {
+ NOTIMPLEMENTED();
}
void NativeWidgetMus::Close() {
@@ -981,28 +1037,52 @@ void NativeWidgetMus::Hide() {
if (!(window_ && window_tree_host_))
return;
- window_tree_host_->Hide();
+ // NOTE: |window_tree_host_| and |window_| visibility is updated in
+ // OnMusWindowVisibilityChanged().
window_->SetVisible(false);
- GetNativeWindow()->Hide();
}
void NativeWidgetMus::ShowMaximizedWithBounds(
const gfx::Rect& restored_bounds) {
- // NOTIMPLEMENTED();
+ if (!window_)
+ return;
+
+ window_->SetSharedProperty<gfx::Rect>(
+ ui::mojom::WindowManager::kRestoreBounds_Property, restored_bounds);
+ ShowWithWindowState(ui::SHOW_STATE_MAXIMIZED);
}
void NativeWidgetMus::ShowWithWindowState(ui::WindowShowState state) {
if (!(window_ && window_tree_host_))
return;
- window_tree_host_->Show();
+ // Matches NativeWidgetAura.
+ switch (state) {
+ case ui::SHOW_STATE_MAXIMIZED:
+ SetShowState(ui::mojom::ShowState::MAXIMIZED);
+ break;
+ case ui::SHOW_STATE_FULLSCREEN:
+ SetShowState(ui::mojom::ShowState::FULLSCREEN);
+ break;
+ case ui::SHOW_STATE_DOCKED:
+ SetShowState(ui::mojom::ShowState::DOCKED);
+ break;
+ default:
+ break;
+ }
+
+ // NOTE: |window_tree_host_| and |window_| visibility is updated in
+ // OnMusWindowVisibilityChanged().
window_->SetVisible(true);
- GetNativeWindow()->Show();
if (native_widget_delegate_->CanActivate()) {
if (state != ui::SHOW_STATE_INACTIVE)
Activate();
GetWidget()->SetInitialFocus(state);
}
+
+ // Matches NativeWidgetAura.
+ if (state == ui::SHOW_STATE_MINIMIZED)
+ Minimize();
}
bool NativeWidgetMus::IsVisible() const {
@@ -1024,71 +1104,73 @@ void NativeWidgetMus::Deactivate() {
}
bool NativeWidgetMus::IsActive() const {
- mus::Window* focused =
+ ui::Window* focused =
window_ ? window_->window_tree()->GetFocusedWindow() : nullptr;
return focused && window_->Contains(focused);
}
void NativeWidgetMus::SetAlwaysOnTop(bool always_on_top) {
- if (window_) {
+ if (window_ && !is_parallel_widget_in_window_manager()) {
window_->SetSharedProperty<bool>(
- mus::mojom::WindowManager::kAlwaysOnTop_Property, always_on_top);
+ ui::mojom::WindowManager::kAlwaysOnTop_Property, always_on_top);
}
}
bool NativeWidgetMus::IsAlwaysOnTop() const {
return window_ &&
window_->HasSharedProperty(
- mus::mojom::WindowManager::kAlwaysOnTop_Property) &&
+ ui::mojom::WindowManager::kAlwaysOnTop_Property) &&
window_->GetSharedProperty<bool>(
- mus::mojom::WindowManager::kAlwaysOnTop_Property);
+ ui::mojom::WindowManager::kAlwaysOnTop_Property);
}
void NativeWidgetMus::SetVisibleOnAllWorkspaces(bool always_visible) {
// Not needed for chromeos.
}
+bool NativeWidgetMus::IsVisibleOnAllWorkspaces() const {
+ return false;
+}
+
void NativeWidgetMus::Maximize() {
- SetShowState(mus::mojom::ShowState::MAXIMIZED);
+ SetShowState(ui::mojom::ShowState::MAXIMIZED);
}
void NativeWidgetMus::Minimize() {
- SetShowState(mus::mojom::ShowState::MINIMIZED);
+ SetShowState(ui::mojom::ShowState::MINIMIZED);
}
bool NativeWidgetMus::IsMaximized() const {
- return mus_window_observer_ &&
- mus_window_observer_->show_state() == mus::mojom::ShowState::MAXIMIZED;
+ return GetShowState(window_) == ui::mojom::ShowState::MAXIMIZED;
}
bool NativeWidgetMus::IsMinimized() const {
- return mus_window_observer_ &&
- mus_window_observer_->show_state() == mus::mojom::ShowState::MINIMIZED;
+ return GetShowState(window_) == ui::mojom::ShowState::MINIMIZED;
}
void NativeWidgetMus::Restore() {
- SetShowState(mus::mojom::ShowState::NORMAL);
+ SetShowState(ui::mojom::ShowState::NORMAL);
}
void NativeWidgetMus::SetFullscreen(bool fullscreen) {
if (IsFullscreen() == fullscreen)
return;
if (fullscreen) {
- show_state_before_fullscreen_ = mus_window_observer_->show_state();
- // TODO(markdittmer): Fullscreen not implemented in mus::Window.
+ show_state_before_fullscreen_ = GetShowState(window_);
+ SetShowState(ui::mojom::ShowState::FULLSCREEN);
} else {
switch (show_state_before_fullscreen_) {
- case mus::mojom::ShowState::MAXIMIZED:
+ case ui::mojom::ShowState::MAXIMIZED:
Maximize();
break;
- case mus::mojom::ShowState::MINIMIZED:
+ case ui::mojom::ShowState::MINIMIZED:
Minimize();
break;
- case mus::mojom::ShowState::DEFAULT:
- case mus::mojom::ShowState::NORMAL:
- case mus::mojom::ShowState::INACTIVE:
- case mus::mojom::ShowState::FULLSCREEN:
- case mus::mojom::ShowState::DOCKED:
+ case ui::mojom::ShowState::DEFAULT:
+ case ui::mojom::ShowState::NORMAL:
+ case ui::mojom::ShowState::INACTIVE:
+ case ui::mojom::ShowState::FULLSCREEN:
+ case ui::mojom::ShowState::DOCKED:
// TODO(sad): This may not be sufficient.
Restore();
break;
@@ -1097,8 +1179,7 @@ void NativeWidgetMus::SetFullscreen(bool fullscreen) {
}
bool NativeWidgetMus::IsFullscreen() const {
- return mus_window_observer_ &&
- mus_window_observer_->show_state() == mus::mojom::ShowState::FULLSCREEN;
+ return GetShowState(window_) == ui::mojom::ShowState::FULLSCREEN;
}
void NativeWidgetMus::SetOpacity(float opacity) {
@@ -1107,16 +1188,16 @@ void NativeWidgetMus::SetOpacity(float opacity) {
}
void NativeWidgetMus::FlashFrame(bool flash_frame) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
-void NativeWidgetMus::RunShellDrag(
- View* view,
- const ui::OSExchangeData& data,
- const gfx::Point& location,
- int operation,
- ui::DragDropTypes::DragEventSource source) {
- // NOTIMPLEMENTED();
+void NativeWidgetMus::RunShellDrag(View* view,
+ const ui::OSExchangeData& data,
+ const gfx::Point& location,
+ int drag_operations,
+ ui::DragDropTypes::DragEventSource source) {
+ if (window_)
+ views::RunShellDrag(content_, data, location, drag_operations, source);
}
void NativeWidgetMus::SchedulePaintInRect(const gfx::Rect& rect) {
@@ -1134,20 +1215,20 @@ void NativeWidgetMus::SetCursor(gfx::NativeCursor cursor) {
// also send an image, but as the cursor code is currently written, the image
// is in a platform native format that's already uploaded to the window
// server.
- mus::mojom::Cursor new_cursor = mus::mojom::Cursor(cursor.native_type());
+ ui::mojom::Cursor new_cursor = ui::mojom::Cursor(cursor.native_type());
if (last_cursor_ != new_cursor)
window_->SetPredefinedCursor(new_cursor);
}
bool NativeWidgetMus::IsMouseEventsEnabled() const {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
return true;
}
void NativeWidgetMus::ClearNativeFocus() {
if (!IsActive())
return;
- mus::Window* focused =
+ ui::Window* focused =
window_ ? window_->window_tree()->GetFocusedWindow() : nullptr;
if (focused && window_->Contains(focused) && focused != window_)
window_->SetFocus();
@@ -1158,7 +1239,7 @@ void NativeWidgetMus::ClearNativeFocus() {
}
gfx::Rect NativeWidgetMus::GetWorkAreaBoundsInScreen() const {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
return gfx::Rect();
}
@@ -1166,26 +1247,45 @@ Widget::MoveLoopResult NativeWidgetMus::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
- // NOTIMPLEMENTED();
- return Widget::MOVE_LOOP_CANCELED;
+ ReleaseCapture();
+
+ base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
+ base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
+ base::RunLoop run_loop;
+
+ ui::mojom::MoveLoopSource mus_source =
+ source == Widget::MOVE_LOOP_SOURCE_MOUSE
+ ? ui::mojom::MoveLoopSource::MOUSE
+ : ui::mojom::MoveLoopSource::TOUCH;
+
+ bool success = false;
+ gfx::Point cursor_location =
+ display::Screen::GetScreen()->GetCursorScreenPoint();
+ window_->PerformWindowMove(
+ mus_source, cursor_location,
+ base::Bind(OnMoveLoopEnd, &success, run_loop.QuitClosure()));
+
+ run_loop.Run();
+
+ return success ? Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
}
void NativeWidgetMus::EndMoveLoop() {
- // NOTIMPLEMENTED();
+ window_->CancelWindowMove();
}
void NativeWidgetMus::SetVisibilityChangedAnimationsEnabled(bool value) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
void NativeWidgetMus::SetVisibilityAnimationDuration(
const base::TimeDelta& duration) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
void NativeWidgetMus::SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
ui::NativeTheme* NativeWidgetMus::GetNativeTheme() const {
@@ -1193,25 +1293,25 @@ ui::NativeTheme* NativeWidgetMus::GetNativeTheme() const {
}
void NativeWidgetMus::OnRootViewLayout() {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
bool NativeWidgetMus::IsTranslucentWindowOpacitySupported() const {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
return true;
}
void NativeWidgetMus::OnSizeConstraintsChanged() {
- if (!window_)
+ if (!window_ || is_parallel_widget_in_window_manager())
return;
window_->SetSharedProperty<int32_t>(
- mus::mojom::WindowManager::kResizeBehavior_Property,
+ ui::mojom::WindowManager::kResizeBehavior_Property,
ResizeBehaviorFromDelegate(GetWidget()->widget_delegate()));
}
void NativeWidgetMus::RepostNativeEvent(gfx::NativeEvent native_event) {
- // NOTIMPLEMENTED();
+ NOTIMPLEMENTED();
}
std::string NativeWidgetMus::GetName() const {
@@ -1231,18 +1331,8 @@ gfx::Size NativeWidgetMus::GetMaximumSize() const {
void NativeWidgetMus::OnBoundsChanged(const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
- // Assume that if the old bounds was completely empty a move happened. This
- // handles the case of a maximize animation acquiring the layer (acquiring a
- // layer results in clearing the bounds).
- if (old_bounds.origin() != new_bounds.origin() ||
- (old_bounds == gfx::Rect(0, 0, 0, 0) && !new_bounds.IsEmpty())) {
- native_widget_delegate_->OnNativeWidgetMove();
- }
- if (old_bounds.size() != new_bounds.size()) {
- native_widget_delegate_->OnNativeWidgetSizeChanged(new_bounds.size());
- UpdateClientArea();
- UpdateHitTestMask();
- }
+ // This is handled in OnHost{Resized,Moved}() like DesktopNativeWidgetAura
+ // instead of here like in NativeWidgetAura.
}
gfx::NativeCursor NativeWidgetMus::GetCursor(const gfx::Point& point) {
@@ -1294,11 +1384,11 @@ void NativeWidgetMus::GetHitTestMask(gfx::Path* mask) const {
native_widget_delegate_->GetHitTestMask(mask);
}
-void NativeWidgetMus::SetShowState(mus::mojom::ShowState show_state) {
+void NativeWidgetMus::SetShowState(ui::mojom::ShowState show_state) {
if (!window_)
return;
window_->SetSharedProperty<int32_t>(
- mus::mojom::WindowManager::kShowState_Property,
+ ui::mojom::WindowManager::kShowState_Property,
static_cast<int32_t>(show_state));
}
@@ -1345,12 +1435,54 @@ void NativeWidgetMus::OnGestureEvent(ui::GestureEvent* event) {
native_widget_delegate_->OnGestureEvent(event);
}
+void NativeWidgetMus::OnHostResized(const aura::WindowTreeHost* host) {
+ native_widget_delegate_->OnNativeWidgetSizeChanged(
+ host->window()->bounds().size());
+ UpdateClientArea();
+ UpdateHitTestMask();
+}
+
+void NativeWidgetMus::OnHostMoved(const aura::WindowTreeHost* host,
+ const gfx::Point& new_origin) {
+ native_widget_delegate_->OnNativeWidgetMove();
+}
+
void NativeWidgetMus::OnHostCloseRequested(const aura::WindowTreeHost* host) {
GetWidget()->Close();
}
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetMus, aura::WindowDragDropDelegate implementation:
+
+void NativeWidgetMus::OnDragEntered(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_);
+ last_drop_operation_ = drop_helper_->OnDragOver(
+ event.data(), event.location(), event.source_operations());
+}
+
+int NativeWidgetMus::OnDragUpdated(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_);
+ last_drop_operation_ = drop_helper_->OnDragOver(
+ event.data(), event.location(), event.source_operations());
+ return last_drop_operation_;
+}
+
+void NativeWidgetMus::OnDragExited() {
+ DCHECK(drop_helper_);
+ drop_helper_->OnDragExit();
+}
+
+int NativeWidgetMus::OnPerformDrop(const ui::DropTargetEvent& event) {
+ DCHECK(drop_helper_);
+ return drop_helper_->OnDrop(event.data(), event.location(),
+ last_drop_operation_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeWidgetMus, ui::InputEventHandler implementation:
+
void NativeWidgetMus::OnWindowInputEvent(
- mus::Window* view,
+ ui::Window* view,
const ui::Event& event_in,
std::unique_ptr<base::Callback<void(EventResult)>>* ack_callback) {
// Take ownership of the callback, indicating that we will handle it.
@@ -1366,31 +1498,31 @@ void NativeWidgetMus::OnWindowInputEvent(
// |ack_handler| acks the event on destruction if necessary.
}
-void NativeWidgetMus::OnMusWindowVisibilityChanging(mus::Window* window) {
- if (window == window_) {
- native_widget_delegate_->OnNativeWidgetVisibilityChanging(
- !window->visible());
- }
+void NativeWidgetMus::OnMusWindowVisibilityChanging(ui::Window* window,
+ bool visible) {
+ if (window == window_)
+ native_widget_delegate_->OnNativeWidgetVisibilityChanging(visible);
}
-void NativeWidgetMus::OnMusWindowVisibilityChanged(mus::Window* window) {
+void NativeWidgetMus::OnMusWindowVisibilityChanged(ui::Window* window,
+ bool visible) {
if (window != window_)
return;
- if (window->visible()) {
+ if (visible) {
window_tree_host_->Show();
GetNativeWindow()->Show();
} else {
window_tree_host_->Hide();
GetNativeWindow()->Hide();
}
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(window->visible());
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
}
void NativeWidgetMus::UpdateHitTestMask() {
// The window manager (or other underlay window provider) is not allowed to
// set a hit test mask, as that could interfere with a client app mask.
- if (surface_type_ == mus::mojom::SurfaceType::UNDERLAY)
+ if (is_parallel_widget_in_window_manager())
return;
if (!native_widget_delegate_->HasHitTestMask()) {
diff --git a/chromium/ui/views/mus/native_widget_mus.h b/chromium/ui/views/mus/native_widget_mus.h
index 33da5378358..3e7f7412ced 100644
--- a/chromium/ui/views/mus/native_widget_mus.h
+++ b/chromium/ui/views/mus/native_widget_mus.h
@@ -10,33 +10,32 @@
#include <map>
#include <memory>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/mus/public/cpp/input_event_handler.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
+#include "services/ui/public/cpp/input_event_handler.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tree_host_observer.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/mus/window_tree_host_mus.h"
#include "ui/views/widget/native_widget_private.h"
+#include "ui/wm/public/drag_drop_delegate.h"
namespace aura {
namespace client {
class DefaultCaptureClient;
+class DragDropClient;
class ScreenPositionClient;
class WindowTreeClient;
}
class Window;
}
-namespace bitmap_uploader {
-class BitmapUploader;
-}
-
-namespace mus {
+namespace ui {
class Window;
class WindowTreeClient;
namespace mojom {
@@ -45,13 +44,8 @@ enum class EventResult;
}
}
-namespace shell {
-class Connector;
-}
-
namespace ui {
class Event;
-class ViewProp;
}
namespace wm {
@@ -60,12 +54,13 @@ class FocusController;
}
namespace views {
-class SurfaceContextFactory;
+class DropHelper;
+class DropTargetMus;
class WidgetDelegate;
-// An implementation of NativeWidget that binds to a mus::Window. Because Aura
+// An implementation of NativeWidget that binds to a ui::Window. Because Aura
// is used extensively within Views code, this code uses aura and binds to the
-// mus::Window via a Mus-specific aura::WindowTreeHost impl. Because the root
+// ui::Window via a Mus-specific aura::WindowTreeHost impl. Because the root
// aura::Window in a hierarchy is created without a delegate by the
// aura::WindowTreeHost, we must create a child aura::Window in this class
// (content_) and attach it to the root.
@@ -73,12 +68,12 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
: public internal::NativeWidgetPrivate,
public aura::WindowDelegate,
public aura::WindowTreeHostObserver,
- public NON_EXPORTED_BASE(mus::InputEventHandler) {
+ public aura::client::DragDropDelegate,
+ public NON_EXPORTED_BASE(ui::InputEventHandler) {
public:
NativeWidgetMus(internal::NativeWidgetDelegate* delegate,
- shell::Connector* connector,
- mus::Window* window,
- mus::mojom::SurfaceType surface_type);
+ ui::Window* window,
+ ui::mojom::SurfaceType surface_type);
~NativeWidgetMus() override;
// Configures the set of properties supplied to the window manager when
@@ -88,12 +83,16 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
std::map<std::string, std::vector<uint8_t>>* properties);
// Notifies all widgets the frame constants changed in some way.
- static void NotifyFrameChanged(mus::WindowTreeClient* client);
+ static void NotifyFrameChanged(ui::WindowTreeClient* client);
+
+ // Returns the native widget for a ui::Window, or null if there is none.
+ static NativeWidgetMus* GetForWindow(ui::Window* window);
- // Returns the widget for a mus::Window, or null if there is none.
- static Widget* GetWidgetForWindow(mus::Window* window);
+ // Returns the widget for a ui::Window, or null if there is none.
+ static Widget* GetWidgetForWindow(ui::Window* window);
- mus::Window* window() { return window_; }
+ ui::mojom::SurfaceType surface_type() const { return surface_type_; }
+ ui::Window* window() { return window_; }
WindowTreeHostMus* window_tree_host() { return window_tree_host_.get(); }
aura::Window* GetRootWindow();
@@ -102,7 +101,7 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
void OnActivationChanged(bool active);
protected:
- // Updates the client area in the mus::Window.
+ // Updates the client area in the ui::Window.
virtual void UpdateClientArea();
// internal::NativeWidgetPrivate:
@@ -139,12 +138,11 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
gfx::Rect GetClientAreaBoundsInScreen() const override;
gfx::Rect GetRestoredBounds() const override;
std::string GetWorkspace() const override;
- void SetBounds(const gfx::Rect& bounds) override;
+ void SetBounds(const gfx::Rect& bounds_in_screen) override;
void SetSize(const gfx::Size& size) override;
void StackAbove(gfx::NativeView native_view) override;
void StackAtTop() override;
- void StackBelow(gfx::NativeView native_view) override;
- void SetShape(SkRegion* shape) override;
+ void SetShape(std::unique_ptr<SkRegion> shape) override;
void Close() override;
void CloseNow() override;
void Show() override;
@@ -158,6 +156,7 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
void SetAlwaysOnTop(bool always_on_top) override;
bool IsAlwaysOnTop() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
void Maximize() override;
void Minimize() override;
bool IsMaximized() const override;
@@ -170,7 +169,7 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
void RunShellDrag(View* view,
const ui::OSExchangeData& data,
const gfx::Point& location,
- int operation,
+ int drag_operations,
ui::DragDropTypes::DragEventSource source) override;
void SchedulePaintInRect(const gfx::Rect& rect) override;
void SetCursor(gfx::NativeCursor cursor) override;
@@ -220,16 +219,25 @@ class VIEWS_MUS_EXPORT NativeWidgetMus
void OnGestureEvent(ui::GestureEvent* event) override;
// Overridden from aura::WindowTreeHostObserver:
+ void OnHostResized(const aura::WindowTreeHost* host) override;
+ void OnHostMoved(const aura::WindowTreeHost* host,
+ const gfx::Point& new_origin) override;
void OnHostCloseRequested(const aura::WindowTreeHost* host) override;
- // Overridden from mus::InputEventHandler:
+ // Overridden from aura::client::DragDropDelegate:
+ void OnDragEntered(const ui::DropTargetEvent& event) override;
+ int OnDragUpdated(const ui::DropTargetEvent& event) override;
+ void OnDragExited() override;
+ int OnPerformDrop(const ui::DropTargetEvent& event) override;
+
+ // Overridden from ui::InputEventHandler:
void OnWindowInputEvent(
- mus::Window* view,
+ ui::Window* view,
const ui::Event& event,
- std::unique_ptr<base::Callback<void(mus::mojom::EventResult)>>*
+ std::unique_ptr<base::Callback<void(ui::mojom::EventResult)>>*
ack_callback) override;
-private:
+ private:
friend class NativeWidgetMusTest;
class MusWindowObserver;
class MusCaptureClient;
@@ -238,45 +246,58 @@ private:
return window_tree_host();
}
- void set_last_cursor(mus::mojom::Cursor cursor) { last_cursor_ = cursor; }
- void SetShowState(mus::mojom::ShowState show_state);
+ // Returns true if this NativeWidgetMus exists on the window manager side
+ // to provide the frame decorations.
+ bool is_parallel_widget_in_window_manager() {
+ return surface_type_ == ui::mojom::SurfaceType::UNDERLAY;
+ }
+
+ void set_last_cursor(ui::mojom::Cursor cursor) { last_cursor_ = cursor; }
+ void SetShowState(ui::mojom::ShowState show_state);
- void OnMusWindowVisibilityChanging(mus::Window* window);
- void OnMusWindowVisibilityChanged(mus::Window* window);
+ void OnMusWindowVisibilityChanging(ui::Window* window, bool visible);
+ void OnMusWindowVisibilityChanged(ui::Window* window, bool visible);
- // Propagates the widget hit test mask, if any, to the mus::Window.
+ // Propagates the widget hit test mask, if any, to the ui::Window.
// TODO(jamescook): Wire this through views::Widget so widgets can push
// updates if needed.
void UpdateHitTestMask();
- mus::Window* window_;
- mus::mojom::Cursor last_cursor_;
+ ui::Window* window_;
+ ui::mojom::Cursor last_cursor_;
internal::NativeWidgetDelegate* native_widget_delegate_;
- const mus::mojom::SurfaceType surface_type_;
- mus::mojom::ShowState show_state_before_fullscreen_;
+ const ui::mojom::SurfaceType surface_type_;
+ ui::mojom::ShowState show_state_before_fullscreen_;
// See class documentation for Widget in widget.h for a note about ownership.
Widget::InitParams::Ownership ownership_;
- // Functions with the same name require the mus::WindowObserver to be in
+ // Functions with the same name require the ui::WindowObserver to be in
// a separate class.
std::unique_ptr<MusWindowObserver> mus_window_observer_;
+ // This is misnamed; The native widget interface offers something called
+ // "native window properties" which are properties which it stores locally,
+ // and this is used to unsafely pass void* pointers around chrome.
+ std::map<std::string, void*> native_window_properties_;
+
+ // Receives drop events for |window_|.
+ std::unique_ptr<DropTargetMus> drop_target_;
+
// Aura configuration.
- std::unique_ptr<SurfaceContextFactory> context_factory_;
std::unique_ptr<WindowTreeHostMus> window_tree_host_;
aura::Window* content_;
std::unique_ptr<wm::FocusController> focus_client_;
std::unique_ptr<MusCaptureClient> capture_client_;
+ std::unique_ptr<aura::client::DragDropClient> drag_drop_client_;
std::unique_ptr<aura::client::WindowTreeClient> window_tree_client_;
std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_;
std::unique_ptr<wm::CursorManager> cursor_manager_;
- // Bitmap management.
- std::unique_ptr<bitmap_uploader::BitmapUploader> bitmap_uploader_;
- std::unique_ptr<ui::ViewProp> prop_;
+ std::unique_ptr<DropHelper> drop_helper_;
+ int last_drop_operation_;
base::WeakPtrFactory<NativeWidgetMus> close_widget_factory_;
diff --git a/chromium/ui/views/mus/native_widget_mus_unittest.cc b/chromium/ui/views/mus/native_widget_mus_unittest.cc
index 6bad3b8f876..559a1f24191 100644
--- a/chromium/ui/views/mus/native_widget_mus_unittest.cc
+++ b/chromium/ui/views/mus/native_widget_mus_unittest.cc
@@ -6,13 +6,14 @@
#include "base/callback.h"
#include "base/macros.h"
-#include "components/mus/public/cpp/property_type_converters.h"
-#include "components/mus/public/cpp/tests/window_tree_client_private.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_property.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
+#include "services/ui/public/cpp/property_type_converters.h"
+#include "services/ui/public/cpp/tests/window_tree_client_private.h"
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/cpp/window_observer.h"
+#include "services/ui/public/cpp/window_property.h"
+#include "services/ui/public/cpp/window_tree_client.h"
+#include "services/ui/public/interfaces/window_manager.mojom.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -24,6 +25,7 @@
#include "ui/gfx/path.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/mus/window_manager_connection.h"
#include "ui/views/test/focus_manager_test.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
@@ -31,7 +33,7 @@
#include "ui/views/widget/widget_observer.h"
#include "ui/wm/public/activation_client.h"
-using mus::mojom::EventResult;
+using ui::mojom::EventResult;
namespace views {
namespace {
@@ -161,26 +163,26 @@ class NativeWidgetMusTest : public ViewsTestBase {
int ack_callback_count() { return ack_callback_count_; }
- void AckCallback(mus::mojom::EventResult result) {
+ void AckCallback(ui::mojom::EventResult result) {
ack_callback_count_++;
- EXPECT_EQ(mus::mojom::EventResult::HANDLED, result);
+ EXPECT_EQ(ui::mojom::EventResult::HANDLED, result);
}
// Returns a mouse pressed event inside the widget. Tests that place views
// within the widget that respond to the event must be constructed within the
// widget coordinate space such that they respond correctly.
std::unique_ptr<ui::MouseEvent> CreateMouseEvent() {
- return base::WrapUnique(new ui::MouseEvent(
+ return base::MakeUnique<ui::MouseEvent>(
ui::ET_MOUSE_PRESSED, gfx::Point(50, 50), gfx::Point(50, 50),
- base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+ base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
}
// Simulates an input event to the NativeWidget.
void OnWindowInputEvent(
NativeWidgetMus* native_widget,
const ui::Event& event,
- std::unique_ptr<base::Callback<void(mus::mojom::EventResult)>>*
- ack_callback) {
+ std::unique_ptr<base::Callback<void(ui::mojom::EventResult)>>*
+ ack_callback) {
native_widget->OnWindowInputEvent(native_widget->window(), event,
ack_callback);
}
@@ -246,39 +248,39 @@ TEST_F(NativeWidgetMusTest, ShowNonActivatableWidget) {
EXPECT_EQ(0u, activation_observer.changes().size());
}
-// Tests that a window with an icon sets the mus::Window icon property.
+// Tests that a window with an icon sets the ui::Window icon property.
TEST_F(NativeWidgetMusTest, AppIcon) {
// Create a Widget with a bitmap as the icon.
SkBitmap source_bitmap = MakeBitmap(SK_ColorRED);
std::unique_ptr<Widget> widget(
CreateWidget(new TestWidgetDelegate(source_bitmap)));
- // The mus::Window has the icon property.
- mus::Window* window =
+ // The ui::Window has the icon property.
+ ui::Window* window =
static_cast<NativeWidgetMus*>(widget->native_widget_private())->window();
EXPECT_TRUE(window->HasSharedProperty(
- mus::mojom::WindowManager::kWindowAppIcon_Property));
+ ui::mojom::WindowManager::kWindowAppIcon_Property));
// The icon is the expected icon.
SkBitmap icon = window->GetSharedProperty<SkBitmap>(
- mus::mojom::WindowManager::kWindowAppIcon_Property);
+ ui::mojom::WindowManager::kWindowAppIcon_Property);
EXPECT_TRUE(gfx::BitmapsAreEqual(source_bitmap, icon));
}
-// Tests that a window without an icon does not set the mus::Window icon
+// Tests that a window without an icon does not set the ui::Window icon
// property.
TEST_F(NativeWidgetMusTest, NoAppIcon) {
// Create a Widget without a special icon.
std::unique_ptr<Widget> widget(CreateWidget(nullptr));
- // The mus::Window does not have an icon property.
- mus::Window* window =
+ // The ui::Window does not have an icon property.
+ ui::Window* window =
static_cast<NativeWidgetMus*>(widget->native_widget_private())->window();
EXPECT_FALSE(window->HasSharedProperty(
- mus::mojom::WindowManager::kWindowAppIcon_Property));
+ ui::mojom::WindowManager::kWindowAppIcon_Property));
}
-// Tests that changing the icon on a Widget updates the mus::Window icon
+// Tests that changing the icon on a Widget updates the ui::Window icon
// property.
TEST_F(NativeWidgetMusTest, ChangeAppIcon) {
// Create a Widget with an icon.
@@ -292,10 +294,10 @@ TEST_F(NativeWidgetMusTest, ChangeAppIcon) {
widget->UpdateWindowIcon();
// The window has the updated icon.
- mus::Window* window =
+ ui::Window* window =
static_cast<NativeWidgetMus*>(widget->native_widget_private())->window();
SkBitmap icon = window->GetSharedProperty<SkBitmap>(
- mus::mojom::WindowManager::kWindowAppIcon_Property);
+ ui::mojom::WindowManager::kWindowAppIcon_Property);
EXPECT_TRUE(gfx::BitmapsAreEqual(bitmap2, icon));
}
@@ -308,33 +310,33 @@ TEST_F(NativeWidgetMusTest, ValidLayerTree) {
}
// Tests that the internal name is propagated from the Widget to the
-// mus::Window.
+// ui::Window.
TEST_F(NativeWidgetMusTest, GetName) {
Widget widget;
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.name = "MyWidget";
widget.Init(params);
- mus::Window* window =
+ ui::Window* window =
static_cast<NativeWidgetMus*>(widget.native_widget_private())->window();
EXPECT_EQ("MyWidget", window->GetName());
}
// Tests that a Widget with a hit test mask propagates the mask to the
-// mus::Window.
+// ui::Window.
TEST_F(NativeWidgetMusTest, HitTestMask) {
gfx::Rect mask(5, 5, 10, 10);
std::unique_ptr<Widget> widget(
CreateWidget(new WidgetDelegateWithHitTestMask(mask)));
// The window has the mask.
- mus::Window* window =
+ ui::Window* window =
static_cast<NativeWidgetMus*>(widget->native_widget_private())->window();
ASSERT_TRUE(window->hit_test_mask());
EXPECT_EQ(mask.ToString(), window->hit_test_mask()->ToString());
}
-// Verifies changing the visibility of a child mus::Window doesn't change the
+// Verifies changing the visibility of a child ui::Window doesn't change the
// visibility of the parent.
TEST_F(NativeWidgetMusTest, ChildVisibilityDoesntEffectParent) {
Widget widget;
@@ -342,13 +344,13 @@ TEST_F(NativeWidgetMusTest, ChildVisibilityDoesntEffectParent) {
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
widget.Init(params);
widget.Show();
- mus::Window* window =
+ ui::Window* window =
static_cast<NativeWidgetMus*>(widget.native_widget_private())->window();
ASSERT_TRUE(window->visible());
// Create a child window, make it visible and parent it to the Widget's
// window.
- mus::Window* child_window = window->window_tree()->NewWindow();
+ ui::Window* child_window = window->window_tree()->NewWindow();
child_window->SetVisible(true);
window->AddChild(child_window);
@@ -416,7 +418,7 @@ TEST_F(NativeWidgetMusTest, WidgetReceivesEvent) {
std::unique_ptr<ui::MouseEvent> mouse = CreateMouseEvent();
NativeWidgetMus* native_widget =
static_cast<NativeWidgetMus*>(widget->native_widget_private());
- mus::WindowTreeClientPrivate test_api(native_widget->window());
+ ui::WindowTreeClientPrivate test_api(native_widget->window());
test_api.CallOnWindowInputEvent(native_widget->window(), std::move(mouse));
EXPECT_EQ(1, handler.num_mouse_events());
}
@@ -480,7 +482,7 @@ TEST_F(NativeWidgetMusTest, SetAndReleaseCapture) {
widget->GetContentsView()->AddChildView(content);
internal::NativeWidgetPrivate* widget_private =
widget->native_widget_private();
- mus::Window* mus_window =
+ ui::Window* mus_window =
static_cast<NativeWidgetMus*>(widget_private)->window();
EXPECT_FALSE(widget_private->HasCapture());
EXPECT_FALSE(mus_window->HasCapture());
@@ -494,7 +496,7 @@ TEST_F(NativeWidgetMusTest, SetAndReleaseCapture) {
EXPECT_FALSE(mus_window->HasCapture());
}
-// Ensure that manually setting NativeWidgetMus's mus::Window bounds also
+// Ensure that manually setting NativeWidgetMus's ui::Window bounds also
// updates its WindowTreeHost bounds.
TEST_F(NativeWidgetMusTest, SetMusWindowBounds) {
std::unique_ptr<Widget> widget(CreateWidget(nullptr));
@@ -503,7 +505,7 @@ TEST_F(NativeWidgetMusTest, SetMusWindowBounds) {
widget->GetContentsView()->AddChildView(content);
NativeWidgetMus* native_widget =
static_cast<NativeWidgetMus*>(widget->native_widget_private());
- mus::Window* mus_window = native_widget->window();
+ ui::Window* mus_window = native_widget->window();
gfx::Rect start_bounds = initial_bounds();
gfx::Rect end_bounds = gfx::Rect(40, 50, 60, 70);
@@ -521,4 +523,90 @@ TEST_F(NativeWidgetMusTest, SetMusWindowBounds) {
EXPECT_EQ(end_bounds, native_widget->window_tree_host()->GetBounds());
}
+// Verifies visibility of the aura::Window and ui::Window are updated when the
+// Widget is shown/hidden.
+TEST_F(NativeWidgetMusTest, TargetVisibility) {
+ std::unique_ptr<Widget> widget(CreateWidget(nullptr));
+ NativeWidgetMus* native_widget =
+ static_cast<NativeWidgetMus*>(widget->native_widget_private());
+ ui::Window* mus_window = native_widget->window();
+ EXPECT_FALSE(mus_window->visible());
+ EXPECT_FALSE(widget->GetNativeView()->TargetVisibility());
+
+ widget->Show();
+ EXPECT_TRUE(mus_window->visible());
+ EXPECT_TRUE(widget->GetNativeView()->TargetVisibility());
+}
+
+// Indirectly verifies Show() isn't invoked twice on the underlying
+// aura::Window.
+TEST_F(NativeWidgetMusTest, DontShowTwice) {
+ std::unique_ptr<Widget> widget(CreateWidget(nullptr));
+ widget->GetNativeView()->layer()->SetOpacity(0.0f);
+ // aura::Window::Show() allows the opacity to be 0 as long as the window is
+ // hidden. So, as long as this only invokes aura::Window::Show() once the
+ // DCHECK in aura::Window::Show() won't fire.
+ widget->Show();
+}
+
+namespace {
+
+// See description of test for details.
+class IsMaximizedObserver : public ui::WindowObserver {
+ public:
+ IsMaximizedObserver() {}
+ ~IsMaximizedObserver() override {}
+
+ void set_widget(Widget* widget) { widget_ = widget; }
+
+ bool got_change() const { return got_change_; }
+
+ // ui::WindowObserver:
+ void OnWindowSharedPropertyChanged(
+ ui::Window* window,
+ const std::string& name,
+ const std::vector<uint8_t>* old_data,
+ const std::vector<uint8_t>* new_data) override {
+ // Expect only one change for the show state.
+ ASSERT_FALSE(got_change_);
+ got_change_ = true;
+ EXPECT_EQ(ui::mojom::WindowManager::kShowState_Property, name);
+ EXPECT_TRUE(widget_->IsMaximized());
+ }
+
+ private:
+ bool got_change_ = false;
+ Widget* widget_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(IsMaximizedObserver);
+};
+
+} // namespace
+
+// Verifies that asking for Widget::IsMaximized() from within
+// OnWindowSharedPropertyChanged() returns the right thing.
+TEST_F(NativeWidgetMusTest, IsMaximized) {
+ ASSERT_TRUE(WindowManagerConnection::Exists());
+ ui::Window* window = WindowManagerConnection::Get()->NewWindow(
+ std::map<std::string, std::vector<uint8_t>>());
+ IsMaximizedObserver observer;
+ // NOTE: the order here is important, we purposefully add the
+ // ui::WindowObserver before creating NativeWidgetMus, which also adds its
+ // own observer.
+ window->AddObserver(&observer);
+
+ std::unique_ptr<Widget> widget(new Widget());
+ observer.set_widget(widget.get());
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = initial_bounds();
+ params.native_widget = new NativeWidgetMus(widget.get(), window,
+ ui::mojom::SurfaceType::DEFAULT);
+ widget->Init(params);
+ window->SetSharedProperty<int32_t>(
+ ui::mojom::WindowManager::kShowState_Property,
+ static_cast<uint32_t>(ui::mojom::ShowState::MAXIMIZED));
+ EXPECT_TRUE(widget->IsMaximized());
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/os_exchange_data_provider_mus.cc b/chromium/ui/views/mus/os_exchange_data_provider_mus.cc
new file mode 100644
index 00000000000..7d47924848a
--- /dev/null
+++ b/chromium/ui/views/mus/os_exchange_data_provider_mus.cc
@@ -0,0 +1,372 @@
+// Copyright 2016 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/mus/os_exchange_data_provider_mus.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "mojo/common/common_type_converters.h"
+#include "net/base/filename_util.h"
+#include "services/ui/public/interfaces/clipboard.mojom.h"
+#include "ui/base/dragdrop/file_info.h"
+#include "url/gurl.h"
+
+namespace views {
+
+namespace {
+
+std::vector<uint8_t> FromString(const std::string& str) {
+ return std::vector<uint8_t>(str.begin(), str.end());
+}
+
+std::string ToString(const std::vector<uint8_t>& v) {
+ return std::string(v.begin(), v.end());
+}
+
+base::string16 ToString16(const std::vector<uint8_t>& v) {
+ DCHECK_EQ(0u, v.size() % 2);
+ return base::string16(
+ reinterpret_cast<const base::char16*>(v.data()),
+ v.size() / 2);
+}
+
+std::vector<base::StringPiece> ParseURIList(const std::vector<uint8_t>& data) {
+ return base::SplitStringPiece(
+ base::StringPiece(
+ reinterpret_cast<const char*>(&data.front()), data.size()),
+ "\n",
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+}
+
+void AddString16ToVector(const base::string16& str,
+ std::vector<uint8_t>* bytes) {
+ const unsigned char* front =
+ reinterpret_cast<const uint8_t*>(str.data());
+ bytes->insert(bytes->end(), front, front + (str.size() * 2));
+}
+
+} // namespace
+
+OSExchangeDataProviderMus::OSExchangeDataProviderMus() {}
+
+OSExchangeDataProviderMus::OSExchangeDataProviderMus(Data data)
+ : mime_data_(std::move(data)) {}
+
+OSExchangeDataProviderMus::~OSExchangeDataProviderMus() {}
+
+OSExchangeDataProviderMus::Data OSExchangeDataProviderMus::GetData() const {
+ return mime_data_;
+}
+
+std::unique_ptr<ui::OSExchangeData::Provider>
+OSExchangeDataProviderMus::Clone() const {
+ std::unique_ptr<OSExchangeDataProviderMus> r =
+ base::MakeUnique<OSExchangeDataProviderMus>();
+ r->drag_image_ = drag_image_;
+ r->drag_image_offset_ = drag_image_offset_;
+ r->mime_data_ = mime_data_;
+ return base::WrapUnique<ui::OSExchangeData::Provider>(r.release());
+}
+
+void OSExchangeDataProviderMus::MarkOriginatedFromRenderer() {
+ // Currently unimplemented because ChromeOS doesn't need this.
+ //
+ // TODO(erg): Implement this when we start porting mus to other platforms.
+}
+
+bool OSExchangeDataProviderMus::DidOriginateFromRenderer() const {
+ return false;
+}
+
+void OSExchangeDataProviderMus::SetString(const base::string16& data) {
+ if (HasString())
+ return;
+
+ mime_data_[ui::mojom::kMimeTypeText] = FromString(base::UTF16ToUTF8(data));
+}
+
+void OSExchangeDataProviderMus::SetURL(const GURL& url,
+ const base::string16& title) {
+ base::string16 spec = base::UTF8ToUTF16(url.spec());
+ std::vector<unsigned char> data;
+ AddString16ToVector(spec, &data);
+ AddString16ToVector(base::ASCIIToUTF16("\n"), &data);
+ AddString16ToVector(title, &data);
+ mime_data_[ui::mojom::kMimeTypeMozillaURL] = std::move(data);
+
+ if (!base::ContainsKey(mime_data_, ui::mojom::kMimeTypeText))
+ mime_data_[ui::mojom::kMimeTypeText] = FromString(url.spec());
+}
+
+void OSExchangeDataProviderMus::SetFilename(const base::FilePath& path) {
+ std::vector<ui::FileInfo> data;
+ data.push_back(ui::FileInfo(path, base::FilePath()));
+ SetFilenames(data);
+}
+
+void OSExchangeDataProviderMus::SetFilenames(
+ const std::vector<ui::FileInfo>& file_names) {
+ std::vector<std::string> paths;
+ for (std::vector<ui::FileInfo>::const_iterator it = file_names.begin();
+ it != file_names.end();
+ ++it) {
+ std::string url_spec = net::FilePathToFileURL(it->path).spec();
+ if (!url_spec.empty())
+ paths.push_back(url_spec);
+ }
+
+ std::string joined_data = base::JoinString(paths, "\n");
+ mime_data_[ui::mojom::kMimeTypeURIList] = FromString(joined_data);
+}
+
+void OSExchangeDataProviderMus::SetPickledData(
+ const ui::Clipboard::FormatType& format,
+ const base::Pickle& pickle) {
+ const unsigned char* bytes =
+ reinterpret_cast<const unsigned char*>(pickle.data());
+
+ mime_data_[format.Serialize()] = mojo::Array<uint8_t>(
+ std::vector<uint8_t>(bytes, bytes + pickle.size()));
+}
+
+bool OSExchangeDataProviderMus::GetString(base::string16* data) const {
+ auto it = mime_data_.find(ui::mojom::kMimeTypeText);
+ if (it != mime_data_.end())
+ *data = base::UTF8ToUTF16(ToString(it->second));
+ return it != mime_data_.end();
+}
+
+bool OSExchangeDataProviderMus::GetURLAndTitle(
+ ui::OSExchangeData::FilenameToURLPolicy policy,
+ GURL* url,
+ base::string16* title) const {
+ auto it = mime_data_.find(ui::mojom::kMimeTypeMozillaURL);
+ if (it == mime_data_.end()) {
+ title->clear();
+ return GetPlainTextURL(url) ||
+ (policy == ui::OSExchangeData::CONVERT_FILENAMES && GetFileURL(url));
+ }
+
+ base::string16 data = ToString16(it->second);
+ base::string16::size_type newline = data.find('\n');
+ if (newline == std::string::npos)
+ return false;
+
+ GURL unparsed_url(data.substr(0, newline));
+ if (!unparsed_url.is_valid())
+ return false;
+
+ *url = unparsed_url;
+ *title = data.substr(newline + 1);
+ return true;
+}
+
+bool OSExchangeDataProviderMus::GetFilename(base::FilePath* path) const {
+ std::vector<ui::FileInfo> filenames;
+ if (GetFilenames(&filenames)) {
+ *path = filenames.front().path;
+ return true;
+ }
+
+ return false;
+}
+
+bool OSExchangeDataProviderMus::GetFilenames(
+ std::vector<ui::FileInfo>* file_names) const {
+ auto it = mime_data_.find(ui::mojom::kMimeTypeURIList);
+ if (it == mime_data_.end())
+ return false;
+
+ file_names->clear();
+ for (const base::StringPiece& piece : ParseURIList(it->second)) {
+ GURL url(piece);
+ base::FilePath file_path;
+ if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path))
+ file_names->push_back(ui::FileInfo(file_path, base::FilePath()));
+ }
+
+ return true;
+}
+
+bool OSExchangeDataProviderMus::GetPickledData(
+ const ui::Clipboard::FormatType& format,
+ base::Pickle* data) const {
+ auto it = mime_data_.find(format.Serialize());
+ if (it == mime_data_.end())
+ return false;
+
+ // Note that the pickle object on the right hand side of the assignment
+ // only refers to the bytes in |data|. The assignment copies the data.
+ *data = base::Pickle(reinterpret_cast<const char*>(it->second.data()),
+ static_cast<int>(it->second.size()));
+ return true;
+}
+
+bool OSExchangeDataProviderMus::HasString() const {
+ return base::ContainsKey(mime_data_, ui::mojom::kMimeTypeText);
+}
+
+bool OSExchangeDataProviderMus::HasURL(
+ ui::OSExchangeData::FilenameToURLPolicy policy) const {
+ if (base::ContainsKey(mime_data_, ui::mojom::kMimeTypeMozillaURL))
+ return true;
+
+ auto it = mime_data_.find(ui::mojom::kMimeTypeURIList);
+ if (it == mime_data_.end())
+ return false;
+
+ for (const base::StringPiece& piece : ParseURIList(it->second)) {
+ if (!GURL(piece).SchemeIsFile() ||
+ policy == ui::OSExchangeData::CONVERT_FILENAMES) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSExchangeDataProviderMus::HasFile() const {
+ auto it = mime_data_.find(ui::mojom::kMimeTypeURIList);
+ if (it == mime_data_.end())
+ return false;
+
+ for (const base::StringPiece& piece : ParseURIList(it->second)) {
+ GURL url(piece);
+ base::FilePath file_path;
+ if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path))
+ return true;
+ }
+
+ return false;
+}
+
+bool OSExchangeDataProviderMus::HasCustomFormat(
+ const ui::Clipboard::FormatType& format) const {
+ return base::ContainsKey(mime_data_, format.Serialize());
+}
+
+// These methods were added in an ad-hoc way to different operating
+// systems. We need to support them until they get cleaned up.
+#if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN)
+void OSExchangeDataProviderMus::SetFileContents(
+ const base::FilePath& filename,
+ const std::string& file_contents) {
+}
+#endif
+
+#if defined(OS_WIN)
+bool OSExchangeDataProviderMus::GetFileContents(
+ base::FilePath* filename,
+ std::string* file_contents) const {
+ return false;
+}
+
+bool OSExchangeDataProviderMus::HasFileContents() const {
+ return false;
+}
+
+void OSExchangeDataProviderMus::SetDownloadFileInfo(
+ const ui::OSExchangeData::DownloadFileInfo& download) {
+}
+#endif
+
+#if defined(USE_AURA)
+void OSExchangeDataProviderMus::SetHtml(const base::string16& html,
+ const GURL& base_url) {
+ std::vector<unsigned char> bytes;
+ // Manually jam a UTF16 BOM into bytes because otherwise, other programs will
+ // assume UTF-8.
+ bytes.push_back(0xFF);
+ bytes.push_back(0xFE);
+ AddString16ToVector(html, &bytes);
+ mime_data_[ui::mojom::kMimeTypeHTML] = bytes;
+}
+
+bool OSExchangeDataProviderMus::GetHtml(base::string16* html,
+ GURL* base_url) const {
+ auto it = mime_data_.find(ui::mojom::kMimeTypeHTML);
+ if (it == mime_data_.end())
+ return false;
+
+ const unsigned char* data = it->second.data();
+ size_t size = it->second.size();
+ base::string16 markup;
+
+ // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is
+ // UTF-16, otherwise assume UTF-8.
+ if (size >= 2 &&
+ reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) {
+ markup.assign(reinterpret_cast<const base::char16*>(data) + 1,
+ (size / 2) - 1);
+ } else {
+ base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup);
+ }
+
+ // If there is a terminating NULL, drop it.
+ if (!markup.empty() && markup.at(markup.length() - 1) == '\0')
+ markup.resize(markup.length() - 1);
+
+ *html = markup;
+ *base_url = GURL();
+ return true;
+}
+
+bool OSExchangeDataProviderMus::HasHtml() const {
+ return base::ContainsKey(mime_data_, ui::mojom::kMimeTypeHTML);
+}
+#endif
+
+#if defined(USE_AURA) || defined(OS_MACOSX)
+void OSExchangeDataProviderMus::SetDragImage(
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& cursor_offset) {
+ drag_image_ = image;
+ drag_image_offset_ = cursor_offset;
+}
+
+const gfx::ImageSkia& OSExchangeDataProviderMus::GetDragImage() const {
+ return drag_image_;
+}
+
+const gfx::Vector2d& OSExchangeDataProviderMus::GetDragImageOffset() const {
+ return drag_image_offset_;
+}
+#endif
+
+bool OSExchangeDataProviderMus::GetFileURL(GURL* url) const {
+ base::FilePath file_path;
+ if (!GetFilename(&file_path))
+ return false;
+
+ GURL test_url = net::FilePathToFileURL(file_path);
+ if (!test_url.is_valid())
+ return false;
+
+ if (url)
+ *url = test_url;
+ return true;
+}
+
+bool OSExchangeDataProviderMus::GetPlainTextURL(GURL* url) const {
+ base::string16 str;
+ if (!GetString(&str))
+ return false;
+
+ GURL test_url(str);
+ if (!test_url.is_valid())
+ return false;
+
+ if (url)
+ *url = test_url;
+ return true;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/os_exchange_data_provider_mus.h b/chromium/ui/views/mus/os_exchange_data_provider_mus.h
new file mode 100644
index 00000000000..120de932f67
--- /dev/null
+++ b/chromium/ui/views/mus/os_exchange_data_provider_mus.h
@@ -0,0 +1,118 @@
+// Copyright 2016 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_MUS_OS_EXCHANGE_DATA_PROVIDER_MUS_H_
+#define UI_VIEWS_MUS_OS_EXCHANGE_DATA_PROVIDER_MUS_H_
+
+#include "ui/base/dragdrop/os_exchange_data.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "mojo/public/cpp/bindings/map.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/mus/mus_export.h"
+
+namespace views {
+
+// Translates chrome's requests for various data types to a platform specific
+// type. In the case of mus, this is a mapping of MIME types to byte arrays.
+//
+// TODO(erg): In the long run, there's a lot of optimizations that we can do
+// once everything targets mus. The entire model of OSExchangeDataProvider
+// shoves all data across the wire at once whether it is needed or not.
+class VIEWS_MUS_EXPORT OSExchangeDataProviderMus
+ : public ui::OSExchangeData::Provider {
+ public:
+ using Data = std::map<std::string, std::vector<uint8_t>>;
+
+ OSExchangeDataProviderMus();
+ explicit OSExchangeDataProviderMus(Data data);
+ ~OSExchangeDataProviderMus() override;
+
+ // Returns the raw MIME type to data mapping.
+ Data GetData() const;
+
+ // Overridden from OSExchangeData::Provider:
+ std::unique_ptr<Provider> Clone() const override;
+
+ void MarkOriginatedFromRenderer() override;
+ bool DidOriginateFromRenderer() const override;
+
+ void SetString(const base::string16& data) override;
+ void SetURL(const GURL& url, const base::string16& title) override;
+ void SetFilename(const base::FilePath& path) override;
+ void SetFilenames(const std::vector<ui::FileInfo>& file_names) override;
+ void SetPickledData(const ui::Clipboard::FormatType& format,
+ const base::Pickle& data) override;
+
+ bool GetString(base::string16* data) const override;
+ bool GetURLAndTitle(ui::OSExchangeData::FilenameToURLPolicy policy,
+ GURL* url,
+ base::string16* title) const override;
+ bool GetFilename(base::FilePath* path) const override;
+ bool GetFilenames(std::vector<ui::FileInfo>* file_names) const override;
+ bool GetPickledData(const ui::Clipboard::FormatType& format,
+ base::Pickle* data) const override;
+
+ bool HasString() const override;
+ bool HasURL(ui::OSExchangeData::FilenameToURLPolicy policy) const override;
+ bool HasFile() const override;
+ bool HasCustomFormat(const ui::Clipboard::FormatType& format) const override;
+
+ // Provider doesn't have a consistent interface between operating systems;
+ // this wasn't seen as a problem when there was a single Provider subclass
+ // per operating system. Now we have to have at least two providers per OS,
+ // leading to the following warts, which will remain until we clean all the
+ // callsites up.
+#if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN)
+ void SetFileContents(const base::FilePath& filename,
+ const std::string& file_contents) override;
+#endif
+#if defined(OS_WIN)
+ bool GetFileContents(base::FilePath* filename,
+ std::string* file_contents) const override;
+ bool HasFileContents() const override;
+ void SetDownloadFileInfo(
+ const ui::OSExchangeData::DownloadFileInfo& download) override;
+#endif
+
+#if defined(USE_AURA)
+ void SetHtml(const base::string16& html, const GURL& base_url) override;
+ bool GetHtml(base::string16* html, GURL* base_url) const override;
+ bool HasHtml() const override;
+#endif
+
+#if defined(USE_AURA) || defined(OS_MACOSX)
+ void SetDragImage(const gfx::ImageSkia& image,
+ const gfx::Vector2d& cursor_offset) override;
+ const gfx::ImageSkia& GetDragImage() const override;
+ const gfx::Vector2d& GetDragImageOffset() const override;
+#endif
+
+ private:
+ // Returns true if |formats_| contains a file format and the file name can be
+ // parsed as a URL.
+ bool GetFileURL(GURL* url) const;
+
+ // Returns true if |formats_| contains a string format and the string can be
+ // parsed as a URL.
+ bool GetPlainTextURL(GURL* url) const;
+
+ // Drag image and offset data.
+ gfx::ImageSkia drag_image_;
+ gfx::Vector2d drag_image_offset_;
+
+ Data mime_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(OSExchangeDataProviderMus);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_OS_EXCHANGE_DATA_PROVIDER_MUS_H_
diff --git a/chromium/ui/views/mus/os_exchange_data_provider_mus_unittest.cc b/chromium/ui/views/mus/os_exchange_data_provider_mus_unittest.cc
new file mode 100644
index 00000000000..c2a7644dd96
--- /dev/null
+++ b/chromium/ui/views/mus/os_exchange_data_provider_mus_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright 2016 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 <memory>
+
+#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/pickle.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "net/base/filename_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/views/mus/os_exchange_data_provider_mus.h"
+#include "url/gurl.h"
+
+using ui::Clipboard;
+using ui::OSExchangeData;
+
+namespace views {
+
+// This file is a copy/paste of the unit tests in os_exchange_data_unittest.cc,
+// with additional SetUp() to force the mus override. I thought about changeing
+// the OSExchangeData test suite to a parameterized test suite, but I've
+// previously had problems with that feature of gtest.
+
+class OSExchangeDataProviderMusTest
+ : public PlatformTest,
+ public ui::OSExchangeDataProviderFactory::Factory {
+ public:
+ OSExchangeDataProviderMusTest() {}
+
+ // Overridden from PlatformTest:
+ void SetUp() override {
+ PlatformTest::SetUp();
+ ui::OSExchangeDataProviderFactory::SetFactory(this);
+ }
+
+ void TearDown() override {
+ ui::OSExchangeDataProviderFactory::SetFactory(nullptr);
+ PlatformTest::TearDown();
+ }
+
+ // Overridden from ui::OSExchangeDataProviderFactory::Factory:
+ std::unique_ptr<OSExchangeData::Provider> BuildProvider() override {
+ return base::MakeUnique<OSExchangeDataProviderMus>();
+ }
+
+ private:
+ base::MessageLoopForUI message_loop_;
+};
+
+TEST_F(OSExchangeDataProviderMusTest, StringDataGetAndSet) {
+ OSExchangeData data;
+ base::string16 input = base::ASCIIToUTF16("I can has cheezburger?");
+ EXPECT_FALSE(data.HasString());
+ data.SetString(input);
+ EXPECT_TRUE(data.HasString());
+
+ OSExchangeData data2(
+ std::unique_ptr<OSExchangeData::Provider>(data.provider().Clone()));
+ base::string16 output;
+ EXPECT_TRUE(data2.HasString());
+ EXPECT_TRUE(data2.GetString(&output));
+ EXPECT_EQ(input, output);
+ std::string url_spec = "http://www.goats.com/";
+ GURL url(url_spec);
+ base::string16 title;
+ EXPECT_FALSE(data2.GetURLAndTitle(
+ OSExchangeData::DO_NOT_CONVERT_FILENAMES, &url, &title));
+ // No URLs in |data|, so url should be untouched.
+ EXPECT_EQ(url_spec, url.spec());
+}
+
+TEST_F(OSExchangeDataProviderMusTest, TestURLExchangeFormats) {
+ OSExchangeData data;
+ std::string url_spec = "http://www.google.com/";
+ GURL url(url_spec);
+ base::string16 url_title = base::ASCIIToUTF16("www.google.com");
+ EXPECT_FALSE(data.HasURL(OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+ data.SetURL(url, url_title);
+ EXPECT_TRUE(data.HasURL(OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+
+ OSExchangeData data2(
+ std::unique_ptr<OSExchangeData::Provider>(data.provider().Clone()));
+
+ // URL spec and title should match
+ GURL output_url;
+ base::string16 output_title;
+ EXPECT_TRUE(data2.HasURL(OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+ EXPECT_TRUE(data2.GetURLAndTitle(
+ OSExchangeData::DO_NOT_CONVERT_FILENAMES, &output_url, &output_title));
+ EXPECT_EQ(url_spec, output_url.spec());
+ EXPECT_EQ(url_title, output_title);
+ base::string16 output_string;
+
+ // URL should be the raw text response
+ EXPECT_TRUE(data2.GetString(&output_string));
+ EXPECT_EQ(url_spec, base::UTF16ToUTF8(output_string));
+}
+
+// Test that setting the URL does not overwrite a previously set custom string.
+TEST_F(OSExchangeDataProviderMusTest, URLAndString) {
+ OSExchangeData data;
+ base::string16 string = base::ASCIIToUTF16("I can has cheezburger?");
+ data.SetString(string);
+ std::string url_spec = "http://www.google.com/";
+ GURL url(url_spec);
+ base::string16 url_title = base::ASCIIToUTF16("www.google.com");
+ data.SetURL(url, url_title);
+
+ base::string16 output_string;
+ EXPECT_TRUE(data.GetString(&output_string));
+ EXPECT_EQ(string, output_string);
+
+ GURL output_url;
+ base::string16 output_title;
+ EXPECT_TRUE(data.GetURLAndTitle(
+ OSExchangeData::DO_NOT_CONVERT_FILENAMES, &output_url, &output_title));
+ EXPECT_EQ(url_spec, output_url.spec());
+ EXPECT_EQ(url_title, output_title);
+}
+
+TEST_F(OSExchangeDataProviderMusTest, TestFileToURLConversion) {
+ OSExchangeData data;
+ EXPECT_FALSE(data.HasURL(OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+ EXPECT_FALSE(data.HasURL(OSExchangeData::CONVERT_FILENAMES));
+ EXPECT_FALSE(data.HasFile());
+
+ base::FilePath current_directory;
+ ASSERT_TRUE(base::GetCurrentDirectory(&current_directory));
+
+ data.SetFilename(current_directory);
+
+ {
+ EXPECT_FALSE(data.HasURL(OSExchangeData::DO_NOT_CONVERT_FILENAMES));
+ GURL actual_url;
+ base::string16 actual_title;
+ EXPECT_FALSE(data.GetURLAndTitle(
+ OSExchangeData::DO_NOT_CONVERT_FILENAMES, &actual_url, &actual_title));
+ EXPECT_EQ(GURL(), actual_url);
+ EXPECT_EQ(base::string16(), actual_title);
+ }
+
+ {
+ EXPECT_TRUE(data.HasURL(OSExchangeData::CONVERT_FILENAMES));
+ GURL actual_url;
+ base::string16 actual_title;
+ EXPECT_TRUE(data.GetURLAndTitle(OSExchangeData::CONVERT_FILENAMES,
+ &actual_url, &actual_title));
+ // Some Mac OS versions return the URL in file://localhost form instead
+ // of file:///, so we compare the url's path not its absolute string.
+ EXPECT_EQ(net::FilePathToFileURL(current_directory).path(),
+ actual_url.path());
+ EXPECT_EQ(base::string16(), actual_title);
+ }
+ EXPECT_TRUE(data.HasFile());
+ base::FilePath actual_path;
+ EXPECT_TRUE(data.GetFilename(&actual_path));
+ EXPECT_EQ(current_directory, actual_path);
+}
+
+TEST_F(OSExchangeDataProviderMusTest, TestPickledData) {
+ const Clipboard::FormatType kTestFormat =
+ Clipboard::GetFormatType("application/vnd.chromium.test");
+
+ base::Pickle saved_pickle;
+ saved_pickle.WriteInt(1);
+ saved_pickle.WriteInt(2);
+ OSExchangeData data;
+ data.SetPickledData(kTestFormat, saved_pickle);
+
+ OSExchangeData copy(
+ std::unique_ptr<OSExchangeData::Provider>(data.provider().Clone()));
+ EXPECT_TRUE(copy.HasCustomFormat(kTestFormat));
+
+ base::Pickle restored_pickle;
+ EXPECT_TRUE(copy.GetPickledData(kTestFormat, &restored_pickle));
+ base::PickleIterator iterator(restored_pickle);
+ int value;
+ EXPECT_TRUE(iterator.ReadInt(&value));
+ EXPECT_EQ(1, value);
+ EXPECT_TRUE(iterator.ReadInt(&value));
+ EXPECT_EQ(2, value);
+}
+
+#if defined(USE_AURA)
+TEST_F(OSExchangeDataProviderMusTest, TestHTML) {
+ OSExchangeData data;
+ GURL url("http://www.google.com/");
+ base::string16 html = base::ASCIIToUTF16(
+ "<HTML>\n<BODY>\n"
+ "<b>bold.</b> <i><b>This is bold italic.</b></i>\n"
+ "</BODY>\n</HTML>");
+ data.SetHtml(html, url);
+
+ OSExchangeData copy(
+ std::unique_ptr<OSExchangeData::Provider>(data.provider().Clone()));
+ base::string16 read_html;
+ EXPECT_TRUE(copy.GetHtml(&read_html, &url));
+ EXPECT_EQ(html, read_html);
+}
+#endif
+
+} // namespace views
+
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router.cc b/chromium/ui/views/mus/pointer_watcher_event_router.cc
new file mode 100644
index 00000000000..998c4cf0d61
--- /dev/null
+++ b/chromium/ui/views/mus/pointer_watcher_event_router.cc
@@ -0,0 +1,152 @@
+// Copyright 2016 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/mus/pointer_watcher_event_router.h"
+
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/cpp/window_tree_client.h"
+#include "ui/display/screen.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/event.h"
+#include "ui/views/mus/native_widget_mus.h"
+#include "ui/views/pointer_watcher.h"
+
+namespace views {
+namespace {
+
+bool HasPointerWatcher(
+ base::ObserverList<views::PointerWatcher, true>* observer_list) {
+ if (!observer_list->might_have_observers())
+ return false;
+
+ // might_have_observers() returned true, see if there really are any
+ // observers. The only way to truly know is to use an Iterator and see if it
+ // has at least one observer.
+ base::ObserverList<PointerWatcher>::Iterator iterator(observer_list);
+ return !!iterator.GetNext();
+}
+
+} // namespace
+
+PointerWatcherEventRouter::PointerWatcherEventRouter(
+ ui::WindowTreeClient* client)
+ : window_tree_client_(client) {
+ client->AddObserver(this);
+}
+
+PointerWatcherEventRouter::~PointerWatcherEventRouter() {
+ if (window_tree_client_)
+ window_tree_client_->RemoveObserver(this);
+}
+
+void PointerWatcherEventRouter::AddPointerWatcher(PointerWatcher* watcher,
+ bool wants_moves) {
+ // Pointer watchers cannot be added multiple times.
+ DCHECK(!move_watchers_.HasObserver(watcher));
+ DCHECK(!non_move_watchers_.HasObserver(watcher));
+ if (wants_moves) {
+ move_watchers_.AddObserver(watcher);
+ if (event_types_ != EventTypes::MOVE_EVENTS) {
+ event_types_ = EventTypes::MOVE_EVENTS;
+ const bool wants_moves = true;
+ window_tree_client_->StartPointerWatcher(wants_moves);
+ }
+ } else {
+ non_move_watchers_.AddObserver(watcher);
+ if (event_types_ == EventTypes::NONE) {
+ event_types_ = EventTypes::NON_MOVE_EVENTS;
+ const bool wants_moves = false;
+ window_tree_client_->StartPointerWatcher(wants_moves);
+ }
+ }
+}
+
+void PointerWatcherEventRouter::RemovePointerWatcher(PointerWatcher* watcher) {
+ if (non_move_watchers_.HasObserver(watcher)) {
+ non_move_watchers_.RemoveObserver(watcher);
+ } else {
+ DCHECK(move_watchers_.HasObserver(watcher));
+ move_watchers_.RemoveObserver(watcher);
+ }
+ const EventTypes types = DetermineEventTypes();
+ if (types == event_types_)
+ return;
+
+ event_types_ = types;
+ switch (types) {
+ case EventTypes::NONE:
+ window_tree_client_->StopPointerWatcher();
+ break;
+ case EventTypes::NON_MOVE_EVENTS:
+ window_tree_client_->StartPointerWatcher(false);
+ break;
+ case EventTypes::MOVE_EVENTS:
+ // It isn't possible to remove an observer and transition to wanting move
+ // events. This could only happen if there is a bug in the add logic.
+ NOTREACHED();
+ break;
+ }
+}
+
+void PointerWatcherEventRouter::OnPointerEventObserved(
+ const ui::PointerEvent& event,
+ ui::Window* target) {
+ Widget* target_widget = nullptr;
+ if (target) {
+ ui::Window* window = target;
+ while (window && !target_widget) {
+ target_widget = NativeWidgetMus::GetWidgetForWindow(target);
+ window = window->parent();
+ }
+ }
+
+ // The mojo input events type converter uses the event root_location field
+ // to store screen coordinates. Screen coordinates really should be returned
+ // separately. See http://crbug.com/608547
+ gfx::Point location_in_screen = event.AsLocatedEvent()->root_location();
+ FOR_EACH_OBSERVER(
+ PointerWatcher, move_watchers_,
+ OnPointerEventObserved(event, location_in_screen, target_widget));
+ if (event.type() != ui::ET_POINTER_MOVED) {
+ FOR_EACH_OBSERVER(
+ PointerWatcher, non_move_watchers_,
+ OnPointerEventObserved(event, location_in_screen, target_widget));
+ }
+}
+
+PointerWatcherEventRouter::EventTypes
+PointerWatcherEventRouter::DetermineEventTypes() {
+ if (HasPointerWatcher(&move_watchers_))
+ return EventTypes::MOVE_EVENTS;
+
+ if (HasPointerWatcher(&non_move_watchers_))
+ return EventTypes::NON_MOVE_EVENTS;
+
+ return EventTypes::NONE;
+}
+
+void PointerWatcherEventRouter::OnWindowTreeCaptureChanged(
+ ui::Window* gained_capture,
+ ui::Window* lost_capture) {
+ const ui::MouseEvent mouse_event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
+ gfx::Point(), ui::EventTimeForNow(), 0, 0);
+ const ui::PointerEvent event(mouse_event);
+ gfx::Point location_in_screen =
+ display::Screen::GetScreen()->GetCursorScreenPoint();
+ FOR_EACH_OBSERVER(PointerWatcher, move_watchers_,
+ OnPointerEventObserved(event, location_in_screen, nullptr));
+ FOR_EACH_OBSERVER(PointerWatcher, non_move_watchers_,
+ OnPointerEventObserved(event, location_in_screen, nullptr));
+}
+
+void PointerWatcherEventRouter::OnDidDestroyClient(
+ ui::WindowTreeClient* client) {
+ // We expect that all observers have been removed by this time.
+ DCHECK_EQ(event_types_, EventTypes::NONE);
+ DCHECK_EQ(client, window_tree_client_);
+ window_tree_client_->RemoveObserver(this);
+ window_tree_client_ = nullptr;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router.h b/chromium/ui/views/mus/pointer_watcher_event_router.h
new file mode 100644
index 00000000000..e75e81d441b
--- /dev/null
+++ b/chromium/ui/views/mus/pointer_watcher_event_router.h
@@ -0,0 +1,79 @@
+// Copyright 2016 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_MUS_POINTER_WATCHER_EVENT_ROUTER_H_
+#define UI_VIEWS_MUS_POINTER_WATCHER_EVENT_ROUTER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "services/ui/public/cpp/window_tree_client_observer.h"
+#include "ui/views/mus/mus_export.h"
+
+namespace ui {
+class PointerEvent;
+class WindowTreeClient;
+}
+
+namespace views {
+
+class PointerWatcher;
+class PointerWatcherEventRouterTest;
+
+// PointerWatcherEventRouter is responsible for maintaining the list of
+// PointerWatchers and notifying appropriately. It is expected the owner of
+// PointerWatcherEventRouter is a WindowTreeClientDelegate and calls
+// OnPointerEventObserved().
+class VIEWS_MUS_EXPORT PointerWatcherEventRouter
+ : public NON_EXPORTED_BASE(ui::WindowTreeClientObserver) {
+ public:
+ // Public solely for tests.
+ enum EventTypes {
+ // No PointerWatchers have been added.
+ NONE,
+
+ // Used when the only PointerWatchers added do not want moves.
+ NON_MOVE_EVENTS,
+
+ // Used when at least one PointerWatcher has been added that wants moves.
+ MOVE_EVENTS,
+ };
+
+ explicit PointerWatcherEventRouter(ui::WindowTreeClient* client);
+ ~PointerWatcherEventRouter() override;
+
+ // Called by WindowTreeClientDelegate to notify PointerWatchers appropriately.
+ void OnPointerEventObserved(const ui::PointerEvent& event,
+ ui::Window* target);
+
+ void AddPointerWatcher(PointerWatcher* watcher, bool wants_moves);
+ void RemovePointerWatcher(PointerWatcher* watcher);
+
+ private:
+ friend class PointerWatcherEventRouterTest;
+
+ // Determines EventTypes based on the number and type of PointerWatchers.
+ EventTypes DetermineEventTypes();
+
+ // ui::WindowTreeClientObserver:
+ void OnWindowTreeCaptureChanged(ui::Window* gained_capture,
+ ui::Window* lost_capture) override;
+ void OnDidDestroyClient(ui::WindowTreeClient* client) override;
+
+ ui::WindowTreeClient* window_tree_client_;
+ // The true parameter to ObserverList indicates the list must be empty on
+ // destruction. Two sets of observers are maintained, one for observers not
+ // needing moves |non_move_watchers_| and |move_watchers_| for those
+ // observers wanting moves too.
+ base::ObserverList<views::PointerWatcher, true> non_move_watchers_;
+ base::ObserverList<views::PointerWatcher, true> move_watchers_;
+
+ EventTypes event_types_ = EventTypes::NONE;
+
+ DISALLOW_COPY_AND_ASSIGN(PointerWatcherEventRouter);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_POINTER_WATCHER_EVENT_ROUTER_H_
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
new file mode 100644
index 00000000000..511cc3338e7
--- /dev/null
+++ b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
@@ -0,0 +1,244 @@
+// Copyright 2016 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/mus/pointer_watcher_event_router.h"
+
+#include <memory>
+
+#include "base/message_loop/message_loop.h"
+#include "services/ui/public/cpp/tests/window_tree_client_private.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/views/mus/window_manager_connection.h"
+#include "ui/views/pointer_watcher.h"
+#include "ui/views/test/scoped_views_test_helper.h"
+
+namespace views {
+namespace {
+
+class TestPointerWatcher : public PointerWatcher {
+ public:
+ TestPointerWatcher() {}
+ ~TestPointerWatcher() override {}
+
+ ui::PointerEvent* last_event_observed() { return last_event_observed_.get(); }
+
+ void Reset() { last_event_observed_.reset(); }
+
+ // PointerWatcher:
+ void OnPointerEventObserved(const ui::PointerEvent& event,
+ const gfx::Point& location_in_screen,
+ Widget* target) override {
+ last_event_observed_ = base::MakeUnique<ui::PointerEvent>(event);
+ }
+
+ private:
+ std::unique_ptr<ui::PointerEvent> last_event_observed_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPointerWatcher);
+};
+
+} // namespace
+
+class PointerWatcherEventRouterTest : public testing::Test {
+ public:
+ PointerWatcherEventRouterTest() {}
+ ~PointerWatcherEventRouterTest() override {}
+
+ void OnPointerEventObserved(const ui::PointerEvent& event) {
+ WindowManagerConnection::Get()
+ ->pointer_watcher_event_router()
+ ->OnPointerEventObserved(event, nullptr);
+ }
+
+ PointerWatcherEventRouter::EventTypes event_types() const {
+ return WindowManagerConnection::Get()
+ ->pointer_watcher_event_router()
+ ->event_types_;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PointerWatcherEventRouterTest);
+};
+
+TEST_F(PointerWatcherEventRouterTest, EventTypes) {
+ base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+ ScopedViewsTestHelper helper;
+ TestPointerWatcher pointer_watcher1, pointer_watcher2;
+ PointerWatcherEventRouter* pointer_watcher_event_router =
+ WindowManagerConnection::Get()->pointer_watcher_event_router();
+ ui::WindowTreeClientPrivate test_api(
+ WindowManagerConnection::Get()->client());
+ EXPECT_FALSE(test_api.HasPointerWatcher());
+
+ // Start with no moves.
+ pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher1, false);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NON_MOVE_EVENTS,
+ event_types());
+ EXPECT_TRUE(test_api.HasPointerWatcher());
+
+ // Add moves.
+ pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher2, true);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
+ EXPECT_TRUE(test_api.HasPointerWatcher());
+
+ // Remove no-moves.
+ pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher1);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
+ EXPECT_TRUE(test_api.HasPointerWatcher());
+
+ // Remove moves.
+ pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher2);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NONE, event_types());
+ EXPECT_FALSE(test_api.HasPointerWatcher());
+
+ // Add moves.
+ pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher2, true);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
+ EXPECT_TRUE(test_api.HasPointerWatcher());
+
+ // Add no moves.
+ pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher1, false);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
+ EXPECT_TRUE(test_api.HasPointerWatcher());
+
+ // Remove moves.
+ pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher2);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NON_MOVE_EVENTS,
+ event_types());
+ EXPECT_TRUE(test_api.HasPointerWatcher());
+
+ // Remove no-moves.
+ pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher1);
+ EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NONE, event_types());
+ EXPECT_FALSE(test_api.HasPointerWatcher());
+}
+
+TEST_F(PointerWatcherEventRouterTest, PointerWatcherNoMove) {
+ base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+ ScopedViewsTestHelper helper;
+ ASSERT_TRUE(WindowManagerConnection::Get());
+ PointerWatcherEventRouter* pointer_watcher_event_router =
+ WindowManagerConnection::Get()->pointer_watcher_event_router();
+ ASSERT_TRUE(pointer_watcher_event_router);
+
+ ui::PointerEvent pointer_event_down(
+ ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, 0,
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH),
+ base::TimeTicks());
+ ui::PointerEvent pointer_event_up(
+ ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, 0,
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE),
+ base::TimeTicks());
+ ui::PointerEvent pointer_event_wheel(
+ ui::ET_POINTER_WHEEL_CHANGED, gfx::Point(), gfx::Point(), ui::EF_NONE, 1,
+ 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE),
+ base::TimeTicks());
+ ui::PointerEvent pointer_event_capture(
+ ui::ET_POINTER_CAPTURE_CHANGED, gfx::Point(), gfx::Point(), ui::EF_NONE,
+ 1, 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE),
+ base::TimeTicks());
+
+ // PointerWatchers receive pointer down events.
+ TestPointerWatcher watcher1;
+ pointer_watcher_event_router->AddPointerWatcher(&watcher1, false);
+ OnPointerEventObserved(pointer_event_down);
+ EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type());
+ watcher1.Reset();
+
+ // PointerWatchers receive pointer up events.
+ OnPointerEventObserved(pointer_event_up);
+ EXPECT_EQ(ui::ET_POINTER_UP, watcher1.last_event_observed()->type());
+ watcher1.Reset();
+
+ // PointerWatchers receive pointer wheel changed events.
+ OnPointerEventObserved(pointer_event_wheel);
+ EXPECT_EQ(ui::ET_POINTER_WHEEL_CHANGED,
+ watcher1.last_event_observed()->type());
+ watcher1.Reset();
+
+ // PointerWatchers receive pointer capture changed events.
+ OnPointerEventObserved(pointer_event_capture);
+ EXPECT_EQ(ui::ET_POINTER_CAPTURE_CHANGED,
+ watcher1.last_event_observed()->type());
+ watcher1.Reset();
+
+ // Two PointerWatchers can both receive a single observed event.
+ TestPointerWatcher watcher2;
+ pointer_watcher_event_router->AddPointerWatcher(&watcher2, false);
+ OnPointerEventObserved(pointer_event_down);
+ EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type());
+ EXPECT_EQ(ui::ET_POINTER_DOWN, watcher2.last_event_observed()->type());
+ watcher1.Reset();
+ watcher2.Reset();
+
+ // Removing the first PointerWatcher stops sending events to it.
+ pointer_watcher_event_router->RemovePointerWatcher(&watcher1);
+ OnPointerEventObserved(pointer_event_down);
+ EXPECT_FALSE(watcher1.last_event_observed());
+ EXPECT_EQ(ui::ET_POINTER_DOWN, watcher2.last_event_observed()->type());
+ watcher1.Reset();
+ watcher2.Reset();
+
+ // Removing the last PointerWatcher stops sending events to it.
+ pointer_watcher_event_router->RemovePointerWatcher(&watcher2);
+ OnPointerEventObserved(pointer_event_down);
+ EXPECT_FALSE(watcher1.last_event_observed());
+ EXPECT_FALSE(watcher2.last_event_observed());
+}
+
+TEST_F(PointerWatcherEventRouterTest, PointerWatcherMove) {
+ base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+ ScopedViewsTestHelper helper;
+ ASSERT_TRUE(WindowManagerConnection::Get());
+ PointerWatcherEventRouter* pointer_watcher_event_router =
+ WindowManagerConnection::Get()->pointer_watcher_event_router();
+ ASSERT_TRUE(pointer_watcher_event_router);
+
+ ui::PointerEvent pointer_event_down(
+ ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, 0,
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH),
+ base::TimeTicks());
+ ui::PointerEvent pointer_event_move(
+ ui::ET_POINTER_MOVED, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, 0,
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH),
+ base::TimeTicks());
+
+ // PointerWatchers receive pointer down events.
+ TestPointerWatcher watcher1;
+ pointer_watcher_event_router->AddPointerWatcher(&watcher1, true);
+ OnPointerEventObserved(pointer_event_down);
+ EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type());
+ watcher1.Reset();
+
+ // PointerWatchers receive pointer move events.
+ OnPointerEventObserved(pointer_event_move);
+ EXPECT_EQ(ui::ET_POINTER_MOVED, watcher1.last_event_observed()->type());
+ watcher1.Reset();
+
+ // Two PointerWatchers can both receive a single observed event.
+ TestPointerWatcher watcher2;
+ pointer_watcher_event_router->AddPointerWatcher(&watcher2, true);
+ OnPointerEventObserved(pointer_event_move);
+ EXPECT_EQ(ui::ET_POINTER_MOVED, watcher1.last_event_observed()->type());
+ EXPECT_EQ(ui::ET_POINTER_MOVED, watcher2.last_event_observed()->type());
+ watcher1.Reset();
+ watcher2.Reset();
+
+ // Removing the first PointerWatcher stops sending events to it.
+ pointer_watcher_event_router->RemovePointerWatcher(&watcher1);
+ OnPointerEventObserved(pointer_event_move);
+ EXPECT_FALSE(watcher1.last_event_observed());
+ EXPECT_EQ(ui::ET_POINTER_MOVED, watcher2.last_event_observed()->type());
+ watcher1.Reset();
+ watcher2.Reset();
+
+ // Removing the last PointerWatcher stops sending events to it.
+ pointer_watcher_event_router->RemovePointerWatcher(&watcher2);
+ OnPointerEventObserved(pointer_event_move);
+ EXPECT_FALSE(watcher1.last_event_observed());
+ EXPECT_FALSE(watcher2.last_event_observed());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/screen_mus.cc b/chromium/ui/views/mus/screen_mus.cc
index 533adcb20d2..e25a5e15f5e 100644
--- a/chromium/ui/views/mus/screen_mus.cc
+++ b/chromium/ui/views/mus/screen_mus.cc
@@ -2,29 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This has to be before any other includes, else default is picked up.
+// See base/logging for details on this.
+#define NOTIMPLEMENTED_POLICY 5
+
#include "ui/views/mus/screen_mus.h"
#include "services/shell/public/cpp/connection.h"
#include "services/shell/public/cpp/connector.h"
#include "ui/aura/window.h"
-#include "ui/display/display_finder.h"
-#include "ui/display/display_observer.h"
-#include "ui/display/mojo/display_type_converters.h"
#include "ui/views/mus/screen_mus_delegate.h"
#include "ui/views/mus/window_manager_frame_values.h"
-#ifdef NOTIMPLEMENTED
-#undef NOTIMPLEMENTED
-#define NOTIMPLEMENTED() DVLOG(1) << "notimplemented"
-#endif
-
namespace mojo {
template <>
struct TypeConverter<views::WindowManagerFrameValues,
- mus::mojom::FrameDecorationValuesPtr> {
+ ui::mojom::FrameDecorationValuesPtr> {
static views::WindowManagerFrameValues Convert(
- const mus::mojom::FrameDecorationValuesPtr& input) {
+ const ui::mojom::FrameDecorationValuesPtr& input) {
views::WindowManagerFrameValues result;
result.normal_insets = input->normal_client_area_insets;
result.maximized_insets = input->maximized_client_area_insets;
@@ -42,15 +38,10 @@ ScreenMus::ScreenMus(ScreenMusDelegate* delegate)
display_manager_observer_binding_(this) {
}
-ScreenMus::~ScreenMus() {
- DCHECK_EQ(this, display::Screen::GetScreen());
- display::Screen::SetScreenInstance(nullptr);
-}
+ScreenMus::~ScreenMus() {}
void ScreenMus::Init(shell::Connector* connector) {
- display::Screen::SetScreenInstance(this);
-
- connector->ConnectToInterface("mojo:mus", &display_manager_);
+ connector->ConnectToInterface("service:ui", &display_manager_);
display_manager_->AddObserver(
display_manager_observer_binding_.CreateInterfacePtrAndBind());
@@ -64,28 +55,14 @@ void ScreenMus::Init(shell::Connector* connector) {
// The WaitForIncomingMethodCall() should have supplied the set of Displays,
// unless mus is going down, in which case encountered_error() is true, or the
// call to WaitForIncomingMethodCall() failed.
- if (display_list_.displays().empty()) {
+ if (display_list()->displays().empty()) {
DCHECK(display_manager_.encountered_error() || !success);
// In this case we install a default display and assume the process is
// going to exit shortly so that the real value doesn't matter.
- display_list_.AddDisplay(
+ display_list()->AddDisplay(
display::Display(0xFFFFFFFF, gfx::Rect(0, 0, 801, 802)),
- DisplayList::Type::PRIMARY);
- }
-}
-
-void ScreenMus::ProcessDisplayChanged(const display::Display& changed_display,
- bool is_primary) {
- if (display_list_.FindDisplayById(changed_display.id()) ==
- display_list_.displays().end()) {
- display_list_.AddDisplay(changed_display,
- is_primary ? DisplayList::Type::PRIMARY
- : DisplayList::Type::NOT_PRIMARY);
- return;
+ display::DisplayList::Type::PRIMARY);
}
- display_list_.UpdateDisplay(
- changed_display,
- is_primary ? DisplayList::Type::PRIMARY : DisplayList::Type::NOT_PRIMARY);
}
gfx::Point ScreenMus::GetCursorScreenPoint() {
@@ -100,88 +77,39 @@ gfx::Point ScreenMus::GetCursorScreenPoint() {
}
bool ScreenMus::IsWindowUnderCursor(gfx::NativeWindow window) {
- if (!window)
- return false;
-
- return window->IsVisible() &&
- window->GetBoundsInScreen().Contains(GetCursorScreenPoint());
-}
-
-gfx::NativeWindow ScreenMus::GetWindowAtScreenPoint(const gfx::Point& point) {
- NOTIMPLEMENTED();
- return nullptr;
-}
-
-display::Display ScreenMus::GetPrimaryDisplay() const {
- return *display_list_.GetPrimaryDisplayIterator();
-}
-
-display::Display ScreenMus::GetDisplayNearestWindow(
- gfx::NativeView view) const {
- NOTIMPLEMENTED();
- return *display_list_.GetPrimaryDisplayIterator();
-}
-
-display::Display ScreenMus::GetDisplayNearestPoint(
- const gfx::Point& point) const {
- return *display::FindDisplayNearestPoint(display_list_.displays(), point);
-}
-
-int ScreenMus::GetNumDisplays() const {
- return static_cast<int>(display_list_.displays().size());
-}
-
-std::vector<display::Display> ScreenMus::GetAllDisplays() const {
- return display_list_.displays();
-}
-
-display::Display ScreenMus::GetDisplayMatching(
- const gfx::Rect& match_rect) const {
- const display::Display* match = display::FindDisplayWithBiggestIntersection(
- display_list_.displays(), match_rect);
- return match ? *match : GetPrimaryDisplay();
-}
-
-void ScreenMus::AddObserver(display::DisplayObserver* observer) {
- display_list_.AddObserver(observer);
-}
-
-void ScreenMus::RemoveObserver(display::DisplayObserver* observer) {
- display_list_.RemoveObserver(observer);
+ return window && window->IsVisible() &&
+ window->GetBoundsInScreen().Contains(GetCursorScreenPoint());
}
-void ScreenMus::OnDisplays(
- mojo::Array<mus::mojom::DisplayPtr> transport_displays) {
+void ScreenMus::OnDisplays(mojo::Array<ui::mojom::WsDisplayPtr> ws_displays) {
// This should only be called once from Init() before any observers have been
// added.
- DCHECK(display_list_.displays().empty());
- std::vector<display::Display> displays =
- transport_displays.To<std::vector<display::Display>>();
- for (size_t i = 0; i < displays.size(); ++i) {
- const bool is_primary = transport_displays[i]->is_primary;
- display_list_.AddDisplay(displays[i], is_primary
- ? DisplayList::Type::PRIMARY
- : DisplayList::Type::NOT_PRIMARY);
+ DCHECK(display_list()->displays().empty());
+ for (size_t i = 0; i < ws_displays.size(); ++i) {
+ const bool is_primary = ws_displays[i]->is_primary;
+ display_list()->AddDisplay(ws_displays[i]->display,
+ is_primary
+ ? display::DisplayList::Type::PRIMARY
+ : display::DisplayList::Type::NOT_PRIMARY);
if (is_primary) {
// TODO(sky): Make WindowManagerFrameValues per display.
WindowManagerFrameValues frame_values =
- transport_displays[i]
+ ws_displays[i]
->frame_decoration_values.To<WindowManagerFrameValues>();
WindowManagerFrameValues::SetInstance(frame_values);
}
}
- DCHECK(!display_list_.displays().empty());
+ DCHECK(!display_list()->displays().empty());
}
void ScreenMus::OnDisplaysChanged(
- mojo::Array<mus::mojom::DisplayPtr> transport_displays) {
- for (size_t i = 0; i < transport_displays.size(); ++i) {
- const bool is_primary = transport_displays[i]->is_primary;
- ProcessDisplayChanged(transport_displays[i].To<display::Display>(),
- is_primary);
+ mojo::Array<ui::mojom::WsDisplayPtr> ws_displays) {
+ for (size_t i = 0; i < ws_displays.size(); ++i) {
+ const bool is_primary = ws_displays[i]->is_primary;
+ ProcessDisplayChanged(ws_displays[i]->display, is_primary);
if (is_primary) {
WindowManagerFrameValues frame_values =
- transport_displays[i]
+ ws_displays[i]
->frame_decoration_values.To<WindowManagerFrameValues>();
WindowManagerFrameValues::SetInstance(frame_values);
if (delegate_)
@@ -191,7 +119,7 @@ void ScreenMus::OnDisplaysChanged(
}
void ScreenMus::OnDisplayRemoved(int64_t id) {
- display_list_.RemoveDisplay(id);
+ display_list()->RemoveDisplay(id);
}
} // namespace views
diff --git a/chromium/ui/views/mus/screen_mus.h b/chromium/ui/views/mus/screen_mus.h
index ddd9c14077d..b86d5d4b16b 100644
--- a/chromium/ui/views/mus/screen_mus.h
+++ b/chromium/ui/views/mus/screen_mus.h
@@ -5,15 +5,9 @@
#ifndef UI_VIEWS_MUS_SCREEN_MUS_H_
#define UI_VIEWS_MUS_SCREEN_MUS_H_
-#include <vector>
-
-#include "base/observer_list.h"
-#include "base/run_loop.h"
-#include "components/mus/public/interfaces/display.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/views/mus/display_list.h"
+#include "services/ui/public/interfaces/display.mojom.h"
+#include "ui/display/screen_base.h"
#include "ui/views/mus/mus_export.h"
namespace shell {
@@ -24,10 +18,10 @@ namespace views {
class ScreenMusDelegate;
-// Screen implementation backed by mus::mojom::DisplayManager.
+// Screen implementation backed by ui::mojom::DisplayManager.
class VIEWS_MUS_EXPORT ScreenMus
- : public display::Screen,
- public NON_EXPORTED_BASE(mus::mojom::DisplayManagerObserver) {
+ : public display::ScreenBase,
+ public NON_EXPORTED_BASE(ui::mojom::DisplayManagerObserver) {
public:
// |delegate| can be nullptr.
explicit ScreenMus(ScreenMusDelegate* delegate);
@@ -36,38 +30,20 @@ class VIEWS_MUS_EXPORT ScreenMus
void Init(shell::Connector* connector);
private:
- // Invoked when a display changed in some weay, including being added.
- // If |is_primary| is true, |changed_display| is the primary display.
- void ProcessDisplayChanged(const display::Display& changed_display,
- bool is_primary);
-
// display::Screen:
gfx::Point GetCursorScreenPoint() override;
bool IsWindowUnderCursor(gfx::NativeWindow window) override;
- gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override;
- display::Display GetPrimaryDisplay() const override;
- display::Display GetDisplayNearestWindow(gfx::NativeView view) const override;
- display::Display GetDisplayNearestPoint(
- const gfx::Point& point) const override;
- int GetNumDisplays() const override;
- std::vector<display::Display> GetAllDisplays() const override;
- display::Display GetDisplayMatching(
- const gfx::Rect& match_rect) const override;
- void AddObserver(display::DisplayObserver* observer) override;
- void RemoveObserver(display::DisplayObserver* observer) override;
- // mus::mojom::DisplayManager:
- void OnDisplays(
- mojo::Array<mus::mojom::DisplayPtr> transport_displays) override;
+ // ui::mojom::DisplayManager:
+ void OnDisplays(mojo::Array<ui::mojom::WsDisplayPtr> ws_displays) override;
void OnDisplaysChanged(
- mojo::Array<mus::mojom::DisplayPtr> transport_displays) override;
+ mojo::Array<ui::mojom::WsDisplayPtr> ws_displays) override;
void OnDisplayRemoved(int64_t id) override;
ScreenMusDelegate* delegate_; // Can be nullptr.
- mus::mojom::DisplayManagerPtr display_manager_;
- mojo::Binding<mus::mojom::DisplayManagerObserver>
+ ui::mojom::DisplayManagerPtr display_manager_;
+ mojo::Binding<ui::mojom::DisplayManagerObserver>
display_manager_observer_binding_;
- DisplayList display_list_;
DISALLOW_COPY_AND_ASSIGN(ScreenMus);
};
diff --git a/chromium/ui/views/mus/screen_mus_delegate.h b/chromium/ui/views/mus/screen_mus_delegate.h
index 1db1b67faaa..2ae48373b52 100644
--- a/chromium/ui/views/mus/screen_mus_delegate.h
+++ b/chromium/ui/views/mus/screen_mus_delegate.h
@@ -13,7 +13,7 @@ class Point;
namespace views {
-// Screen implementation backed by mus::mojom::DisplayManager.
+// Screen implementation backed by ui::mojom::DisplayManager.
class VIEWS_MUS_EXPORT ScreenMusDelegate {
public:
virtual void OnWindowManagerFrameValuesChanged() = 0;
diff --git a/chromium/ui/views/mus/surface_binding.cc b/chromium/ui/views/mus/surface_binding.cc
deleted file mode 100644
index fb0e3818bb5..00000000000
--- a/chromium/ui/views/mus/surface_binding.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2015 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/mus/surface_binding.h"
-
-#include <stdint.h>
-
-#include <map>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/threading/thread_local.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/output_surface.h"
-#include "cc/output/output_surface_client.h"
-#include "cc/output/software_output_device.h"
-#include "cc/resources/shared_bitmap_manager.h"
-#include "components/mus/public/cpp/context_provider.h"
-#include "components/mus/public/cpp/output_surface.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "ui/views/mus/window_tree_host_mus.h"
-
-namespace views {
-
-// PerClientState --------------------------------------------------------------
-
-// State needed per WindowTreeClient. Provides the real implementation of
-// CreateOutputSurface. SurfaceBinding obtains a pointer to the
-// PerClientState appropriate for the WindowTreeClient. PerClientState is
-// stored in a thread local map. When no more refereces to a PerClientState
-// remain the PerClientState is deleted and the underlying map cleaned up.
-class SurfaceBinding::PerClientState : public base::RefCounted<PerClientState> {
- public:
- static PerClientState* Get(shell::Connector* connector,
- mus::WindowTreeClient* client);
-
- std::unique_ptr<cc::OutputSurface> CreateOutputSurface(
- mus::Window* window,
- mus::mojom::SurfaceType type);
-
- private:
- typedef std::map<mus::WindowTreeClient*, PerClientState*> ClientToStateMap;
-
- friend class base::RefCounted<PerClientState>;
-
- PerClientState(shell::Connector* connector,
- mus::WindowTreeClient* client);
- ~PerClientState();
-
- static base::LazyInstance<
- base::ThreadLocalPointer<ClientToStateMap>>::Leaky window_states;
-
- shell::Connector* connector_;
- mus::WindowTreeClient* client_;
-
- DISALLOW_COPY_AND_ASSIGN(PerClientState);
-};
-
-// static
-base::LazyInstance<base::ThreadLocalPointer<
- SurfaceBinding::PerClientState::ClientToStateMap>>::Leaky
- SurfaceBinding::PerClientState::window_states;
-
-// static
-SurfaceBinding::PerClientState* SurfaceBinding::PerClientState::Get(
- shell::Connector* connector,
- mus::WindowTreeClient* client) {
- // |connector| can be null in some unit-tests.
- if (!connector)
- return nullptr;
- ClientToStateMap* window_map = window_states.Pointer()->Get();
- if (!window_map) {
- window_map = new ClientToStateMap;
- window_states.Pointer()->Set(window_map);
- }
- if (!(*window_map)[client])
- (*window_map)[client] = new PerClientState(connector, client);
- return (*window_map)[client];
-}
-
-std::unique_ptr<cc::OutputSurface>
-SurfaceBinding::PerClientState::CreateOutputSurface(
- mus::Window* window,
- mus::mojom::SurfaceType surface_type) {
- scoped_refptr<cc::ContextProvider> context_provider(
- new mus::ContextProvider(connector_));
- return base::WrapUnique(new mus::OutputSurface(
- context_provider, window->RequestSurface(surface_type)));
-}
-
-SurfaceBinding::PerClientState::PerClientState(
- shell::Connector* connector,
- mus::WindowTreeClient* client)
- : connector_(connector), client_(client) {}
-
-SurfaceBinding::PerClientState::~PerClientState() {
- ClientToStateMap* window_map = window_states.Pointer()->Get();
- DCHECK(window_map);
- DCHECK_EQ(this, (*window_map)[client_]);
- window_map->erase(client_);
- if (window_map->empty()) {
- delete window_map;
- window_states.Pointer()->Set(nullptr);
- }
-}
-
-// SurfaceBinding --------------------------------------------------------------
-
-SurfaceBinding::SurfaceBinding(shell::Connector* connector,
- mus::Window* window,
- mus::mojom::SurfaceType surface_type)
- : window_(window),
- surface_type_(surface_type),
- state_(PerClientState::Get(connector, window->window_tree())) {}
-
-SurfaceBinding::~SurfaceBinding() {}
-
-std::unique_ptr<cc::OutputSurface> SurfaceBinding::CreateOutputSurface() {
- return state_ ? state_->CreateOutputSurface(window_, surface_type_) : nullptr;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mus/surface_binding.h b/chromium/ui/views/mus/surface_binding.h
deleted file mode 100644
index 2ff6c76b6fa..00000000000
--- a/chromium/ui/views/mus/surface_binding.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 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_MUS_SURFACE_BINDING_H_
-#define UI_VIEWS_MUS_SURFACE_BINDING_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "ui/views/mus/mus_export.h"
-
-namespace cc {
-class OutputSurface;
-}
-
-namespace mus {
-class Window;
-}
-
-namespace shell {
-class Connector;
-}
-
-namespace views {
-
-// SurfaceBinding is responsible for managing the connections necessary to
-// bind a Window to the surfaces service.
-// Internally SurfaceBinding manages one connection (and related structures) per
-// WindowTree. That is, all Windows from a particular WindowTree share the same
-// connection.
-class VIEWS_MUS_EXPORT SurfaceBinding {
- public:
- SurfaceBinding(shell::Connector* connector,
- mus::Window* window,
- mus::mojom::SurfaceType surface_type);
- ~SurfaceBinding();
-
- // Creates an OutputSurface that renders to the Window supplied to the
- // constructor.
- std::unique_ptr<cc::OutputSurface> CreateOutputSurface();
-
- private:
- class PerClientState;
-
- mus::Window* window_;
- const mus::mojom::SurfaceType surface_type_;
- scoped_refptr<PerClientState> state_;
-
- DISALLOW_COPY_AND_ASSIGN(SurfaceBinding);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_MUS_SURFACE_BINDING_H_
diff --git a/chromium/ui/views/mus/surface_context_factory.cc b/chromium/ui/views/mus/surface_context_factory.cc
index 316d14e3c27..d5f9966bb77 100644
--- a/chromium/ui/views/mus/surface_context_factory.cc
+++ b/chromium/ui/views/mus/surface_context_factory.cc
@@ -5,13 +5,14 @@
#include "ui/views/mus/surface_context_factory.h"
#include "base/memory/ptr_util.h"
-#include "cc/output/output_surface.h"
#include "cc/resources/shared_bitmap_manager.h"
#include "cc/surfaces/surface_id_allocator.h"
-#include "components/mus/public/cpp/window.h"
-#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/ui/public/cpp/compositor_frame_sink.h"
+#include "services/ui/public/cpp/gpu_service.h"
+#include "services/ui/public/cpp/window.h"
#include "ui/compositor/reflector.h"
#include "ui/gl/gl_bindings.h"
+#include "ui/views/mus/native_widget_mus.h"
namespace views {
namespace {
@@ -27,22 +28,20 @@ class FakeReflector : public ui::Reflector {
} // namespace
-SurfaceContextFactory::SurfaceContextFactory(
- shell::Connector* connector,
- mus::Window* window,
- mus::mojom::SurfaceType surface_type)
- : surface_binding_(connector, window, surface_type),
- next_surface_id_namespace_(1u) {}
+SurfaceContextFactory::SurfaceContextFactory(ui::GpuService* gpu_service)
+ : next_sink_id_(1u), gpu_service_(gpu_service) {}
SurfaceContextFactory::~SurfaceContextFactory() {}
-void SurfaceContextFactory::CreateOutputSurface(
+void SurfaceContextFactory::CreateCompositorFrameSink(
base::WeakPtr<ui::Compositor> compositor) {
- // NOTIMPLEMENTED();
- std::unique_ptr<cc::OutputSurface> surface =
- surface_binding_.CreateOutputSurface();
- if (surface)
- compositor->SetOutputSurface(std::move(surface));
+ ui::Window* window = compositor->window();
+ NativeWidgetMus* native_widget = NativeWidgetMus::GetForWindow(window);
+ ui::mojom::SurfaceType surface_type = native_widget->surface_type();
+ auto compositor_frame_sink = base::MakeUnique<ui::CompositorFrameSink>(
+ gpu_service_->EstablishGpuChannelSync(),
+ window->RequestSurface(surface_type));
+ compositor->SetCompositorFrameSink(std::move(compositor_frame_sink));
}
std::unique_ptr<ui::Reflector> SurfaceContextFactory::CreateReflector(
@@ -83,27 +82,29 @@ cc::SharedBitmapManager* SurfaceContextFactory::GetSharedBitmapManager() {
gpu::GpuMemoryBufferManager*
SurfaceContextFactory::GetGpuMemoryBufferManager() {
- return &gpu_memory_buffer_manager_;
+ return gpu_service_->gpu_memory_buffer_manager();
}
cc::TaskGraphRunner* SurfaceContextFactory::GetTaskGraphRunner() {
return raster_thread_helper_.task_graph_runner();
}
-std::unique_ptr<cc::SurfaceIdAllocator>
-SurfaceContextFactory::CreateSurfaceIdAllocator() {
- return base::WrapUnique(
- new cc::SurfaceIdAllocator(next_surface_id_namespace_++));
+cc::FrameSinkId SurfaceContextFactory::AllocateFrameSinkId() {
+ return cc::FrameSinkId(0, next_sink_id_++);
}
cc::SurfaceManager* SurfaceContextFactory::GetSurfaceManager() {
- // NOTIMPLEMENTED();
- return nullptr;
+ return &surface_manager_;
+}
+
+void SurfaceContextFactory::SetDisplayVisible(ui::Compositor* compositor,
+ bool visible) {
+ // TODO(fsamuel): display[compositor]->SetVisible(visible);
}
void SurfaceContextFactory::ResizeDisplay(ui::Compositor* compositor,
const gfx::Size& size) {
- // NOTIMPLEMENTED();
+ // TODO(fsamuel): display[compositor]->Resize(size);
}
} // namespace views
diff --git a/chromium/ui/views/mus/surface_context_factory.h b/chromium/ui/views/mus/surface_context_factory.h
index 740d856cf19..d7bfe42b5e8 100644
--- a/chromium/ui/views/mus/surface_context_factory.h
+++ b/chromium/ui/views/mus/surface_context_factory.h
@@ -8,33 +8,27 @@
#include <stdint.h>
#include "base/macros.h"
-#include "components/mus/common/mojo_gpu_memory_buffer_manager.h"
-#include "components/mus/gles2/raster_thread_helper.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
+#include "cc/surfaces/surface_manager.h"
+#include "services/ui/public/cpp/raster_thread_helper.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "ui/compositor/compositor.h"
#include "ui/views/mus/mus_export.h"
-#include "ui/views/mus/surface_binding.h"
-namespace mojo {
-class Connector;
-}
-
-namespace mus {
-class Window;
+namespace ui {
+class GpuService;
}
namespace views {
class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory {
public:
- SurfaceContextFactory(shell::Connector* connector,
- mus::Window* window,
- mus::mojom::SurfaceType surface_type);
+ explicit SurfaceContextFactory(ui::GpuService* gpu_service);
~SurfaceContextFactory() override;
private:
// ContextFactory:
- void CreateOutputSurface(base::WeakPtr<ui::Compositor> compositor) override;
+ void CreateCompositorFrameSink(
+ base::WeakPtr<ui::Compositor> compositor) override;
std::unique_ptr<ui::Reflector> CreateReflector(
ui::Compositor* mirrored_compositor,
ui::Layer* mirroring_layer) override;
@@ -47,22 +41,26 @@ class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory {
cc::SharedBitmapManager* GetSharedBitmapManager() override;
gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
cc::TaskGraphRunner* GetTaskGraphRunner() override;
- std::unique_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override;
+ cc::FrameSinkId AllocateFrameSinkId() override;
cc::SurfaceManager* GetSurfaceManager() override;
+ void SetDisplayVisible(ui::Compositor* compositor, bool visible) override;
void ResizeDisplay(ui::Compositor* compositor,
const gfx::Size& size) override;
void SetDisplayColorSpace(ui::Compositor* compositor,
const gfx::ColorSpace& color_space) override {}
void SetAuthoritativeVSyncInterval(ui::Compositor* compositor,
base::TimeDelta interval) override {}
+ void SetDisplayVSyncParameters(ui::Compositor* compositor,
+ base::TimeTicks timebase,
+ base::TimeDelta interval) override {}
void SetOutputIsSecure(ui::Compositor* compositor, bool secure) override {}
void AddObserver(ui::ContextFactoryObserver* observer) override {}
void RemoveObserver(ui::ContextFactoryObserver* observer) override {}
- SurfaceBinding surface_binding_;
- uint32_t next_surface_id_namespace_;
- gles2::RasterThreadHelper raster_thread_helper_;
- mus::MojoGpuMemoryBufferManager gpu_memory_buffer_manager_;
+ cc::SurfaceManager surface_manager_;
+ uint32_t next_sink_id_;
+ ui::RasterThreadHelper raster_thread_helper_;
+ ui::GpuService* gpu_service_;
DISALLOW_COPY_AND_ASSIGN(SurfaceContextFactory);
};
diff --git a/chromium/ui/views/mus/text_input_client_impl.cc b/chromium/ui/views/mus/text_input_client_impl.cc
new file mode 100644
index 00000000000..59b4b995c66
--- /dev/null
+++ b/chromium/ui/views/mus/text_input_client_impl.cc
@@ -0,0 +1,55 @@
+// Copyright 2016 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/mus/text_input_client_impl.h"
+
+#include "ui/base/ime/text_input_client.h"
+#include "ui/views/mus/input_method_mus.h"
+
+namespace views {
+
+TextInputClientImpl::TextInputClientImpl(ui::TextInputClient* text_input_client,
+ InputMethodMus* input_method)
+ : text_input_client_(text_input_client),
+ input_method_(input_method),
+ binding_(this) {}
+
+TextInputClientImpl::~TextInputClientImpl() {}
+
+ui::mojom::TextInputClientPtr TextInputClientImpl::CreateInterfacePtrAndBind() {
+ return binding_.CreateInterfacePtrAndBind();
+}
+
+void TextInputClientImpl::OnCompositionEvent(
+ ui::mojom::CompositionEventPtr event) {
+ switch (event->type) {
+ case ui::mojom::CompositionEventType::INSERT_CHAR: {
+ DCHECK((*event->key_event)->IsKeyEvent());
+ ui::KeyEvent* key_event = (*event->key_event)->AsKeyEvent();
+ DCHECK(key_event->is_char());
+ text_input_client_->InsertChar(*key_event);
+ break;
+ }
+ case ui::mojom::CompositionEventType::CONFIRM:
+ text_input_client_->ConfirmCompositionText();
+ break;
+ case ui::mojom::CompositionEventType::CLEAR:
+ text_input_client_->ClearCompositionText();
+ break;
+ case ui::mojom::CompositionEventType::UPDATE:
+ case ui::mojom::CompositionEventType::INSERT_TEXT:
+ // TODO(moshayedi): crbug.com/631524. Implement these types of composition
+ // events once we have the necessary fields in ui.mojom.CompositionEvent.
+ NOTIMPLEMENTED();
+ break;
+ }
+}
+
+void TextInputClientImpl::OnUnhandledEvent(
+ std::unique_ptr<ui::Event> key_event) {
+ DCHECK(key_event && key_event->IsKeyEvent());
+ input_method_->DispatchKeyEventPostIME(key_event->AsKeyEvent());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/text_input_client_impl.h b/chromium/ui/views/mus/text_input_client_impl.h
new file mode 100644
index 00000000000..cb51a6cd913
--- /dev/null
+++ b/chromium/ui/views/mus/text_input_client_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2016 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_MUS_TEXT_INPUT_CLIENT_IMPL_H_
+#define UI_VIEWS_MUS_TEXT_INPUT_CLIENT_IMPL_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/ui/public/interfaces/ime.mojom.h"
+
+namespace ui {
+class TextInputClient;
+}
+
+namespace views {
+
+class InputMethodMus;
+
+// TextInputClientImpl receieves updates from IME drivers over Mojo IPC, and
+// notifies the underlying ui::TextInputClient accordingly.
+class TextInputClientImpl : public ui::mojom::TextInputClient {
+ public:
+ TextInputClientImpl(ui::TextInputClient* text_input_client,
+ InputMethodMus* input_method);
+ ~TextInputClientImpl() override;
+
+ ui::mojom::TextInputClientPtr CreateInterfacePtrAndBind();
+
+ private:
+ // ui::mojom::TextInputClient:
+ void OnCompositionEvent(ui::mojom::CompositionEventPtr event) override;
+ void OnUnhandledEvent(std::unique_ptr<ui::Event> key_event) override;
+
+ ui::TextInputClient* text_input_client_;
+ InputMethodMus* input_method_;
+ mojo::Binding<ui::mojom::TextInputClient> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextInputClientImpl);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_TEXT_INPUT_CLIENT_IMPL_H_
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
index 2257b8e8640..8b10feb0cbf 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ b/chromium/ui/views/mus/views_mus_test_suite.cc
@@ -5,6 +5,7 @@
#include "ui/views/mus/views_mus_test_suite.h"
#include <memory>
+#include <string>
#include "base/command_line.h"
#include "base/files/file_path.h"
@@ -12,12 +13,11 @@
#include "base/synchronization/waitable_event.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
-#include "components/mus/common/gpu_service.h"
-#include "components/mus/common/switches.h"
#include "services/shell/background/background_shell.h"
#include "services/shell/public/cpp/connector.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service.h"
+#include "services/shell/public/cpp/service_context.h"
+#include "services/ui/common/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/mus/window_manager_connection.h"
#include "ui/views/test/platform_test_helper.h"
@@ -32,27 +32,24 @@ void EnsureCommandLineSwitch(const std::string& name) {
cmd_line->AppendSwitch(name);
}
-class DefaultShellClient : public shell::ShellClient {
+class DefaultService : public shell::Service {
public:
- DefaultShellClient() {}
- ~DefaultShellClient() override {}
+ DefaultService() {}
+ ~DefaultService() override {}
private:
- DISALLOW_COPY_AND_ASSIGN(DefaultShellClient);
+ DISALLOW_COPY_AND_ASSIGN(DefaultService);
};
class PlatformTestHelperMus : public PlatformTestHelper {
public:
PlatformTestHelperMus(shell::Connector* connector,
const shell::Identity& identity) {
- mus::GpuService::Initialize(connector);
// It is necessary to recreate the WindowManagerConnection for each test,
// since a new MessageLoop is created for each test.
connection_ = WindowManagerConnection::Create(connector, identity);
}
- ~PlatformTestHelperMus() override {
- mus::GpuService::Terminate();
- }
+ ~PlatformTestHelperMus() override {}
private:
std::unique_ptr<WindowManagerConnection> connection_;
@@ -63,7 +60,7 @@ class PlatformTestHelperMus : public PlatformTestHelper {
std::unique_ptr<PlatformTestHelper> CreatePlatformTestHelper(
const shell::Identity& identity,
const base::Callback<shell::Connector*(void)>& callback) {
- return base::WrapUnique(new PlatformTestHelperMus(callback.Run(), identity));
+ return base::MakeUnique<PlatformTestHelperMus>(callback.Run(), identity);
}
} // namespace
@@ -118,16 +115,15 @@ class ShellConnection {
}
void SetUpConnections(base::WaitableEvent* wait) {
- background_shell_.reset(new shell::BackgroundShell);
+ background_shell_ = base::MakeUnique<shell::BackgroundShell>();
background_shell_->Init(nullptr);
- shell_client_.reset(new DefaultShellClient);
- shell_connection_.reset(new shell::ShellConnection(
- shell_client_.get(),
- background_shell_->CreateShellClientRequest(GetTestName())));
+ service_ = base::MakeUnique<DefaultService>();
+ shell_connection_ = base::MakeUnique<shell::ServiceContext>(
+ service_.get(), background_shell_->CreateServiceRequest(GetTestName()));
// ui/views/mus requires a WindowManager running, so launch test_wm.
shell::Connector* connector = shell_connection_->connector();
- connector->Connect("mojo:test_wm");
+ connector->Connect("service:test_wm");
shell_connector_ = connector->Clone();
shell_identity_ = shell_connection_->identity();
wait->Signal();
@@ -149,8 +145,8 @@ class ShellConnection {
base::Thread thread_;
std::unique_ptr<shell::BackgroundShell> background_shell_;
- std::unique_ptr<shell::ShellConnection> shell_connection_;
- std::unique_ptr<DefaultShellClient> shell_client_;
+ std::unique_ptr<shell::ServiceContext> shell_connection_;
+ std::unique_ptr<DefaultService> service_;
std::unique_ptr<shell::Connector> shell_connector_;
shell::Identity shell_identity_;
@@ -167,10 +163,10 @@ void ViewsMusTestSuite::Initialize() {
// Let other mojo apps know that we're running in tests. Do this with a
// command line flag to avoid making blocking calls to other processes for
// setup for tests (e.g. to unlock the screen in the window manager).
- EnsureCommandLineSwitch(mus::switches::kUseTestConfig);
+ EnsureCommandLineSwitch(ui::switches::kUseTestConfig);
ViewsTestSuite::Initialize();
- shell_connections_.reset(new ShellConnection);
+ shell_connections_ = base::MakeUnique<ShellConnection>();
}
void ViewsMusTestSuite::Shutdown() {
diff --git a/chromium/ui/views/mus/window_manager_connection.cc b/chromium/ui/views/mus/window_manager_connection.cc
index 4d1fe3bc11b..8c4cf85d690 100644
--- a/chromium/ui/views/mus/window_manager_connection.cc
+++ b/chromium/ui/views/mus/window_manager_connection.cc
@@ -4,21 +4,28 @@
#include "ui/views/mus/window_manager_connection.h"
+#include <set>
#include <utility>
#include "base/lazy_instance.h"
+#include "base/memory/ptr_util.h"
#include "base/threading/thread_local.h"
-#include "components/mus/public/cpp/property_type_converters.h"
-#include "components/mus/public/cpp/window.h"
-#include "components/mus/public/cpp/window_property.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/interfaces/event_matcher.mojom.h"
-#include "components/mus/public/interfaces/window_tree.mojom.h"
#include "services/shell/public/cpp/connection.h"
#include "services/shell/public/cpp/connector.h"
+#include "services/ui/public/cpp/gpu_service.h"
+#include "services/ui/public/cpp/property_type_converters.h"
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/cpp/window_property.h"
+#include "services/ui/public/cpp/window_tree_client.h"
+#include "services/ui/public/interfaces/event_matcher.mojom.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "ui/aura/env.h"
#include "ui/views/mus/clipboard_mus.h"
#include "ui/views/mus/native_widget_mus.h"
+#include "ui/views/mus/os_exchange_data_provider_mus.h"
+#include "ui/views/mus/pointer_watcher_event_router.h"
#include "ui/views/mus/screen_mus.h"
+#include "ui/views/mus/surface_context_factory.h"
#include "ui/views/pointer_watcher.h"
#include "ui/views/views_delegate.h"
@@ -34,13 +41,29 @@ base::LazyInstance<WindowManagerConnectionPtr>::Leaky lazy_tls_ptr =
} // namespace
+WindowManagerConnection::~WindowManagerConnection() {
+ // ~WindowTreeClient calls back to us (we're its delegate), destroy it while
+ // we are still valid.
+ client_.reset();
+ ui::OSExchangeDataProviderFactory::SetFactory(nullptr);
+ ui::Clipboard::DestroyClipboardForCurrentThread();
+ gpu_service_.reset();
+ lazy_tls_ptr.Pointer()->Set(nullptr);
+
+ if (ViewsDelegate::GetInstance()) {
+ ViewsDelegate::GetInstance()->set_native_widget_factory(
+ ViewsDelegate::NativeWidgetFactory());
+ }
+}
+
// static
std::unique_ptr<WindowManagerConnection> WindowManagerConnection::Create(
shell::Connector* connector,
- const shell::Identity& identity) {
+ const shell::Identity& identity,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DCHECK(!lazy_tls_ptr.Pointer()->Get());
WindowManagerConnection* connection =
- new WindowManagerConnection(connector, identity);
+ new WindowManagerConnection(connector, identity, std::move(task_runner));
DCHECK(lazy_tls_ptr.Pointer()->Get());
return base::WrapUnique(connection);
}
@@ -57,7 +80,7 @@ bool WindowManagerConnection::Exists() {
return !!lazy_tls_ptr.Pointer()->Get();
}
-mus::Window* WindowManagerConnection::NewWindow(
+ui::Window* WindowManagerConnection::NewWindow(
const std::map<std::string, std::vector<uint8_t>>& properties) {
return client_->NewTopLevelWindow(&properties);
}
@@ -73,109 +96,66 @@ NativeWidget* WindowManagerConnection::CreateNativeWidgetMus(
return nullptr;
std::map<std::string, std::vector<uint8_t>> properties = props;
NativeWidgetMus::ConfigurePropertiesForNewWindow(init_params, &properties);
- properties[mus::mojom::WindowManager::kAppID_Property] =
+ properties[ui::mojom::WindowManager::kAppID_Property] =
mojo::ConvertTo<std::vector<uint8_t>>(identity_.name());
- return new NativeWidgetMus(delegate, connector_, NewWindow(properties),
- mus::mojom::SurfaceType::DEFAULT);
-}
-
-void WindowManagerConnection::AddPointerWatcher(PointerWatcher* watcher) {
- bool had_watcher = HasPointerWatcher();
- pointer_watchers_.AddObserver(watcher);
- if (!had_watcher) {
- // Start a watcher for pointer down.
- // TODO(jamescook): Extend event observers to handle multiple event types.
- mus::mojom::EventMatcherPtr matcher = mus::mojom::EventMatcher::New();
- matcher->type_matcher = mus::mojom::EventTypeMatcher::New();
- matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN;
- client_->SetEventObserver(std::move(matcher));
- }
+ return new NativeWidgetMus(delegate, NewWindow(properties),
+ ui::mojom::SurfaceType::DEFAULT);
}
-void WindowManagerConnection::RemovePointerWatcher(PointerWatcher* watcher) {
- pointer_watchers_.RemoveObserver(watcher);
- if (!HasPointerWatcher()) {
- // Last PointerWatcher removed, stop the event observer.
- client_->SetEventObserver(nullptr);
- }
+const std::set<ui::Window*>& WindowManagerConnection::GetRoots() const {
+ return client_->GetRoots();
}
WindowManagerConnection::WindowManagerConnection(
shell::Connector* connector,
- const shell::Identity& identity)
+ const shell::Identity& identity,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: connector_(connector), identity_(identity) {
lazy_tls_ptr.Pointer()->Set(this);
- client_.reset(new mus::WindowTreeClient(this, nullptr, nullptr));
+
+ gpu_service_ = ui::GpuService::Create(connector, std::move(task_runner));
+ compositor_context_factory_ =
+ base::MakeUnique<views::SurfaceContextFactory>(gpu_service_.get());
+ aura::Env::GetInstance()->set_context_factory(
+ compositor_context_factory_.get());
+ client_ = base::MakeUnique<ui::WindowTreeClient>(this, nullptr, nullptr);
client_->ConnectViaWindowTreeFactory(connector_);
- screen_.reset(new ScreenMus(this));
+ pointer_watcher_event_router_ =
+ base::MakeUnique<PointerWatcherEventRouter>(client_.get());
+
+ screen_ = base::MakeUnique<ScreenMus>(this);
screen_->Init(connector);
- std::unique_ptr<ClipboardMus> clipboard(new ClipboardMus);
+ std::unique_ptr<ClipboardMus> clipboard = base::MakeUnique<ClipboardMus>();
clipboard->Init(connector);
ui::Clipboard::SetClipboardForCurrentThread(std::move(clipboard));
+ ui::OSExchangeDataProviderFactory::SetFactory(this);
+
ViewsDelegate::GetInstance()->set_native_widget_factory(base::Bind(
&WindowManagerConnection::CreateNativeWidgetMus,
base::Unretained(this),
std::map<std::string, std::vector<uint8_t>>()));
}
-WindowManagerConnection::~WindowManagerConnection() {
- // ~WindowTreeClient calls back to us (we're its delegate), destroy it while
- // we are still valid.
- client_.reset();
- ui::Clipboard::DestroyClipboardForCurrentThread();
- lazy_tls_ptr.Pointer()->Set(nullptr);
-
- if (ViewsDelegate::GetInstance()) {
- ViewsDelegate::GetInstance()->set_native_widget_factory(
- ViewsDelegate::NativeWidgetFactory());
- }
-}
+void WindowManagerConnection::OnEmbed(ui::Window* root) {}
-bool WindowManagerConnection::HasPointerWatcher() {
- // Check to see if we really have any observers left. This doesn't use
- // base::ObserverList<>::might_have_observers() because that returns true
- // during iteration over the list even when the last observer is removed.
- base::ObserverList<PointerWatcher>::Iterator iterator(&pointer_watchers_);
- return !!iterator.GetNext();
+void WindowManagerConnection::OnLostConnection(ui::WindowTreeClient* client) {
+ DCHECK_EQ(client, client_.get());
+ client_.reset();
}
-void WindowManagerConnection::OnEmbed(mus::Window* root) {}
-
-void WindowManagerConnection::OnWindowTreeClientDestroyed(
- mus::WindowTreeClient* client) {
- if (client_.get() == client) {
- client_.release();
- } else {
- DCHECK(!client_);
- }
+void WindowManagerConnection::OnEmbedRootDestroyed(ui::Window* root) {
+ // Not called for WindowManagerConnection as WindowTreeClient isn't created by
+ // way of an Embed().
+ NOTREACHED();
}
-void WindowManagerConnection::OnEventObserved(const ui::Event& event,
- mus::Window* target) {
- if (!event.IsLocatedEvent())
- return;
- Widget* target_widget = nullptr;
- if (target) {
- mus::Window* root = target->GetRoot();
- target_widget = NativeWidgetMus::GetWidgetForWindow(root);
- }
-
- // The mojo input events type converter uses the event root_location field
- // to store screen coordinates. Screen coordinates really should be returned
- // separately. See http://crbug.com/608547
- gfx::Point location_in_screen = event.AsLocatedEvent()->root_location();
- if (event.type() == ui::ET_MOUSE_PRESSED) {
- FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_,
- OnMousePressed(*event.AsMouseEvent(), location_in_screen,
- target_widget));
- } else if (event.type() == ui::ET_TOUCH_PRESSED) {
- FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_,
- OnTouchPressed(*event.AsTouchEvent(), location_in_screen,
- target_widget));
- }
+void WindowManagerConnection::OnPointerEventObserved(
+ const ui::PointerEvent& event,
+ ui::Window* target) {
+ pointer_watcher_event_router_->OnPointerEventObserved(event, target);
}
void WindowManagerConnection::OnWindowManagerFrameValuesChanged() {
@@ -187,4 +167,9 @@ gfx::Point WindowManagerConnection::GetCursorScreenPoint() {
return client_->GetCursorScreenPoint();
}
+std::unique_ptr<OSExchangeData::Provider>
+WindowManagerConnection::BuildProvider() {
+ return base::MakeUnique<OSExchangeDataProviderMus>();
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/window_manager_connection.h b/chromium/ui/views/mus/window_manager_connection.h
index 8af483995bc..cad161ac061 100644
--- a/chromium/ui/views/mus/window_manager_connection.h
+++ b/chromium/ui/views/mus/window_manager_connection.h
@@ -13,9 +13,9 @@
#include <vector>
#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
#include "services/shell/public/cpp/identity.h"
+#include "services/ui/public/cpp/window_tree_client_delegate.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/mus/screen_mus_delegate.h"
#include "ui/views/widget/widget.h"
@@ -24,11 +24,17 @@ namespace shell {
class Connector;
}
+namespace ui {
+class GpuService;
+}
+
namespace views {
class ClipboardMus;
class NativeWidget;
class PointerWatcher;
+class PointerWatcherEventRouter;
class ScreenMus;
+class SurfaceContextFactory;
namespace internal {
class NativeWidgetDelegate;
}
@@ -43,54 +49,65 @@ class NativeWidgetDelegate;
//
// TODO(sky): this name is now totally confusing. Come up with a better one.
class VIEWS_MUS_EXPORT WindowManagerConnection
- : public NON_EXPORTED_BASE(mus::WindowTreeClientDelegate),
- public ScreenMusDelegate {
+ : public NON_EXPORTED_BASE(ui::WindowTreeClientDelegate),
+ public ScreenMusDelegate,
+ public ui::OSExchangeDataProviderFactory::Factory {
public:
+ ~WindowManagerConnection() override;
+
+ // |io_task_runner| is used by the gpu service. If no task runner is provided,
+ // then a new thread is created and used by ui::GpuService.
static std::unique_ptr<WindowManagerConnection> Create(
shell::Connector* connector,
- const shell::Identity& identity);
+ const shell::Identity& identity,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = nullptr);
static WindowManagerConnection* Get();
static bool Exists();
- ~WindowManagerConnection() override;
-
+ PointerWatcherEventRouter* pointer_watcher_event_router() {
+ return pointer_watcher_event_router_.get();
+ }
shell::Connector* connector() { return connector_; }
+ ui::GpuService* gpu_service() { return gpu_service_.get(); }
+ ui::WindowTreeClient* client() { return client_.get(); }
- mus::Window* NewWindow(const std::map<std::string,
- std::vector<uint8_t>>& properties);
+ ui::Window* NewWindow(
+ const std::map<std::string, std::vector<uint8_t>>& properties);
NativeWidget* CreateNativeWidgetMus(
const std::map<std::string, std::vector<uint8_t>>& properties,
const Widget::InitParams& init_params,
internal::NativeWidgetDelegate* delegate);
- void AddPointerWatcher(PointerWatcher* watcher);
- void RemovePointerWatcher(PointerWatcher* watcher);
+ const std::set<ui::Window*>& GetRoots() const;
private:
- friend class WindowManagerConnectionTest;
-
- WindowManagerConnection(shell::Connector* connector,
- const shell::Identity& identity);
-
- // Returns true if there is one or more pointer watchers for this client.
- bool HasPointerWatcher();
+ WindowManagerConnection(
+ shell::Connector* connector,
+ const shell::Identity& identity,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- // mus::WindowTreeClientDelegate:
- void OnEmbed(mus::Window* root) override;
- void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override;
- void OnEventObserved(const ui::Event& event, mus::Window* target) override;
+ // ui::WindowTreeClientDelegate:
+ void OnEmbed(ui::Window* root) override;
+ void OnLostConnection(ui::WindowTreeClient* client) override;
+ void OnEmbedRootDestroyed(ui::Window* root) override;
+ void OnPointerEventObserved(const ui::PointerEvent& event,
+ ui::Window* target) override;
// ScreenMusDelegate:
void OnWindowManagerFrameValuesChanged() override;
gfx::Point GetCursorScreenPoint() override;
+ // ui:OSExchangeDataProviderFactory::Factory:
+ std::unique_ptr<OSExchangeData::Provider> BuildProvider() override;
+
shell::Connector* connector_;
shell::Identity identity_;
std::unique_ptr<ScreenMus> screen_;
- std::unique_ptr<mus::WindowTreeClient> client_;
- // Must be empty on destruction.
- base::ObserverList<PointerWatcher, true> pointer_watchers_;
+ std::unique_ptr<ui::WindowTreeClient> client_;
+ std::unique_ptr<ui::GpuService> gpu_service_;
+ std::unique_ptr<PointerWatcherEventRouter> pointer_watcher_event_router_;
+ std::unique_ptr<SurfaceContextFactory> compositor_context_factory_;
DISALLOW_COPY_AND_ASSIGN(WindowManagerConnection);
};
diff --git a/chromium/ui/views/mus/window_manager_connection_unittest.cc b/chromium/ui/views/mus/window_manager_connection_unittest.cc
deleted file mode 100644
index 967b5ad83d0..00000000000
--- a/chromium/ui/views/mus/window_manager_connection_unittest.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2016 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/mus/window_manager_connection.h"
-
-#include <memory>
-
-#include "base/message_loop/message_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/event.h"
-#include "ui/views/pointer_watcher.h"
-#include "ui/views/test/scoped_views_test_helper.h"
-
-namespace views {
-namespace {
-
-class TestPointerWatcher : public PointerWatcher {
- public:
- TestPointerWatcher() {}
- ~TestPointerWatcher() override {}
-
- bool mouse_pressed() const { return mouse_pressed_; }
- bool touch_pressed() const { return touch_pressed_; }
-
- void Reset() {
- mouse_pressed_ = false;
- touch_pressed_ = false;
- }
-
- // PointerWatcher:
- void OnMousePressed(const ui::MouseEvent& event,
- const gfx::Point& location_in_screen,
- Widget* target) override {
- mouse_pressed_ = true;
- }
- void OnTouchPressed(const ui::TouchEvent& event,
- const gfx::Point& location_in_screen,
- Widget* target) override {
- touch_pressed_ = true;
- }
-
- private:
- bool mouse_pressed_ = false;
- bool touch_pressed_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(TestPointerWatcher);
-};
-
-} // namespace
-
-class WindowManagerConnectionTest : public testing::Test {
- public:
- WindowManagerConnectionTest() {}
- ~WindowManagerConnectionTest() override {}
-
- void OnEventObserved(const ui::Event& event) {
- WindowManagerConnection::Get()->OnEventObserved(event, nullptr);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(WindowManagerConnectionTest);
-};
-
-TEST_F(WindowManagerConnectionTest, PointerWatcher) {
- base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
- ScopedViewsTestHelper helper;
- WindowManagerConnection* connection = WindowManagerConnection::Get();
- ASSERT_TRUE(connection);
- ui::MouseEvent mouse_pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
- base::TimeTicks(), ui::EF_NONE, 0);
- ui::TouchEvent touch_pressed(ui::ET_TOUCH_PRESSED, gfx::Point(), 1,
- base::TimeTicks());
- ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, 0);
-
- // PointerWatchers receive mouse events.
- TestPointerWatcher watcher1;
- connection->AddPointerWatcher(&watcher1);
- OnEventObserved(mouse_pressed);
- EXPECT_TRUE(watcher1.mouse_pressed());
- watcher1.Reset();
-
- // PointerWatchers receive touch events.
- OnEventObserved(touch_pressed);
- EXPECT_TRUE(watcher1.touch_pressed());
- watcher1.Reset();
-
- // PointerWatchers do not trigger for key events.
- OnEventObserved(key_pressed);
- EXPECT_FALSE(watcher1.mouse_pressed());
- EXPECT_FALSE(watcher1.touch_pressed());
- watcher1.Reset();
-
- // Two PointerWatchers can both receive a single observed event.
- TestPointerWatcher watcher2;
- connection->AddPointerWatcher(&watcher2);
- OnEventObserved(mouse_pressed);
- EXPECT_TRUE(watcher1.mouse_pressed());
- EXPECT_TRUE(watcher2.mouse_pressed());
- watcher1.Reset();
- watcher2.Reset();
-
- // Removing the first PointerWatcher stops sending events to it.
- connection->RemovePointerWatcher(&watcher1);
- OnEventObserved(mouse_pressed);
- EXPECT_FALSE(watcher1.mouse_pressed());
- EXPECT_TRUE(watcher2.mouse_pressed());
- watcher1.Reset();
- watcher2.Reset();
-
- // Removing the last PointerWatcher stops sending events to it.
- connection->RemovePointerWatcher(&watcher2);
- OnEventObserved(mouse_pressed);
- EXPECT_FALSE(watcher1.mouse_pressed());
- EXPECT_FALSE(watcher1.touch_pressed());
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mus/window_manager_constants_converters.cc b/chromium/ui/views/mus/window_manager_constants_converters.cc
index 889737698f1..90ee4793112 100644
--- a/chromium/ui/views/mus/window_manager_constants_converters.cc
+++ b/chromium/ui/views/mus/window_manager_constants_converters.cc
@@ -7,30 +7,30 @@
namespace mojo {
// static
-mus::mojom::WindowType
-TypeConverter<mus::mojom::WindowType, views::Widget::InitParams::Type>::Convert(
+ui::mojom::WindowType
+TypeConverter<ui::mojom::WindowType, views::Widget::InitParams::Type>::Convert(
views::Widget::InitParams::Type type) {
switch (type) {
case views::Widget::InitParams::TYPE_WINDOW:
- return mus::mojom::WindowType::WINDOW;
+ return ui::mojom::WindowType::WINDOW;
case views::Widget::InitParams::TYPE_PANEL:
- return mus::mojom::WindowType::PANEL;
+ return ui::mojom::WindowType::PANEL;
case views::Widget::InitParams::TYPE_WINDOW_FRAMELESS:
- return mus::mojom::WindowType::WINDOW_FRAMELESS;
+ return ui::mojom::WindowType::WINDOW_FRAMELESS;
case views::Widget::InitParams::TYPE_CONTROL:
- return mus::mojom::WindowType::CONTROL;
+ return ui::mojom::WindowType::CONTROL;
case views::Widget::InitParams::TYPE_POPUP:
- return mus::mojom::WindowType::POPUP;
+ return ui::mojom::WindowType::POPUP;
case views::Widget::InitParams::TYPE_MENU:
- return mus::mojom::WindowType::MENU;
+ return ui::mojom::WindowType::MENU;
case views::Widget::InitParams::TYPE_TOOLTIP:
- return mus::mojom::WindowType::TOOLTIP;
+ return ui::mojom::WindowType::TOOLTIP;
case views::Widget::InitParams::TYPE_BUBBLE:
- return mus::mojom::WindowType::BUBBLE;
+ return ui::mojom::WindowType::BUBBLE;
case views::Widget::InitParams::TYPE_DRAG:
- return mus::mojom::WindowType::DRAG;
+ return ui::mojom::WindowType::DRAG;
}
- return mus::mojom::WindowType::POPUP;
+ return ui::mojom::WindowType::POPUP;
}
} // namespace mojo
diff --git a/chromium/ui/views/mus/window_manager_constants_converters.h b/chromium/ui/views/mus/window_manager_constants_converters.h
index 0c73d9d8f58..1a93a030f9a 100644
--- a/chromium/ui/views/mus/window_manager_constants_converters.h
+++ b/chromium/ui/views/mus/window_manager_constants_converters.h
@@ -5,11 +5,11 @@
#ifndef UI_VIEWS_MUS_WINDOW_MANAGER_CONSTANTS_CONVERTERS_H_
#define UI_VIEWS_MUS_WINDOW_MANAGER_CONSTANTS_CONVERTERS_H_
-#include "components/mus/public/interfaces/window_manager_constants.mojom.h"
+#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/widget/widget.h"
-namespace mus {
+namespace ui {
class Window;
}
@@ -17,8 +17,8 @@ namespace mojo {
template <>
struct VIEWS_MUS_EXPORT
- TypeConverter<mus::mojom::WindowType, views::Widget::InitParams::Type> {
- static mus::mojom::WindowType Convert(views::Widget::InitParams::Type type);
+ TypeConverter<ui::mojom::WindowType, views::Widget::InitParams::Type> {
+ static ui::mojom::WindowType Convert(views::Widget::InitParams::Type type);
};
} // namespace mojo
diff --git a/chromium/ui/views/mus/window_tree_host_mus.cc b/chromium/ui/views/mus/window_tree_host_mus.cc
index 4aed38c33de..caed894310e 100644
--- a/chromium/ui/views/mus/window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/window_tree_host_mus.cc
@@ -5,7 +5,7 @@
#include "ui/views/mus/window_tree_host_mus.h"
#include "base/memory/ptr_util.h"
-#include "components/mus/public/cpp/window.h"
+#include "services/ui/public/cpp/window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/events/event.h"
@@ -23,7 +23,7 @@ static uint32_t accelerated_widget_count = 1;
// WindowTreeHostMus, public:
WindowTreeHostMus::WindowTreeHostMus(NativeWidgetMus* native_widget,
- mus::Window* window)
+ ui::Window* window)
: native_widget_(native_widget) {
// We need accelerated widget numbers to be different for each
// window and fit in the smallest sizeof(AcceleratedWidget) uint32_t
@@ -38,11 +38,13 @@ WindowTreeHostMus::WindowTreeHostMus(NativeWidgetMus* native_widget,
// TODO(markdittmer): Use correct device-scale-factor from |window|.
OnAcceleratedWidgetAvailable(accelerated_widget, 1.f);
- SetPlatformWindow(base::WrapUnique(new ui::StubWindow(
+ SetPlatformWindow(base::MakeUnique<ui::StubWindow>(
this,
- false))); // Do not advertise accelerated widget; already set manually.
+ false)); // Do not advertise accelerated widget; already set manually.
- // Initialize the stub platform window bounds to those of the mus::Window.
+ compositor()->SetWindow(window);
+
+ // Initialize the stub platform window bounds to those of the ui::Window.
platform_window()->SetBounds(window->bounds());
// The location of events is already transformed, and there is no way to
@@ -52,7 +54,7 @@ WindowTreeHostMus::WindowTreeHostMus(NativeWidgetMus* native_widget,
dispatcher()->set_transform_events(false);
compositor()->SetHostHasTransparentBackground(true);
- input_method_.reset(new InputMethodMUS(this, window));
+ input_method_ = base::MakeUnique<InputMethodMus>(this, window);
SetSharedInputMethod(input_method_.get());
}
@@ -61,10 +63,13 @@ WindowTreeHostMus::~WindowTreeHostMus() {
DestroyDispatcher();
}
+void WindowTreeHostMus::InitInputMethod(shell::Connector* connector) {
+ input_method_->Init(connector);
+}
+
void WindowTreeHostMus::DispatchEvent(ui::Event* event) {
if (event->IsKeyEvent() && GetInputMethod()) {
GetInputMethod()->DispatchKeyEvent(event->AsKeyEvent());
- event->StopPropagation();
return;
}
WindowTreeHostPlatform::DispatchEvent(event);
@@ -89,4 +94,9 @@ void WindowTreeHostMus::OnCloseRequest() {
OnHostCloseRequested();
}
+gfx::ICCProfile WindowTreeHostMus::GetICCProfileForCurrentDisplay() {
+ // TODO: This should read the profile from mus. crbug.com/647510
+ return gfx::ICCProfile();
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/window_tree_host_mus.h b/chromium/ui/views/mus/window_tree_host_mus.h
index 683e65faa1e..535aeb2fb07 100644
--- a/chromium/ui/views/mus/window_tree_host_mus.h
+++ b/chromium/ui/views/mus/window_tree_host_mus.h
@@ -6,12 +6,13 @@
#define UI_VIEWS_MUS_WINDOW_TREE_HOST_MUS_H_
#include "base/macros.h"
+#include "services/shell/public/cpp/connector.h"
#include "ui/aura/window_tree_host_platform.h"
#include "ui/views/mus/mus_export.h"
class SkBitmap;
-namespace mus {
+namespace ui {
class Window;
}
@@ -21,14 +22,17 @@ class Connector;
namespace views {
-class InputMethodMUS;
+class InputMethodMus;
class NativeWidgetMus;
class PlatformWindowMus;
class VIEWS_MUS_EXPORT WindowTreeHostMus : public aura::WindowTreeHostPlatform {
public:
- WindowTreeHostMus(NativeWidgetMus* native_widget, mus::Window* window);
+ WindowTreeHostMus(NativeWidgetMus* native_widget, ui::Window* window);
~WindowTreeHostMus() override;
+ NativeWidgetMus* native_widget() { return native_widget_; }
+
+ void InitInputMethod(shell::Connector* connector);
private:
// aura::WindowTreeHostPlatform:
@@ -36,9 +40,10 @@ class VIEWS_MUS_EXPORT WindowTreeHostMus : public aura::WindowTreeHostPlatform {
void OnClosed() override;
void OnActivationChanged(bool active) override;
void OnCloseRequest() override;
+ gfx::ICCProfile GetICCProfileForCurrentDisplay() override;
NativeWidgetMus* native_widget_;
- std::unique_ptr<InputMethodMUS> input_method_;
+ std::unique_ptr<InputMethodMus> input_method_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeHostMus);
};
diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc
index c9cc6a64328..8d4fc45aa28 100644
--- a/chromium/ui/views/painter.cc
+++ b/chromium/ui/views/painter.cc
@@ -65,8 +65,7 @@ void SolidRoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
gfx::ScopedCanvas scoped_canvas(canvas);
const float scale = canvas->UndoDeviceScaleFactor();
- gfx::RectF border_rect_f((gfx::SizeF(size)));
- border_rect_f.Scale(scale);
+ gfx::RectF border_rect_f(gfx::ScaleToEnclosingRect(gfx::Rect(size), scale));
const SkScalar scaled_corner_radius = SkFloatToScalar(radius_ * scale);
SkPaint paint;
@@ -344,20 +343,20 @@ Painter* Painter::CreateImageGridPainter(const int image_ids[]) {
// static
std::unique_ptr<Painter> Painter::CreateDashedFocusPainter() {
- return base::WrapUnique(new DashedFocusPainter(gfx::Insets()));
+ return base::MakeUnique<DashedFocusPainter>(gfx::Insets());
}
// static
std::unique_ptr<Painter> Painter::CreateDashedFocusPainterWithInsets(
const gfx::Insets& insets) {
- return base::WrapUnique(new DashedFocusPainter(insets));
+ return base::MakeUnique<DashedFocusPainter>(insets);
}
// static
std::unique_ptr<Painter> Painter::CreateSolidFocusPainter(
SkColor color,
const gfx::Insets& insets) {
- return base::WrapUnique(new SolidFocusPainter(color, insets));
+ return base::MakeUnique<SolidFocusPainter>(color, insets);
}
// HorizontalPainter ----------------------------------------------------------
diff --git a/chromium/ui/views/pointer_watcher.h b/chromium/ui/views/pointer_watcher.h
index 2abc4cb42d2..7a68216db7d 100644
--- a/chromium/ui/views/pointer_watcher.h
+++ b/chromium/ui/views/pointer_watcher.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_POINTER_WATCHER_H_
#define UI_VIEWS_POINTER_WATCHER_H_
+#include "base/macros.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -12,29 +13,49 @@ class Point;
}
namespace ui {
-class MouseEvent;
-class TouchEvent;
+class PointerEvent;
}
namespace views {
class Widget;
+// When a PointerWatcher is added the types of events desired is specified by
+// way of PointerWatcherEventTypes.
+enum class PointerWatcherEventTypes {
+ // The PointerWatcher is interested in press, release, capture and mouse
+ // wheel.
+ BASIC,
+ // The PointerWatcher is interested in BASIC events, as well as move
+ // events.
+ MOVES,
+ // The PointerWatcher is interested in MOVE events, as well as drag
+ // events.
+ DRAGS
+};
+
// An interface for read-only observation of pointer events (in particular, the
// events cannot be marked as handled). Only certain event types are supported.
// The |target| is the top-level widget that will receive the event, if any.
+// To reduce IPC traffic from the window server, move events are not provided
+// unless the app specifically requests them.
// NOTE: On mus this allows observation of events outside of windows owned
// by the current process, in which case the |target| will be null. On mus
// event.target() is always null.
+// NOTE: Mouse capture change events are sent through OnPointerEventObserved and
+// its |target| is always null.
class VIEWS_EXPORT PointerWatcher {
public:
+ PointerWatcher() {}
+
+ virtual void OnPointerEventObserved(const ui::PointerEvent& event,
+ const gfx::Point& location_in_screen,
+ Widget* target) = 0;
+
+ protected:
virtual ~PointerWatcher() {}
- virtual void OnMousePressed(const ui::MouseEvent& event,
- const gfx::Point& location_in_screen,
- Widget* target) = 0;
- virtual void OnTouchPressed(const ui::TouchEvent& event,
- const gfx::Point& location_in_screen,
- Widget* target) = 0;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PointerWatcher);
};
} // namespace views
diff --git a/chromium/ui/views/repeat_controller.h b/chromium/ui/views/repeat_controller.h
index 5eef95961ed..aff5a35fbf3 100644
--- a/chromium/ui/views/repeat_controller.h
+++ b/chromium/ui/views/repeat_controller.h
@@ -33,6 +33,8 @@ class RepeatController {
// Stop repeating.
void Stop();
+ const base::OneShotTimer& timer_for_testing() const { return timer_; }
+
private:
// Called when the timer expires.
void Run();
diff --git a/chromium/ui/views/resources/default_100_percent/slider_right_active.png b/chromium/ui/views/resources/default_100_percent/slider_right_active.png
deleted file mode 100644
index 3fa882dd86c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/slider_right_active.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/slider_right_active.png b/chromium/ui/views/resources/default_200_percent/slider_right_active.png
deleted file mode 100644
index 3da2bb7558b..00000000000
--- a/chromium/ui/views/resources/default_200_percent/slider_right_active.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/views_resources.grd b/chromium/ui/views/resources/views_resources.grd
index 7d6eb05ee83..dbcd9c47cca 100644
--- a/chromium/ui/views/resources/views_resources.grd
+++ b/chromium/ui/views/resources/views_resources.grd
@@ -160,7 +160,6 @@
<structure type="chrome_scaled_image" name="IDR_MENU_CHECK" file="cros/menu_check.png" />
</if>
<structure type="chrome_scaled_image" name="IDR_SLIDER_ACTIVE_LEFT" file="slider_left_active.png" />
- <structure type="chrome_scaled_image" name="IDR_SLIDER_ACTIVE_RIGHT" file="slider_right_active.png" />
<structure type="chrome_scaled_image" name="IDR_SLIDER_ACTIVE_CENTER" file="slider_center_active.png" />
<structure type="chrome_scaled_image" name="IDR_SLIDER_DISABLED_LEFT" file="slider_left_disabled.png" />
<structure type="chrome_scaled_image" name="IDR_SLIDER_DISABLED_RIGHT" file="slider_right_disabled.png" />
diff --git a/chromium/ui/views/resources/views_resources.gyp b/chromium/ui/views/resources/views_resources.gyp
deleted file mode 100644
index 1596f3621f6..00000000000
--- a/chromium/ui/views/resources/views_resources.gyp
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2015 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.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //ui/views/resources
- 'target_name': 'views_resources',
- 'type': 'none',
- 'variables': {
- 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/views/resources',
- },
- 'actions': [{
- 'action_name': 'views_resources',
- 'variables': {
- 'grit_grd_file': 'views_resources.grd',
- },
- 'includes': [ '../../../build/grit_action.gypi' ],
- }],
- 'includes': [ '../../../build/grit_target.gypi' ],
- },
- ],
-}
diff --git a/chromium/ui/views/round_rect_painter.cc b/chromium/ui/views/round_rect_painter.cc
index 1b96a125c43..7673b72a380 100644
--- a/chromium/ui/views/round_rect_painter.cc
+++ b/chromium/ui/views/round_rect_painter.cc
@@ -26,14 +26,14 @@ void RoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
SkPaint paint;
paint.setColor(border_color_);
paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(1);
+ paint.setStrokeWidth(kBorderWidth);
paint.setFlags(SkPaint::kAntiAlias_Flag);
gfx::Rect rect(size);
- rect.Inset(0, 0, 1, 1);
+ rect.Inset(0, 0, kBorderWidth, kBorderWidth);
SkRect skia_rect = gfx::RectToSkRect(rect);
- skia_rect.offset(.5, .5);
+ skia_rect.offset(kBorderWidth / 2.f, kBorderWidth / 2.f);
canvas->sk_canvas()->drawRoundRect(skia_rect, SkIntToScalar(corner_radius_),
- SkIntToScalar(corner_radius_), paint);
+ SkIntToScalar(corner_radius_), paint);
}
} // namespace views
diff --git a/chromium/ui/views/round_rect_painter.h b/chromium/ui/views/round_rect_painter.h
index f52624a425a..17c51d0fc60 100644
--- a/chromium/ui/views/round_rect_painter.h
+++ b/chromium/ui/views/round_rect_painter.h
@@ -21,6 +21,8 @@ namespace views {
// Painter to draw a border with rounded corners.
class VIEWS_EXPORT RoundRectPainter : public Painter {
public:
+ enum { kBorderWidth = 1 };
+
RoundRectPainter(SkColor border_color, int corner_radius);
~RoundRectPainter() override;
diff --git a/chromium/ui/views/style/mac/combobox_background_mac.cc b/chromium/ui/views/style/mac/combobox_background_mac.cc
index d15be0838a9..e9d73b19cf9 100644
--- a/chromium/ui/views/style/mac/combobox_background_mac.cc
+++ b/chromium/ui/views/style/mac/combobox_background_mac.cc
@@ -22,7 +22,7 @@ ComboboxBackgroundMac::~ComboboxBackgroundMac() {}
void ComboboxBackgroundMac::Paint(gfx::Canvas* canvas, View* view) const {
gfx::RectF bounds(view->GetLocalBounds());
- gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, view->bounds());
+ gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, view->width());
// Inset the left side far enough to draw only the arrow button, and inset the
// other three sides by half a pixel so the edge of the background doesn't
diff --git a/chromium/ui/views/style/mac/dialog_button_border_mac.cc b/chromium/ui/views/style/mac/dialog_button_border_mac.cc
deleted file mode 100644
index 2781b1ccb64..00000000000
--- a/chromium/ui/views/style/mac/dialog_button_border_mac.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2015 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/style/mac/dialog_button_border_mac.h"
-
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkDrawLooper.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "ui/gfx/canvas.h"
-#include "ui/native_theme/native_theme_mac.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/custom_button.h"
-#include "ui/views/controls/button/label_button.h"
-
-using ui::NativeThemeMac;
-
-namespace views {
-namespace {
-
-// Default border insets, to provide text padding.
-const int kPaddingX = 19;
-const int kPaddingY = 7;
-
-NativeThemeMac::ButtonBackgroundType PaintTypeFromButton(
- const LabelButton& button) {
- if (!button.enabled() || button.state() == Button::STATE_DISABLED)
- return NativeThemeMac::ButtonBackgroundType::DISABLED;
- if (button.state() == Button::STATE_PRESSED)
- return NativeThemeMac::ButtonBackgroundType::PRESSED;
- if (DialogButtonBorderMac::ShouldRenderDefault(button))
- return NativeThemeMac::ButtonBackgroundType::HIGHLIGHTED;
- return NativeThemeMac::ButtonBackgroundType::NORMAL;
-}
-
-} // namespace
-
-DialogButtonBorderMac::DialogButtonBorderMac() {
- set_insets(gfx::Insets(kPaddingY, kPaddingX, kPaddingY, kPaddingX));
-}
-
-DialogButtonBorderMac::~DialogButtonBorderMac() {}
-
-// static
-bool DialogButtonBorderMac::ShouldRenderDefault(const LabelButton& button) {
- // TODO(tapted): Check whether the Widget is active, and only return true here
- // if it is. Plumbing this requires default buttons to also observe Widget
- // activations to ensure text and background colors are properly invalidated.
- return button.is_default();
-}
-
-void DialogButtonBorderMac::Paint(const View& view, gfx::Canvas* canvas) {
- // Actually, |view| should be a LabelButton as well, but don't rely too much
- // on RTTI.
- DCHECK(CustomButton::AsCustomButton(&view));
- const LabelButton& button = static_cast<const LabelButton&>(view);
-
- ui::NativeThemeMac::PaintStyledGradientButton(
- canvas->sk_canvas(), view.GetLocalBounds(), PaintTypeFromButton(button),
- true, true, button.HasFocus());
-}
-
-gfx::Size DialogButtonBorderMac::GetMinimumSize() const {
- // Overridden by PlatformStyle. Here, just ensure the minimum size is
- // consistent with the padding.
- return gfx::Size(2 * kPaddingX, 2 * kPaddingY);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/style/mac/dialog_button_border_mac.h b/chromium/ui/views/style/mac/dialog_button_border_mac.h
deleted file mode 100644
index b10b09a9b7e..00000000000
--- a/chromium/ui/views/style/mac/dialog_button_border_mac.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2015 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_STYLE_MAC_DIALOG_BUTTON_BORDER_MAC_H_
-#define UI_VIEWS_STYLE_MAC_DIALOG_BUTTON_BORDER_MAC_H_
-
-#include "base/macros.h"
-#include "ui/views/controls/button/label_button_border.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-
-class LabelButton;
-
-// Skia port of the default button style used for dialogs on Chrome Mac.
-// Originally provided by ConstrainedWindowButton, which used Quartz-backed
-// Cocoa drawing routines.
-class VIEWS_EXPORT DialogButtonBorderMac : public LabelButtonBorder {
- public:
- DialogButtonBorderMac();
- ~DialogButtonBorderMac() override;
-
- // Whether the given |button| should get a highlighted background.
- static bool ShouldRenderDefault(const LabelButton& button);
-
- // views::Border:
- void Paint(const View& view, gfx::Canvas* canvas) override;
- gfx::Size GetMinimumSize() const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DialogButtonBorderMac);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_STYLE_MAC_DIALOG_BUTTON_BORDER_MAC_H_
diff --git a/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc b/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc
deleted file mode 100644
index 950697481e1..00000000000
--- a/chromium/ui/views/style/mac/dialog_button_border_mac_unittest.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2015 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/style/mac/dialog_button_border_mac.h"
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/compositor/canvas_painter.h"
-#include "ui/gfx/canvas.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/test/views_test_base.h"
-
-namespace views {
-namespace {
-
-// LabelButton that can optionally provide a custom border.
-class TestLabelButton : public LabelButton {
- public:
- explicit TestLabelButton(const char* text)
- : LabelButton(nullptr, base::ASCIIToUTF16(text)) {}
-
- void SimulateAddToWidget() { OnNativeThemeChanged(nullptr); }
- void set_provide_custom_border(bool value) { provide_custom_border_ = value; }
-
- // LabelButton:
- std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override {
- if (!provide_custom_border_)
- return LabelButton::CreateDefaultBorder();
-
- return base::WrapUnique(new LabelButtonAssetBorder(style()));
- }
-
- private:
- bool provide_custom_border_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(TestLabelButton);
-};
-
-gfx::Size DialogButtonBorderMacSize() {
- const DialogButtonBorderMac template_border;
- return template_border.GetMinimumSize();
-}
-
-// A heuristic that tries to determine whether the border on |view| is a
-// DialogButtonBorderMac by checking its minimum size.
-bool BorderIsDialogButton(const View& view) {
- const Border* border = view.border();
- return border && DialogButtonBorderMacSize() == border->GetMinimumSize();
-}
-
-SkColor TestPaint(View* view) {
- EXPECT_TRUE(view->visible());
- EXPECT_FALSE(view->bounds().IsEmpty());
- const gfx::Point center = view->bounds().CenterPoint();
- gfx::Canvas canvas(view->bounds().size(), 1.0, false /* is_opaque */);
- SkCanvas* sk_canvas = canvas.sk_canvas();
-
- // Read a pixel - it should be blank.
- SkColor initial_pixel;
- SkBitmap bitmap;
- bitmap.allocN32Pixels(1, 1);
- EXPECT_TRUE(sk_canvas->readPixels(&bitmap, center.x(), center.y()));
- initial_pixel = bitmap.getColor(0, 0);
- EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), initial_pixel);
-
- view->Paint(ui::CanvasPainter(&canvas, 1.f).context());
-
- // Ensure save()/restore() calls are balanced.
- EXPECT_EQ(1, sk_canvas->getSaveCount());
-
- // Ensure "something" happened. This assumes the border is a
- // DialogButtonBorderMac, which always modifies the center pixel.
- EXPECT_TRUE(sk_canvas->readPixels(&bitmap, center.x(), center.y()));
- return bitmap.getColor(0, 0);
-}
-
-void TestPaintAllStates(CustomButton* button, bool verify) {
- for (int i = 0; i < Button::STATE_COUNT; ++i) {
- Button::ButtonState state = static_cast<Button::ButtonState>(i);
- SCOPED_TRACE(testing::Message() << "Button::ButtonState: " << state);
- button->SetState(state);
- SkColor color = TestPaint(button);
- if (verify)
- EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), color);
- }
-}
-
-} // namespace
-
-using DialogButtonBorderMacTest = ViewsTestBase;
-
-// Verify that the DialogButtonBorderMac insets are consistent with the
-// minimum size, and they're correctly carried across to the View's preferred
-// size.
-TEST_F(DialogButtonBorderMacTest, DrawMinimumSize) {
- TestLabelButton button("");
- button.SetStyle(Button::STYLE_BUTTON);
- button.SimulateAddToWidget();
-
- EXPECT_TRUE(BorderIsDialogButton(button));
-
- // The border minimum size should be at least the size of the insets.
- const gfx::Size border_min_size = DialogButtonBorderMacSize();
- const gfx::Insets insets = button.GetInsets();
- EXPECT_LE(insets.width(), border_min_size.width());
- EXPECT_LE(insets.height(), border_min_size.height());
-
- // The view preferred size should be at least as big as the border minimum.
- gfx::Size view_preferred_size = button.GetPreferredSize();
- EXPECT_LE(border_min_size.width(), view_preferred_size.width());
- EXPECT_LE(border_min_size.height(), view_preferred_size.height());
-
- // Note that Mac's PlatformStyle specifies a minimum button size, but it
- // shouldn't be larger than the size of the button's label plus border insets.
- // If it was, a Button::SetMinSize() call would be needed here to override it.
-
- button.SizeToPreferredSize();
- EXPECT_EQ(view_preferred_size.width(), button.width());
- EXPECT_EQ(view_preferred_size.height(), button.height());
-
- {
- SCOPED_TRACE("Preferred Size");
- TestPaintAllStates(&button, true);
- }
-
- // The View can ignore the border minimum size. To account for shadows, the
- // border will paint something as small as 4x4.
- {
- SCOPED_TRACE("Minimum Paint Size");
- button.SetSize(gfx::Size(4, 4));
- TestPaintAllStates(&button, true);
- }
-
- // Smaller than that, nothing gets painted, but the paint code should be sane.
- {
- SCOPED_TRACE("Size 1x1");
- button.SetSize(gfx::Size(1, 1));
- TestPaintAllStates(&button, false);
- }
-}
-
-// Test drawing with some text. The usual case.
-TEST_F(DialogButtonBorderMacTest, DrawWithLabel) {
- TestLabelButton button("");
- button.SetStyle(Button::STYLE_BUTTON);
- button.SimulateAddToWidget();
-
- EXPECT_TRUE(BorderIsDialogButton(button));
-
- button.SizeToPreferredSize();
- const gfx::Size no_label_size = button.size();
-
- button.SetText(
- base::ASCIIToUTF16("Label Text That Exceeds the Minimum Button Size"));
- button.SizeToPreferredSize();
-
- // Long label, so the button width should be greater than the empty button.
- EXPECT_LT(no_label_size.width(), button.width());
-
- // The height shouldn't change.
- EXPECT_EQ(no_label_size.height(), button.height());
-
- TestPaintAllStates(&button, true);
-}
-
-// Test that the themed style is not used for STYLE_TEXTBUTTON (the default), or
-// when a custom Border is set, or when a LabelButton subclass provides its own
-// default border.
-TEST_F(DialogButtonBorderMacTest, ChecksButtonStyle) {
- TestLabelButton button("");
- button.SimulateAddToWidget();
-
- // Default style is STYLE_TEXTBUTTON, which doesn't use the themed border.
- EXPECT_FALSE(BorderIsDialogButton(button));
-
- button.SetStyle(Button::STYLE_BUTTON);
- button.SimulateAddToWidget();
- EXPECT_TRUE(BorderIsDialogButton(button));
-
- button.set_provide_custom_border(true);
- button.SimulateAddToWidget();
- EXPECT_FALSE(BorderIsDialogButton(button));
-
- button.set_provide_custom_border(false);
- button.SimulateAddToWidget();
- EXPECT_TRUE(BorderIsDialogButton(button));
-
- // Any call to SetBorder() will immediately prevent themed buttons and adding
- // to a Widget (to pick up a NativeTheme) shouldn't restore them.
- button.SetBorder(Border::NullBorder());
- EXPECT_FALSE(BorderIsDialogButton(button));
- button.SimulateAddToWidget();
- EXPECT_FALSE(BorderIsDialogButton(button));
-}
-
-} // namespace views
diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc
index a4cad6c345c..a9fd9829c9d 100644
--- a/chromium/ui/views/style/platform_style.cc
+++ b/chromium/ui/views/style/platform_style.cc
@@ -38,7 +38,12 @@ const int PlatformStyle::kComboboxNormalArrowPadding = 7;
const int PlatformStyle::kMinLabelButtonWidth = 70;
const int PlatformStyle::kMinLabelButtonHeight = 33;
const bool PlatformStyle::kDefaultLabelButtonHasBoldFont = true;
+const bool PlatformStyle::kDialogDefaultButtonCanBeCancel = true;
const bool PlatformStyle::kTextfieldDragVerticallyDragsToEnd = false;
+const CustomButton::NotifyAction PlatformStyle::kMenuNotifyActivationAction =
+ CustomButton::NOTIFY_ON_RELEASE;
+const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = false;
+const bool PlatformStyle::kUseRipples = true;
// static
gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled,
@@ -49,7 +54,7 @@ gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled,
// static
std::unique_ptr<FocusableBorder> PlatformStyle::CreateComboboxBorder() {
- return base::WrapUnique(new FocusableBorder());
+ return base::MakeUnique<FocusableBorder>();
}
// static
@@ -59,22 +64,8 @@ std::unique_ptr<Background> PlatformStyle::CreateComboboxBackground(
}
// static
-std::unique_ptr<LabelButtonBorder> PlatformStyle::CreateLabelButtonBorder(
- Button::ButtonStyle style) {
- if (!ui::MaterialDesignController::IsModeMaterial() ||
- style != Button::STYLE_TEXTBUTTON) {
- return base::WrapUnique(new LabelButtonAssetBorder(style));
- }
-
- std::unique_ptr<LabelButtonBorder> border(new views::LabelButtonBorder());
- border->set_insets(views::LabelButtonAssetBorder::GetDefaultInsetsForStyle(
- Button::STYLE_TEXTBUTTON));
- return border;
-}
-
-// static
std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
- return base::WrapUnique(new NativeScrollBar(is_horizontal));
+ return base::MakeUnique<NativeScrollBar>(is_horizontal);
}
// static
@@ -84,6 +75,9 @@ SkColor PlatformStyle::TextColorForButton(
return color_by_state[button.state()];
}
+// static
+void PlatformStyle::OnTextfieldKeypressUnhandled() {}
+
#endif // OS_MACOSX
#if !defined(DESKTOP_LINUX) && !defined(OS_MACOSX)
@@ -96,10 +90,6 @@ void PlatformStyle::ApplyLabelButtonTextStyle(
colors[Button::STATE_HOVERED] = kStyleButtonTextColor;
colors[Button::STATE_PRESSED] = kStyleButtonTextColor;
- const ui::NativeTheme* theme = label->GetNativeTheme();
- label->SetBackgroundColor(
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonBackgroundColor));
- label->SetAutoColorReadabilityEnabled(false);
label->SetShadows(gfx::ShadowValues(
1, gfx::ShadowValue(gfx::Vector2d(0, 1), 0, kStyleButtonShadowColor)));
}
diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h
index 8534aa27635..8405cb2009a 100644
--- a/chromium/ui/views/style/platform_style.h
+++ b/chromium/ui/views/style/platform_style.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/views_export.h"
@@ -18,7 +19,6 @@ class Border;
class FocusableBorder;
class Label;
class LabelButton;
-class LabelButtonBorder;
class ScrollBar;
// Cross-platform API for providing platform-specific styling for toolkit-views.
@@ -38,10 +38,23 @@ class VIEWS_EXPORT PlatformStyle {
// Whether dialog-default buttons are given a bold font style.
static const bool kDefaultLabelButtonHasBoldFont;
+ // Whether the default button for a dialog can be the Cancel button.
+ static const bool kDialogDefaultButtonCanBeCancel;
+
// Whether dragging vertically above or below a textfield's bounds selects to
// the left or right end of the text from the cursor, respectively.
static const bool kTextfieldDragVerticallyDragsToEnd;
+ // The menu button's action to show the menu.
+ static const CustomButton::NotifyAction kMenuNotifyActivationAction;
+
+ // Whether selecting a row in a TreeView selects the entire row or only the
+ // label for that row.
+ static const bool kTreeViewSelectionPaintsEntireRow;
+
+ // Whether ripples should be used for visual feedback on control activation.
+ static const bool kUseRipples;
+
// Creates an ImageSkia containing the image to use for the combobox arrow.
// The |is_enabled| argument is true if the control the arrow is for is
// enabled, and false if the control is disabled. The |style| argument is the
@@ -56,11 +69,6 @@ class VIEWS_EXPORT PlatformStyle {
static std::unique_ptr<Background> CreateComboboxBackground(
int shoulder_width);
- // Creates the default label button border for the given |style|. Used when a
- // custom default border is not provided for a particular LabelButton class.
- static std::unique_ptr<LabelButtonBorder> CreateLabelButtonBorder(
- Button::ButtonStyle style);
-
// Creates the default scrollbar for the given orientation.
static std::unique_ptr<ScrollBar> CreateScrollBar(bool is_horizontal);
@@ -78,6 +86,10 @@ class VIEWS_EXPORT PlatformStyle {
static std::unique_ptr<Border> CreateThemedLabelButtonBorder(
LabelButton* button);
+ // Called whenever a textfield keypress is unhandled for any reason. Gives
+ // visual/audio feedback about the unhandled key if platform-appropriate.
+ static void OnTextfieldKeypressUnhandled();
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformStyle);
};
diff --git a/chromium/ui/views/style/platform_style_mac.mm b/chromium/ui/views/style/platform_style_mac.mm
index 5a8d2bd0b63..866bba64424 100644
--- a/chromium/ui/views/style/platform_style_mac.mm
+++ b/chromium/ui/views/style/platform_style_mac.mm
@@ -6,15 +6,16 @@
#include "base/memory/ptr_util.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_utils.h"
#include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/vector_icons.h"
+#include "ui/gfx/vector_icons_public.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/button/label_button_border.h"
#include "ui/views/controls/focusable_rounded_border_mac.h"
#import "ui/views/controls/scrollbar/cocoa_scroll_bar.h"
#include "ui/views/style/mac/combobox_background_mac.h"
-#include "ui/views/style/mac/dialog_button_border_mac.h"
+
+#import <Cocoa/Cocoa.h>
namespace views {
@@ -22,7 +23,13 @@ const int PlatformStyle::kComboboxNormalArrowPadding = 0;
const int PlatformStyle::kMinLabelButtonWidth = 32;
const int PlatformStyle::kMinLabelButtonHeight = 30;
const bool PlatformStyle::kDefaultLabelButtonHasBoldFont = false;
+const bool PlatformStyle::kDialogDefaultButtonCanBeCancel = false;
const bool PlatformStyle::kTextfieldDragVerticallyDragsToEnd = true;
+const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = true;
+const bool PlatformStyle::kUseRipples = false;
+
+const CustomButton::NotifyAction PlatformStyle::kMenuNotifyActivationAction =
+ CustomButton::NOTIFY_ON_PRESS;
// static
gfx::ImageSkia PlatformStyle::CreateComboboxArrow(bool is_enabled,
@@ -48,21 +55,12 @@ std::unique_ptr<FocusableBorder> PlatformStyle::CreateComboboxBorder() {
// static
std::unique_ptr<Background> PlatformStyle::CreateComboboxBackground(
int shoulder_width) {
- return base::WrapUnique(new ComboboxBackgroundMac(shoulder_width));
-}
-
-// static
-std::unique_ptr<LabelButtonBorder> PlatformStyle::CreateLabelButtonBorder(
- Button::ButtonStyle style) {
- if (style == Button::STYLE_BUTTON)
- return base::WrapUnique(new DialogButtonBorderMac());
-
- return base::WrapUnique(new LabelButtonAssetBorder(style));
+ return base::MakeUnique<ComboboxBackgroundMac>(shoulder_width);
}
// static
std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
- return base::WrapUnique(new CocoaScrollBar(is_horizontal));
+ return base::MakeUnique<CocoaScrollBar>(is_horizontal);
}
// static
@@ -70,8 +68,7 @@ SkColor PlatformStyle::TextColorForButton(
const ButtonColorByState& color_by_state,
const LabelButton& button) {
Button::ButtonState state = button.state();
- if (button.style() == Button::STYLE_BUTTON &&
- DialogButtonBorderMac::ShouldRenderDefault(button)) {
+ if (button.style() == Button::STYLE_BUTTON && button.is_default()) {
// For convenience, we currently assume Mac wants the color corresponding to
// the pressed state for default buttons.
state = Button::STATE_PRESSED;
@@ -83,10 +80,13 @@ SkColor PlatformStyle::TextColorForButton(
void PlatformStyle::ApplyLabelButtonTextStyle(
views::Label* label,
ButtonColorByState* color_by_state) {
- const ui::NativeTheme* theme = label->GetNativeTheme();
ButtonColorByState& colors = *color_by_state;
- colors[Button::STATE_PRESSED] =
- theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonHighlightColor);
+ colors[Button::STATE_PRESSED] = SK_ColorWHITE;
+}
+
+// static
+void PlatformStyle::OnTextfieldKeypressUnhandled() {
+ NSBeep();
}
} // namespace views
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index 1e803135964..201e6d04c85 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -237,7 +237,6 @@ class TouchSelectionControllerImpl::EditingHandleView
draw_invisible_(false),
weak_ptr_factory_(this) {
widget_.reset(CreateTouchSelectionPopupWidget(context, this));
- widget_->SetContentsView(this);
aura::Window* window = widget_->GetNativeWindow();
window->SetEventTargeter(std::unique_ptr<ui::EventTargeter>(
@@ -321,6 +320,10 @@ class TouchSelectionControllerImpl::EditingHandleView
}
gfx::Size GetPreferredSize() const override {
+ // This function will be called during widget initialization, i.e. before
+ // SetBoundInScreen has been called. No-op in that case.
+ if (selection_bound_.type() == gfx::SelectionBound::EMPTY)
+ return gfx::Size();
return GetSelectionWidgetBounds(selection_bound_).size();
}
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
index b1a5e36e3dc..e3983dc0459 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -97,7 +97,7 @@ class TouchSelectionControllerImplTest : public ViewsTestBase {
textfield_widget_->SetContentsView(container);
container->AddChildView(textfield_);
- textfield_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
+ textfield_->SetBoundsRect(gfx::Rect(0, 0, 200, 21));
textfield_->set_id(1);
textfield_widget_->Show();
@@ -687,11 +687,6 @@ class TestTouchEditable : public ui::TouchEditable {
NOTREACHED();
return false;
}
- bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator) override {
- NOTREACHED();
- return false;
- }
void ExecuteCommand(int command_id, int event_flags) override {
NOTREACHED();
}
diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
index b506f787de5..b208d5ffb35 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
+++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
@@ -161,10 +161,7 @@ Button* TouchSelectionMenuRunnerViews::Menu::CreateButton(
LabelButton* button = new LabelButton(this, label);
button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight));
button->SetFocusForPlatform();
- const gfx::FontList& font_list =
- ui::ResourceBundle::GetSharedInstance().GetFontList(
- ui::ResourceBundle::SmallFont);
- button->SetFontList(font_list);
+ button->AdjustFontSize(ui::ResourceBundle::kSmallFontDelta);
button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
button->set_tag(tag);
return button;
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index be3bbf5b7ed..a57d82f97db 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -447,7 +447,13 @@ void View::OnEnabledChanged() {
// Transformations -------------------------------------------------------------
gfx::Transform View::GetTransform() const {
- return layer() ? layer()->transform() : gfx::Transform();
+ if (!layer())
+ return gfx::Transform();
+
+ gfx::Transform transform = layer()->transform();
+ gfx::ScrollOffset scroll_offset = layer()->CurrentScrollOffset();
+ transform.Translate(-scroll_offset.x(), -scroll_offset.y());
+ return transform;
}
void View::SetTransform(const gfx::Transform& transform) {
@@ -826,7 +832,7 @@ void View::Paint(const ui::PaintContext& parent_context) {
transform_from_parent.Translate(offset_from_parent.x(),
offset_from_parent.y());
transform_from_parent.PreconcatTransform(GetTransform());
- transform_recorder.Transform(transform_from_parent, size());
+ transform_recorder.Transform(transform_from_parent);
}
// Note that the cache is not aware of the offset of the view
@@ -835,16 +841,8 @@ void View::Paint(const ui::PaintContext& parent_context) {
if (is_invalidated || !paint_cache_.UseCache(context, size())) {
ui::PaintRecorder recorder(context, size(), &paint_cache_);
gfx::Canvas* canvas = recorder.canvas();
-
- // If the View we are about to paint requested the canvas to be flipped, we
- // should change the transform appropriately.
- // The canvas mirroring is undone once the View is done painting so that we
- // don't pass the canvas with the mirrored transform to Views that didn't
- // request the canvas to be flipped.
- if (FlipCanvasOnPaintForRTLUI()) {
- canvas->Translate(gfx::Vector2d(width(), 0));
- canvas->Scale(-1, 1);
- }
+ gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, width(),
+ flip_canvas_on_paint_for_rtl_ui_);
// Delegate painting the contents of the View to the virtual OnPaint method.
OnPaint(canvas);
@@ -1082,6 +1080,10 @@ ViewTargeter* View::GetEffectiveViewTargeter() const {
return view_targeter;
}
+WordLookupClient* View::GetWordLookupClient() {
+ return nullptr;
+}
+
bool View::CanAcceptEvent(const ui::Event& event) {
return IsDrawn();
}
@@ -1091,7 +1093,7 @@ ui::EventTarget* View::GetParentTarget() {
}
std::unique_ptr<ui::EventTargetIterator> View::GetChildIterator() const {
- return base::WrapUnique(new ui::EventTargetIteratorImpl<View>(children_));
+ return base::MakeUnique<ui::EventTargetIteratorImpl<View>>(children_);
}
ui::EventTargeter* View::GetEventTargeter() {
@@ -1109,7 +1111,7 @@ void View::AddAccelerator(const ui::Accelerator& accelerator) {
if (!accelerators_.get())
accelerators_.reset(new std::vector<ui::Accelerator>());
- if (!ContainsValue(*accelerators_.get(), accelerator))
+ if (!base::ContainsValue(*accelerators_.get(), accelerator))
accelerators_->push_back(accelerator);
RegisterPendingAccelerators();
@@ -2081,7 +2083,7 @@ void View::CreateLayer() {
for (int i = 0, count = child_count(); i < count; ++i)
child_at(i)->UpdateChildLayerVisibility(true);
- SetLayer(new ui::Layer());
+ SetLayer(base::MakeUnique<ui::Layer>());
layer()->set_delegate(this);
layer()->set_name(GetClassName());
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index 6b45c6313ba..28171db1da3 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -76,6 +76,7 @@ class LayoutManager;
class NativeViewAccessibility;
class ScrollView;
class Widget;
+class WordLookupClient;
namespace internal {
class PreEventDispatchHandler;
@@ -538,13 +539,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// This method determines whether the gfx::Canvas object passed to
// View::Paint() needs to be transformed such that anything drawn on the
// canvas object during View::Paint() is flipped horizontally.
- //
- // By default, this function returns false (which is the initial value of
- // |flip_canvas_on_paint_for_rtl_ui_|). View subclasses that need to paint on
- // a flipped gfx::Canvas when the UI layout is right-to-left need to call
- // EnableCanvasFlippingForRTLUI().
- bool FlipCanvasOnPaintForRTLUI() const {
- return flip_canvas_on_paint_for_rtl_ui_ ? base::i18n::IsRTL() : false;
+ bool flip_canvas_on_paint_for_rtl_ui() const {
+ return flip_canvas_on_paint_for_rtl_ui_;
}
// Enables or disables flipping of the gfx::Canvas during View::Paint().
@@ -722,6 +718,9 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
ViewTargeter* targeter() const { return targeter_.get(); }
+ // Returns the WordLookupClient associated with this view.
+ virtual WordLookupClient* GetWordLookupClient();
+
// Overridden from ui::EventTarget:
bool CanAcceptEvent(const ui::Event& event) override;
ui::EventTarget* GetParentTarget() override;
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index 38f55bd11bd..e9af12ad5a9 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -526,7 +526,7 @@ TEST_F(ViewTest, PaintEmptyView) {
// Paint "everything".
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
// The empty view has nothing to paint so it doesn't try build a cache, nor do
@@ -548,7 +548,7 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCache) {
gfx::Rect pixel_rect = gfx::Rect(1, 1);
float device_scale_factor = 1.f;
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect));
EXPECT_TRUE(v1->did_paint_);
@@ -564,14 +564,14 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCache) {
list->VisualRectForTesting(item_index));
// If invalidation doesn't intersect v1, we paint with the cache.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect));
EXPECT_FALSE(v1->did_paint_);
v1->Reset();
// If invalidation does intersect v1, we don't paint with the cache.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, v1->bounds()));
EXPECT_TRUE(v1->did_paint_);
@@ -579,7 +579,7 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCache) {
// Moving the view should still use the cache when the invalidation doesn't
// intersect v1.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
v1->SetX(9);
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect));
@@ -596,7 +596,7 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCache) {
// Moving the view should not use the cache when painting without
// invalidation.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
v1->SetX(8);
root_view->Paint(ui::PaintContext(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect),
@@ -626,7 +626,7 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCacheInRTL) {
gfx::Rect pixel_rect = gfx::Rect(1, 1);
float device_scale_factor = 1.f;
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect));
EXPECT_TRUE(v1->did_paint_);
@@ -643,14 +643,14 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCacheInRTL) {
list->VisualRectForTesting(item_index));
// If invalidation doesn't intersect v1, we paint with the cache.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect));
EXPECT_FALSE(v1->did_paint_);
v1->Reset();
// If invalidation does intersect v1, we don't paint with the cache.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, v1->bounds()));
EXPECT_TRUE(v1->did_paint_);
@@ -658,7 +658,7 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCacheInRTL) {
// Moving the view should still use the cache when the invalidation doesn't
// intersect v1.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
v1->SetX(9);
root_view->Paint(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect));
@@ -676,7 +676,7 @@ TEST_F(ViewTest, PaintWithMovedViewUsesCacheInRTL) {
// Moving the view should not use the cache when painting without
// invalidation.
- list = cc::DisplayItemList::Create(pixel_rect, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
v1->SetX(8);
root_view->Paint(ui::PaintContext(
ui::PaintContext(list.get(), device_scale_factor, pixel_rect),
@@ -710,14 +710,14 @@ TEST_F(ViewTest, PaintWithUnknownInvalidation) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(1, 1);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
// With a known invalidation, v1 and v2 are not painted.
EXPECT_FALSE(v1->did_paint_);
@@ -750,14 +750,14 @@ TEST_F(ViewTest, PaintContainsChildren) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(25, 26);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -794,14 +794,14 @@ TEST_F(ViewTest, PaintContainsChildrenInRTL) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(25, 26);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -826,14 +826,14 @@ TEST_F(ViewTest, PaintIntersectsChildren) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(9, 10, 5, 6);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -870,14 +870,14 @@ TEST_F(ViewTest, PaintIntersectsChildrenInRTL) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(2, 10, 5, 6);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -902,14 +902,14 @@ TEST_F(ViewTest, PaintIntersectsChildButNotGrandChild) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(9, 10, 2, 3);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -946,14 +946,14 @@ TEST_F(ViewTest, PaintIntersectsChildButNotGrandChildInRTL) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(2, 10, 2, 3);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -978,14 +978,14 @@ TEST_F(ViewTest, PaintIntersectsNoChildren) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(9, 10, 2, 1);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -1022,14 +1022,14 @@ TEST_F(ViewTest, PaintIntersectsNoChildrenInRTL) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
gfx::Rect paint_area(2, 10, 2, 1);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -1054,7 +1054,7 @@ TEST_F(ViewTest, PaintIntersectsOneChild) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
@@ -1062,7 +1062,7 @@ TEST_F(ViewTest, PaintIntersectsOneChild) {
// Intersects with the second child only.
gfx::Rect paint_area(3, 3, 1, 2);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -1110,7 +1110,7 @@ TEST_F(ViewTest, PaintIntersectsOneChildInRTL) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
@@ -1118,7 +1118,7 @@ TEST_F(ViewTest, PaintIntersectsOneChildInRTL) {
// Intersects with the first child only.
gfx::Rect paint_area(3, 10, 1, 2);
gfx::Rect root_area(root_view->size());
- list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+ list = cc::DisplayItemList::Create(cc::DisplayItemListSettings());
EXPECT_FALSE(v1->did_paint_);
EXPECT_FALSE(v2->did_paint_);
@@ -1155,7 +1155,7 @@ TEST_F(ViewTest, PaintInPromotedToLayer) {
// invalidation.
gfx::Rect first_paint(1, 1);
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
v1->Paint(ui::PaintContext(list.get(), 1.f, first_paint));
v1->Reset();
v2->Reset();
@@ -1164,7 +1164,7 @@ TEST_F(ViewTest, PaintInPromotedToLayer) {
gfx::Rect paint_area(25, 26);
gfx::Rect view_area(root_view->size());
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(view_area, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
// The promoted views are not painted as they are separate paint roots.
root_view->Paint(ui::PaintContext(list.get(), 1.f, paint_area));
@@ -1176,7 +1176,7 @@ TEST_F(ViewTest, PaintInPromotedToLayer) {
gfx::Rect paint_area(1, 1);
gfx::Rect view_area(v1->size());
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(view_area, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
// The |v1| view is painted. If it used its offset incorrect, it would think
// its at (10,11) instead of at (0,0) since it is the paint root.
@@ -1191,7 +1191,7 @@ TEST_F(ViewTest, PaintInPromotedToLayer) {
gfx::Rect paint_area(3, 3, 1, 2);
gfx::Rect view_area(v1->size());
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(view_area, cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
// The |v2| view is painted also. If it used its offset incorrect, it would
// think its at (13,15) instead of at (3,4) since |v1| is the paint root.
@@ -1238,7 +1238,7 @@ TEST_F(ViewTest, PaintLocalBounds) {
EXPECT_EQ(gfx::Rect(0, 1000, 100, 100), v1->GetVisibleBounds());
scoped_refptr<cc::DisplayItemList> list =
- cc::DisplayItemList::Create(gfx::Rect(), cc::DisplayItemListSettings());
+ cc::DisplayItemList::Create(cc::DisplayItemListSettings());
ui::PaintContext context(list.get(), 1.f, gfx::Rect());
v1->Paint(context);
diff --git a/chromium/ui/views/view_unittest_aura.cc b/chromium/ui/views/view_unittest_aura.cc
index b1e7b2fee60..531302ae75b 100644
--- a/chromium/ui/views/view_unittest_aura.cc
+++ b/chromium/ui/views/view_unittest_aura.cc
@@ -122,7 +122,7 @@ TEST_F(ViewAuraTest, RecreateLayersWithWindows) {
{
std::unique_ptr<ui::LayerTreeOwner> cloned_owner(
- wm::RecreateLayers(w1->GetNativeView(), nullptr));
+ wm::RecreateLayers(w1->GetNativeView()));
EXPECT_EQ(w1_layer, cloned_owner->root());
EXPECT_NE(w1_layer, w1->GetNativeView()->layer());
diff --git a/chromium/ui/views/views.gyp b/chromium/ui/views/views.gyp
deleted file mode 100644
index 29964e6f5eb..00000000000
--- a/chromium/ui/views/views.gyp
+++ /dev/null
@@ -1,1056 +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.
-{
- 'variables': {
- 'chromium_code': 1,
- # Sources lists shared with GN build.
- 'views_sources': [
- 'accessibility/native_view_accessibility.cc',
- 'accessibility/native_view_accessibility.h',
- 'accessibility/native_view_accessibility_win.cc',
- 'accessibility/native_view_accessibility_win.h',
- 'accessible_pane_view.cc',
- 'accessible_pane_view.h',
- 'animation/bounds_animator.cc',
- 'animation/bounds_animator.h',
- 'animation/flood_fill_ink_drop_ripple.cc',
- 'animation/flood_fill_ink_drop_ripple.h',
- 'animation/ink_drop.h',
- 'animation/ink_drop_animation_ended_reason.cc',
- 'animation/ink_drop_animation_ended_reason.h',
- 'animation/ink_drop_highlight.cc',
- 'animation/ink_drop_highlight.h',
- 'animation/ink_drop_highlight_observer.h',
- 'animation/ink_drop_host.h',
- 'animation/ink_drop_host_view.cc',
- 'animation/ink_drop_host_view.h',
- 'animation/ink_drop_impl.cc',
- 'animation/ink_drop_impl.h',
- 'animation/ink_drop_painted_layer_delegates.cc',
- 'animation/ink_drop_painted_layer_delegates.h',
- 'animation/ink_drop_ripple.cc',
- 'animation/ink_drop_ripple.h',
- 'animation/ink_drop_ripple_observer.h',
- 'animation/ink_drop_state.cc',
- 'animation/ink_drop_state.h',
- 'animation/ink_drop_stub.h',
- 'animation/ink_drop_stub.cc',
- 'animation/scroll_animator.cc',
- 'animation/scroll_animator.h',
- 'animation/square_ink_drop_ripple.cc',
- 'animation/square_ink_drop_ripple.h',
- 'background.cc',
- 'background.h',
- 'border.cc',
- 'border.h',
- 'bubble/bubble_border.cc',
- 'bubble/bubble_border.h',
- 'bubble/bubble_dialog_delegate.cc',
- 'bubble/bubble_dialog_delegate.h',
- 'bubble/bubble_frame_view.cc',
- 'bubble/bubble_frame_view.h',
- 'button_drag_utils.cc',
- 'button_drag_utils.h',
- 'cocoa/bridged_content_view.h',
- 'cocoa/bridged_content_view.mm',
- 'cocoa/bridged_native_widget.h',
- 'cocoa/bridged_native_widget.mm',
- 'cocoa/bridged_native_widget_owner.h',
- 'cocoa/drag_drop_client_mac.h',
- 'cocoa/drag_drop_client_mac.mm',
- 'cocoa/cocoa_mouse_capture.h',
- 'cocoa/cocoa_mouse_capture.mm',
- 'cocoa/cocoa_mouse_capture_delegate.h',
- 'cocoa/cocoa_window_move_loop.h',
- 'cocoa/cocoa_window_move_loop.mm',
- 'cocoa/native_widget_mac_nswindow.h',
- 'cocoa/native_widget_mac_nswindow.mm',
- 'cocoa/tooltip_manager_mac.h',
- 'cocoa/tooltip_manager_mac.mm',
- 'cocoa/views_nswindow_delegate.h',
- 'cocoa/views_nswindow_delegate.mm',
- 'cocoa/views_scrollbar_bridge.h',
- 'cocoa/views_scrollbar_bridge.mm',
- 'cocoa/widget_owner_nswindow_adapter.h',
- 'cocoa/widget_owner_nswindow_adapter.mm',
- 'color_chooser/color_chooser_listener.h',
- 'color_chooser/color_chooser_view.cc',
- 'color_chooser/color_chooser_view.h',
- 'context_menu_controller.h',
- 'controls/button/blue_button.cc',
- 'controls/button/blue_button.h',
- 'controls/button/button.cc',
- 'controls/button/button.h',
- 'controls/button/checkbox.cc',
- 'controls/button/checkbox.h',
- 'controls/button/custom_button.cc',
- 'controls/button/custom_button.h',
- 'controls/button/image_button.cc',
- 'controls/button/image_button.h',
- 'controls/button/label_button.cc',
- 'controls/button/label_button.h',
- 'controls/button/label_button_border.cc',
- 'controls/button/label_button_border.h',
- 'controls/button/md_text_button.cc',
- 'controls/button/md_text_button.h',
- 'controls/button/menu_button.cc',
- 'controls/button/menu_button.h',
- 'controls/button/menu_button_listener.h',
- 'controls/button/radio_button.cc',
- 'controls/button/radio_button.h',
- 'controls/combobox/combobox.cc',
- 'controls/combobox/combobox.h',
- 'controls/combobox/combobox_listener.h',
- 'controls/focusable_border.cc',
- 'controls/focusable_border.h',
- 'controls/focusable_rounded_border_mac.cc',
- 'controls/focusable_rounded_border_mac.h',
- 'controls/glow_hover_controller.cc',
- 'controls/glow_hover_controller.h',
- 'controls/image_view.cc',
- 'controls/image_view.h',
- 'controls/label.cc',
- 'controls/label.h',
- 'controls/link.cc',
- 'controls/link.h',
- 'controls/link_listener.h',
- 'controls/menu/display_change_listener_mac.cc',
- 'controls/menu/menu_config.cc',
- 'controls/menu/menu_config.h',
- 'controls/menu/menu_config_chromeos.cc',
- 'controls/menu/menu_config_linux.cc',
- 'controls/menu/menu_config_mac.mm',
- 'controls/menu/menu_config_win.cc',
- 'controls/menu/menu_controller.cc',
- 'controls/menu/menu_controller.h',
- 'controls/menu/menu_controller_delegate.h',
- 'controls/menu/menu_delegate.cc',
- 'controls/menu/menu_delegate.h',
- 'controls/menu/menu_host.cc',
- 'controls/menu/menu_host.h',
- 'controls/menu/menu_host_root_view.cc',
- 'controls/menu/menu_host_root_view.h',
- 'controls/menu/menu_image_util.cc',
- 'controls/menu/menu_image_util.h',
- 'controls/menu/menu_insertion_delegate_win.h',
- 'controls/menu/menu_item_view.cc',
- 'controls/menu/menu_item_view.h',
- 'controls/menu/menu_listener.cc',
- 'controls/menu/menu_listener.h',
- 'controls/menu/menu_message_loop.h',
- 'controls/menu/menu_message_loop_mac.cc',
- 'controls/menu/menu_message_loop_mac.h',
- 'controls/menu/menu_model_adapter.cc',
- 'controls/menu/menu_model_adapter.h',
- 'controls/menu/menu_runner.cc',
- 'controls/menu/menu_runner.h',
- 'controls/menu/menu_runner_handler.h',
- 'controls/menu/menu_runner_impl.cc',
- 'controls/menu/menu_runner_impl.h',
- 'controls/menu/menu_runner_impl_adapter.cc',
- 'controls/menu/menu_runner_impl_adapter.h',
- 'controls/menu/menu_runner_impl_cocoa.h',
- 'controls/menu/menu_runner_impl_cocoa.mm',
- 'controls/menu/menu_runner_impl_interface.h',
- 'controls/menu/menu_scroll_view_container.cc',
- 'controls/menu/menu_scroll_view_container.h',
- 'controls/menu/menu_separator.h',
- 'controls/menu/menu_separator_views.cc',
- 'controls/menu/menu_separator_win.cc',
- 'controls/menu/menu_types.h',
- 'controls/menu/native_menu_win.cc',
- 'controls/menu/native_menu_win.h',
- 'controls/menu/submenu_view.cc',
- 'controls/menu/submenu_view.h',
- 'controls/message_box_view.cc',
- 'controls/message_box_view.h',
- 'controls/native/native_view_host.cc',
- 'controls/native/native_view_host.h',
- 'controls/native/native_view_host_mac.h',
- 'controls/native/native_view_host_mac.mm',
- 'controls/prefix_delegate.h',
- 'controls/prefix_selector.cc',
- 'controls/prefix_selector.h',
- 'controls/progress_bar.cc',
- 'controls/progress_bar.h',
- 'controls/resize_area.cc',
- 'controls/resize_area.h',
- 'controls/resize_area_delegate.h',
- 'controls/scroll_view.cc',
- 'controls/scroll_view.h',
- 'controls/scrollbar/base_scroll_bar.cc',
- 'controls/scrollbar/base_scroll_bar.h',
- 'controls/scrollbar/base_scroll_bar_button.cc',
- 'controls/scrollbar/base_scroll_bar_button.h',
- 'controls/scrollbar/base_scroll_bar_thumb.cc',
- 'controls/scrollbar/base_scroll_bar_thumb.h',
- 'controls/scrollbar/cocoa_scroll_bar.h',
- 'controls/scrollbar/cocoa_scroll_bar.mm',
- 'controls/scrollbar/native_scroll_bar.cc',
- 'controls/scrollbar/native_scroll_bar.h',
- 'controls/scrollbar/native_scroll_bar_views.cc',
- 'controls/scrollbar/native_scroll_bar_views.h',
- 'controls/scrollbar/native_scroll_bar_wrapper.h',
- 'controls/scrollbar/overlay_scroll_bar.cc',
- 'controls/scrollbar/overlay_scroll_bar.h',
- 'controls/scrollbar/scroll_bar.cc',
- 'controls/scrollbar/scroll_bar.h',
- 'controls/separator.cc',
- 'controls/separator.h',
- 'controls/single_split_view.cc',
- 'controls/single_split_view.h',
- 'controls/single_split_view_listener.h',
- 'controls/slide_out_view.cc',
- 'controls/slide_out_view.h',
- 'controls/slider.cc',
- 'controls/slider.h',
- 'controls/styled_label.cc',
- 'controls/styled_label.h',
- 'controls/styled_label_listener.h',
- 'controls/tabbed_pane/tabbed_pane.cc',
- 'controls/tabbed_pane/tabbed_pane.h',
- 'controls/tabbed_pane/tabbed_pane_listener.h',
- 'controls/table/table_header.cc',
- 'controls/table/table_header.h',
- 'controls/table/table_utils.cc',
- 'controls/table/table_utils.h',
- 'controls/table/table_view.cc',
- 'controls/table/table_view.h',
- 'controls/table/table_view_observer.h',
- 'controls/table/table_view_row_background_painter.h',
- 'controls/textfield/textfield.cc',
- 'controls/textfield/textfield.h',
- 'controls/textfield/textfield_controller.cc',
- 'controls/textfield/textfield_controller.h',
- 'controls/textfield/textfield_model.cc',
- 'controls/textfield/textfield_model.h',
- 'controls/throbber.cc',
- 'controls/throbber.h',
- 'controls/tree/tree_view.cc',
- 'controls/tree/tree_view.h',
- 'controls/tree/tree_view_controller.cc',
- 'controls/tree/tree_view_controller.h',
- 'debug_utils.cc',
- 'debug_utils.h',
- 'drag_controller.h',
- 'drag_utils.cc',
- 'drag_utils.h',
- 'drag_utils_mac.mm',
- 'event_monitor.h',
- 'event_monitor_mac.h',
- 'event_monitor_mac.mm',
- 'focus/external_focus_tracker.cc',
- 'focus/external_focus_tracker.h',
- 'focus/focus_manager.cc',
- 'focus/focus_manager.h',
- 'focus/focus_manager_delegate.h',
- 'focus/focus_manager_factory.cc',
- 'focus/focus_manager_factory.h',
- 'focus/focus_search.cc',
- 'focus/focus_search.h',
- 'focus/view_storage.cc',
- 'focus/view_storage.h',
- 'focus/widget_focus_manager.cc',
- 'focus/widget_focus_manager.h',
- 'layout/box_layout.cc',
- 'layout/box_layout.h',
- 'layout/fill_layout.cc',
- 'layout/fill_layout.h',
- 'layout/grid_layout.cc',
- 'layout/grid_layout.h',
- 'layout/layout_constants.h',
- 'layout/layout_manager.cc',
- 'layout/layout_manager.h',
- 'linux_ui/linux_ui.cc',
- 'linux_ui/linux_ui.h',
- 'linux_ui/status_icon_linux.cc',
- 'linux_ui/status_icon_linux.h',
- 'linux_ui/window_button_order_observer.h',
- 'linux_ui/window_button_order_provider.cc',
- 'masked_targeter_delegate.cc',
- 'masked_targeter_delegate.h',
- 'metrics.cc',
- 'metrics.h',
- 'metrics_mac.cc',
- 'mouse_constants.h',
- 'mouse_watcher.cc',
- 'mouse_watcher.h',
- 'mouse_watcher_view_host.cc',
- 'mouse_watcher_view_host.h',
- 'native_cursor.h',
- 'native_cursor_mac.mm',
- 'native_theme_delegate.h',
- 'painter.cc',
- 'painter.h',
- 'pointer_watcher.h',
- 'rect_based_targeting_utils.cc',
- 'rect_based_targeting_utils.h',
- 'repeat_controller.cc',
- 'repeat_controller.h',
- 'round_rect_painter.cc',
- 'round_rect_painter.h',
- 'shadow_border.cc',
- 'shadow_border.h',
- 'style/mac/combobox_background_mac.cc',
- 'style/mac/combobox_background_mac.h',
- 'style/mac/dialog_button_border_mac.cc',
- 'style/mac/dialog_button_border_mac.h',
- 'style/platform_style.cc',
- 'style/platform_style.h',
- 'style/platform_style_mac.mm',
- 'view.cc',
- 'view.h',
- 'view_constants.cc',
- 'view_constants.h',
- 'view_model.cc',
- 'view_model.h',
- 'view_model_utils.cc',
- 'view_model_utils.h',
- 'view_targeter.cc',
- 'view_targeter.h',
- 'view_targeter_delegate.cc',
- 'view_targeter_delegate.h',
- 'views_delegate.cc',
- 'views_delegate.h',
- 'views_export.h',
- 'views_exports.cc',
- 'views_switches.cc',
- 'views_switches.h',
- 'views_touch_selection_controller_factory.h',
- 'views_touch_selection_controller_factory_mac.cc',
- 'widget/drop_helper.cc',
- 'widget/drop_helper.h',
- 'widget/monitor_win.cc',
- 'widget/monitor_win.h',
- 'widget/native_widget.h',
- 'widget/native_widget_delegate.h',
- 'widget/native_widget_mac.h',
- 'widget/native_widget_mac.mm',
- 'widget/native_widget_private.h',
- 'widget/root_view.cc',
- 'widget/root_view.h',
- 'widget/root_view_targeter.cc',
- 'widget/root_view_targeter.h',
- 'widget/tooltip_manager.cc',
- 'widget/tooltip_manager.h',
- 'widget/widget.cc',
- 'widget/widget.h',
- 'widget/widget_aura_utils.cc',
- 'widget/widget_aura_utils.h',
- 'widget/widget_delegate.cc',
- 'widget/widget_delegate.h',
- 'widget/widget_deletion_observer.cc',
- 'widget/widget_deletion_observer.h',
- 'widget/widget_observer.h',
- 'widget/widget_removals_observer.h',
- 'window/client_view.cc',
- 'window/client_view.h',
- 'window/custom_frame_view.cc',
- 'window/custom_frame_view.h',
- 'window/dialog_client_view.cc',
- 'window/dialog_client_view.h',
- 'window/dialog_delegate.cc',
- 'window/dialog_delegate.h',
- 'window/frame_background.cc',
- 'window/frame_background.h',
- 'window/frame_buttons.h',
- 'window/native_frame_view.cc',
- 'window/native_frame_view.h',
- 'window/non_client_view.cc',
- 'window/non_client_view.h',
- 'window/window_button_order_provider.cc',
- 'window/window_button_order_provider.h',
- 'window/window_resources.h',
- 'window/window_shape.cc',
- 'window/window_shape.h',
- ],
- 'views_win_sources': [
- 'widget/widget_hwnd_utils.cc',
- 'widget/widget_hwnd_utils.h',
- 'win/fullscreen_handler.cc',
- 'win/fullscreen_handler.h',
- 'win/hwnd_message_handler.cc',
- 'win/hwnd_message_handler.h',
- 'win/hwnd_message_handler_delegate.h',
- 'win/hwnd_util.h',
- 'win/hwnd_util_aurawin.cc',
- 'win/scoped_fullscreen_visibility.cc',
- 'win/scoped_fullscreen_visibility.h',
- 'win/windows_session_change_observer.cc',
- 'win/windows_session_change_observer.h',
- ],
- 'views_aura_sources': [
- 'accessibility/ax_aura_obj_cache.cc',
- 'accessibility/ax_aura_obj_cache.h',
- 'accessibility/ax_view_obj_wrapper.cc',
- 'accessibility/ax_view_obj_wrapper.h',
- 'accessibility/ax_widget_obj_wrapper.cc',
- 'accessibility/ax_widget_obj_wrapper.h',
- 'accessibility/ax_window_obj_wrapper.cc',
- 'accessibility/ax_window_obj_wrapper.h',
- 'bubble/bubble_window_targeter.cc',
- 'bubble/bubble_window_targeter.h',
- 'bubble/tray_bubble_view.cc',
- 'bubble/tray_bubble_view.h',
- 'controls/menu/display_change_listener_aura.cc',
- 'controls/menu/menu_key_event_handler.cc',
- 'controls/menu/menu_key_event_handler.h',
- 'controls/menu/menu_message_loop_aura.cc',
- 'controls/menu/menu_message_loop_aura.h',
- 'controls/native/native_view_host_aura.cc',
- 'controls/native/native_view_host_aura.h',
- 'corewm/cursor_height_provider_win.cc',
- 'corewm/cursor_height_provider_win.h',
- 'corewm/tooltip.h',
- 'corewm/tooltip_aura.cc',
- 'corewm/tooltip_aura.h',
- 'corewm/tooltip_controller.cc',
- 'corewm/tooltip_controller.h',
- 'corewm/tooltip_win.cc',
- 'corewm/tooltip_win.h',
- 'drag_utils_aura.cc',
- 'event_monitor_aura.cc',
- 'event_monitor_aura.h',
- 'metrics_aura.cc',
- 'native_cursor_aura.cc',
- 'touchui/touch_selection_controller_impl.cc',
- 'touchui/touch_selection_controller_impl.h',
- 'touchui/touch_selection_menu_runner_views.cc',
- 'touchui/touch_selection_menu_runner_views.h',
- 'view_constants_aura.cc',
- 'view_constants_aura.h',
- 'views_touch_selection_controller_factory_aura.cc',
- 'widget/native_widget_aura.cc',
- 'widget/native_widget_aura.h',
- 'widget/tooltip_manager_aura.cc',
- 'widget/tooltip_manager_aura.h',
- 'widget/window_reorderer.cc',
- 'widget/window_reorderer.h',
- ],
- 'views_desktop_aura_sources': [
- 'widget/desktop_aura/desktop_capture_client.cc',
- 'widget/desktop_aura/desktop_capture_client.h',
- 'widget/desktop_aura/desktop_cursor_loader_updater.h',
- 'widget/desktop_aura/desktop_drop_target_win.cc',
- 'widget/desktop_aura/desktop_drop_target_win.h',
- 'widget/desktop_aura/desktop_event_client.cc',
- 'widget/desktop_aura/desktop_event_client.h',
- 'widget/desktop_aura/desktop_focus_rules.cc',
- 'widget/desktop_aura/desktop_focus_rules.h',
- 'widget/desktop_aura/desktop_native_cursor_manager.cc',
- 'widget/desktop_aura/desktop_native_cursor_manager.h',
- 'widget/desktop_aura/desktop_native_widget_aura.cc',
- 'widget/desktop_aura/desktop_native_widget_aura.h',
- 'widget/desktop_aura/desktop_screen.h',
- 'widget/desktop_aura/desktop_screen_position_client.cc',
- 'widget/desktop_aura/desktop_screen_position_client.h',
- 'widget/desktop_aura/desktop_window_tree_host.h',
- ],
- 'views_desktop_aura_linux_sources': [
- 'style/platform_style_linux.cc',
- 'widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc',
- 'widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h',
- ],
- 'views_desktop_aura_x11_sources': [
- 'accessibility/native_view_accessibility_auralinux.cc',
- 'accessibility/native_view_accessibility_auralinux.h',
- 'widget/desktop_aura/desktop_drag_drop_client_aurax11.cc',
- 'widget/desktop_aura/desktop_drag_drop_client_aurax11.h',
- 'widget/desktop_aura/desktop_screen_x11.cc',
- 'widget/desktop_aura/desktop_screen_x11.h',
- 'widget/desktop_aura/desktop_window_tree_host_x11.cc',
- 'widget/desktop_aura/desktop_window_tree_host_x11.h',
- 'widget/desktop_aura/x11_desktop_handler.cc',
- 'widget/desktop_aura/x11_desktop_handler.h',
- 'widget/desktop_aura/x11_desktop_window_move_client.cc',
- '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_pointer_grab.cc',
- 'widget/desktop_aura/x11_pointer_grab.h',
- 'widget/desktop_aura/x11_topmost_window_finder.cc',
- 'widget/desktop_aura/x11_topmost_window_finder.h',
- 'widget/desktop_aura/x11_whole_screen_move_loop.cc',
- 'widget/desktop_aura/x11_whole_screen_move_loop.h',
- 'widget/desktop_aura/x11_window_event_filter.cc',
- 'widget/desktop_aura/x11_window_event_filter.h',
- ],
- 'views_desktop_aura_win_sources': [
- 'widget/desktop_aura/desktop_cursor_loader_updater_aurawin.cc',
- 'widget/desktop_aura/desktop_drag_drop_client_win.cc',
- 'widget/desktop_aura/desktop_drag_drop_client_win.h',
- 'widget/desktop_aura/desktop_screen_win.cc',
- 'widget/desktop_aura/desktop_screen_win.h',
- 'widget/desktop_aura/desktop_window_tree_host_win.cc',
- 'widget/desktop_aura/desktop_window_tree_host_win.h',
- ],
- 'views_desktop_aura_ozone_sources': [
- 'widget/desktop_aura/desktop_factory_ozone.cc',
- 'widget/desktop_aura/desktop_factory_ozone.h',
- 'widget/desktop_aura/desktop_screen_ozone.cc',
- 'widget/desktop_aura/desktop_window_tree_host_ozone.cc',
- ],
- 'views_test_support_sources': [
- 'animation/test/flood_fill_ink_drop_ripple_test_api.cc',
- 'animation/test/flood_fill_ink_drop_ripple_test_api.h',
- 'animation/test/ink_drop_highlight_test_api.cc',
- 'animation/test/ink_drop_highlight_test_api.h',
- 'animation/test/ink_drop_host_view_test_api.cc',
- 'animation/test/ink_drop_host_view_test_api.h',
- 'animation/test/ink_drop_impl_test_api.cc',
- 'animation/test/ink_drop_impl_test_api.h',
- 'animation/test/ink_drop_ripple_test_api.cc',
- 'animation/test/ink_drop_ripple_test_api.h',
- 'animation/test/ink_drop_utils.cc',
- 'animation/test/square_ink_drop_ripple_test_api.cc',
- 'animation/test/square_ink_drop_ripple_test_api.h',
- 'animation/test/test_ink_drop.cc',
- 'animation/test/test_ink_drop.h',
- 'animation/test/test_ink_drop_animation_observer_helper.h',
- 'animation/test/test_ink_drop_highlight_observer.cc',
- 'animation/test/test_ink_drop_highlight_observer.h',
- 'animation/test/test_ink_drop_host.cc',
- 'animation/test/test_ink_drop_host.h',
- 'animation/test/test_ink_drop_ripple_observer.cc',
- 'animation/test/test_ink_drop_ripple_observer.h',
- 'controls/textfield/textfield_test_api.cc',
- 'controls/textfield/textfield_test_api.h',
- 'test/capture_tracking_view.cc',
- 'test/capture_tracking_view.h',
- 'test/combobox_test_api.cc',
- 'test/combobox_test_api.h',
- 'test/desktop_test_views_delegate.h',
- 'test/desktop_test_views_delegate_mac.mm',
- 'test/event_generator_delegate_mac.h',
- 'test/event_generator_delegate_mac.mm',
- 'test/focus_manager_test.cc',
- 'test/focus_manager_test.h',
- 'test/menu_runner_test_api.cc',
- 'test/menu_runner_test_api.h',
- 'test/menu_test_utils.cc',
- 'test/menu_test_utils.h',
- 'test/native_widget_factory.cc',
- 'test/native_widget_factory.h',
- 'test/scoped_views_test_helper.cc',
- 'test/scoped_views_test_helper.h',
- 'test/slider_test_api.cc',
- 'test/slider_test_api.h',
- 'test/test_views.cc',
- 'test/test_views.h',
- 'test/test_views_delegate.h',
- 'test/test_views_delegate_mac.mm',
- 'test/test_widget_observer.cc',
- 'test/test_widget_observer.h',
- 'test/views_test_base.cc',
- 'test/views_test_base.h',
- 'test/views_test_helper.cc',
- 'test/views_test_helper.h',
- 'test/views_test_helper_mac.h',
- 'test/views_test_helper_mac.mm',
- 'test/widget_test.cc',
- 'test/widget_test.h',
- 'test/widget_test_mac.mm',
- 'test/x11_property_change_waiter.cc',
- 'test/x11_property_change_waiter.h',
- 'views_test_suite.cc',
- 'views_test_suite.h',
- ],
- 'views_test_support_aura_sources': [
- 'corewm/tooltip_controller_test_helper.cc',
- 'corewm/tooltip_controller_test_helper.h',
- 'test/desktop_test_views_delegate_aura.cc',
- 'test/test_views_delegate_aura.cc',
- 'test/views_test_helper_aura.cc',
- 'test/views_test_helper_aura.h',
- 'test/widget_test_aura.cc',
- ],
- 'views_test_support_desktop_aura_x11_sources': [
- 'test/desktop_screen_x11_test_api.cc',
- 'test/desktop_screen_x11_test_api.h',
- 'test/ui_controls_factory_desktop_aurax11.cc',
- 'test/ui_controls_factory_desktop_aurax11.h',
- ],
- 'views_unittests_sources': [
- 'accessibility/native_view_accessibility_unittest.cc',
- 'accessibility/native_view_accessibility_win_unittest.cc',
- 'accessible_pane_view_unittest.cc',
- 'animation/bounds_animator_unittest.cc',
- 'animation/flood_fill_ink_drop_ripple_unittest.cc',
- 'animation/ink_drop_highlight_unittest.cc',
- 'animation/ink_drop_host_view_unittest.cc',
- 'animation/ink_drop_impl_unittest.cc',
- 'animation/ink_drop_ripple_unittest.cc',
- 'animation/ink_drop_unittest.cc',
- 'animation/square_ink_drop_ripple_unittest.cc',
- 'border_unittest.cc',
- 'bubble/bubble_border_unittest.cc',
- 'bubble/bubble_dialog_delegate_unittest.cc',
- 'bubble/bubble_frame_view_unittest.cc',
- 'bubble/bubble_window_targeter_unittest.cc',
- 'cocoa/bridged_native_widget_unittest.mm',
- 'cocoa/cocoa_mouse_capture_unittest.mm',
- 'cocoa/drag_drop_client_mac_unittest.mm',
- 'controls/button/blue_button_unittest.cc',
- 'controls/button/custom_button_unittest.cc',
- 'controls/button/image_button_unittest.cc',
- 'controls/button/label_button_unittest.cc',
- 'controls/button/menu_button_unittest.cc',
- 'controls/combobox/combobox_unittest.cc',
- 'controls/label_unittest.cc',
- 'controls/menu/menu_controller_unittest.cc',
- 'controls/menu/menu_item_view_unittest.cc',
- 'controls/menu/menu_model_adapter_unittest.cc',
- 'controls/menu/menu_runner_cocoa_unittest.mm',
- 'controls/menu/menu_runner_unittest.cc',
- 'controls/native/native_view_host_mac_unittest.mm',
- 'controls/native/native_view_host_test_base.cc',
- 'controls/native/native_view_host_test_base.h',
- 'controls/native/native_view_host_unittest.cc',
- 'controls/prefix_selector_unittest.cc',
- 'controls/progress_bar_unittest.cc',
- 'controls/scroll_view_unittest.cc',
- 'controls/scrollbar/scrollbar_unittest.cc',
- 'controls/single_split_view_unittest.cc',
- 'controls/slider_unittest.cc',
- 'controls/styled_label_unittest.cc',
- 'controls/tabbed_pane/tabbed_pane_unittest.cc',
- 'controls/table/table_utils_unittest.cc',
- 'controls/table/table_view_unittest.cc',
- 'controls/table/test_table_model.cc',
- 'controls/table/test_table_model.h',
- 'controls/textfield/textfield_model_unittest.cc',
- 'controls/textfield/textfield_unittest.cc',
- 'controls/tree/tree_view_unittest.cc',
- 'event_monitor_unittest.cc',
- 'focus/focus_manager_unittest.cc',
- 'focus/focus_traversal_unittest.cc',
- 'layout/box_layout_unittest.cc',
- 'layout/grid_layout_unittest.cc',
- 'rect_based_targeting_utils_unittest.cc',
- 'run_all_unittests_main.cc',
- 'style/mac/dialog_button_border_mac_unittest.cc',
- 'view_model_unittest.cc',
- 'view_model_utils_unittest.cc',
- 'view_targeter_unittest.cc',
- 'view_unittest.cc',
- 'widget/native_widget_mac_accessibility_unittest.mm',
- 'widget/native_widget_mac_unittest.mm',
- 'widget/native_widget_unittest.cc',
- 'widget/root_view_unittest.cc',
- 'widget/widget_unittest.cc',
- 'widget/window_reorderer_unittest.cc',
- 'window/custom_frame_view_unittest.cc',
- 'window/dialog_client_view_unittest.cc',
- 'window/dialog_delegate_unittest.cc',
- ],
- 'views_unittests_desktop_sources': [
- 'widget/desktop_widget_unittest.cc',
- ],
- 'views_unittests_aura_sources': [
- 'accessibility/ax_aura_obj_cache_unittest.cc',
- 'controls/native/native_view_host_aura_unittest.cc',
- 'corewm/tooltip_controller_unittest.cc',
- 'touchui/touch_selection_controller_impl_unittest.cc',
- 'touchui/touch_selection_menu_runner_views_unittest.cc',
- 'view_unittest_aura.cc',
- 'widget/native_widget_aura_unittest.cc',
- ],
- 'views_unittests_desktop_aura_sources': [
- 'widget/desktop_aura/desktop_focus_rules_unittest.cc',
- 'widget/desktop_aura/desktop_native_widget_aura_unittest.cc',
- ],
- 'views_unittests_desktop_aurax11_sources': [
- 'widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc',
- 'widget/desktop_aura/desktop_screen_x11_unittest.cc',
- 'widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc',
- ],
- },
- 'targets': [
- {
- # GN version: //ui/views
- 'target_name': 'views',
- 'type': '<(component)',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/base.gyp:base_i18n',
- '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '../../skia/skia.gyp:skia',
- '../../third_party/icu/icu.gyp:icui18n',
- '../../third_party/icu/icu.gyp:icuuc',
- '../../url/url.gyp:url_lib',
- '../accessibility/accessibility.gyp:accessibility',
- '../accessibility/accessibility.gyp:ax_gen',
- '../base/ime/ui_base_ime.gyp:ui_base_ime',
- '../base/ui_base.gyp:ui_base',
- '../compositor/compositor.gyp:compositor',
- '../display/display.gyp:display',
- '../events/events.gyp:events',
- '../events/events.gyp:events_base',
- '../events/platform/events_platform.gyp:events_platform',
- '../gfx/gfx.gyp:gfx',
- '../gfx/gfx.gyp:gfx_geometry',
- '../gfx/gfx.gyp:gfx_range',
- '../gfx/gfx.gyp:gfx_vector_icons',
- '../native_theme/native_theme.gyp:native_theme',
- '../resources/ui_resources.gyp:ui_resources',
- '../strings/ui_strings.gyp:ui_strings',
- 'resources/views_resources.gyp:views_resources',
- ],
- 'all_dependent_settings': {
- 'defines': [
- 'TOOLKIT_VIEWS=1',
- ],
- },
- 'export_dependent_settings': [
- '../accessibility/accessibility.gyp:ax_gen',
- 'resources/views_resources.gyp:views_resources',
- ],
- 'defines': [
- 'VIEWS_IMPLEMENTATION',
- ],
- 'sources': [
- '<@(views_sources)',
- ],
- 'conditions': [
- ['use_aura==0', {
- 'sources!': [
- 'bubble/tray_bubble_view.cc',
- 'bubble/tray_bubble_view.h',
- ],
- }],
- ['chromeos==0 and use_x11==1', {
- 'dependencies': [
- '../display/display.gyp:display_util',
- ],
- }],
- ['OS=="linux" and chromeos==0 and use_ozone==0', {
- 'dependencies': [
- '../../build/linux/system.gyp:atk',
- ],
- }],
- ['OS=="linux" and chromeos==0', {
- 'dependencies': [
- '../shell_dialogs/shell_dialogs.gyp:shell_dialogs',
- ],
- 'sources!': [
- 'window/window_button_order_provider.cc',
- ],
- }, { # OS=="linux" and chromeos==0
- 'sources/': [
- ['exclude', 'linux_ui'],
- ],
- 'sources!': [
- 'controls/menu/menu_config_linux.cc',
- ],
- }],
- ['OS=="win"', {
- 'sources': [
- '<@(views_win_sources)',
- ],
- 'dependencies': [
- # For accessibility
- '../../third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
- ],
- 'include_dirs': [
- '../../third_party/wtl/include',
- ],
- 'link_settings': {
- 'libraries': [
- '-limm32.lib',
- '-loleacc.lib',
- '-lwtsapi32.lib',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'DelayLoadDLLs': [
- 'user32.dll',
- ],
- },
- },
- },
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- 'msvs_disabled_warnings': [ 4267, ],
- }],
- ['use_ozone==1', {
- 'dependencies': [
- '../ozone/ozone.gyp:ozone',
- ],
- }],
- ['use_x11==1', {
- 'dependencies': [
- '../../build/linux/system.gyp:x11',
- '../../build/linux/system.gyp:xrandr',
- '../events/devices/events_devices.gyp:events_devices',
- '../events/devices/x11/events_devices_x11.gyp:events_devices_x11',
- '../events/keycodes/events_keycodes.gyp:keycodes_x11',
- '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
- '../gfx/x/gfx_x11.gyp:gfx_x11',
- ],
- }],
- ['use_aura==1', {
- 'sources': [
- '<@(views_aura_sources)',
- ],
- 'dependencies': [
- '../aura/aura.gyp:aura',
- '../touch_selection/ui_touch_selection.gyp:ui_touch_selection',
- '../wm/wm.gyp:wm',
- ],
- }],
- ['use_aura and chromeos == 0', {
- 'sources': [ '<@(views_desktop_aura_sources)' ],
- 'conditions': [
- ['OS == "linux"', {
- 'sources': [ '<@(views_desktop_aura_linux_sources)' ],
- }],
- ['use_x11 == 1', {
- 'sources': [ '<@(views_desktop_aura_x11_sources)' ],
- 'dependencies': [
- '../../build/linux/system.gyp:xext',
- '../../ui/base/x/ui_base_x.gyp:ui_base_x',
- ],
- }],
- ['OS == "win"', {
- 'sources': [ '<@(views_desktop_aura_win_sources)' ],
- }],
- ['use_ozone==1', {
- 'sources': [ '<@(views_desktop_aura_ozone_sources)' ],
- }],
- ],
- }],
- ['OS=="mac"', {
- 'dependencies': [
- '../accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac',
- ],
- 'link_settings': {
- 'libraries': [
- # Required by bridged_native_widget.mm.
- '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
- ],
- },
- }],
- ],
- }, # target_name: views
- {
- # GN version: //ui/views:test_support
- 'target_name': 'views_test_support',
- 'type': 'static_library',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../ipc/ipc.gyp:test_support_ipc',
- '../../skia/skia.gyp:skia',
- '../../testing/gtest.gyp:gtest',
- '../base/ime/ui_base_ime.gyp:ui_base_ime',
- '../base/ui_base.gyp:ui_base',
- '../base/ui_base.gyp:ui_base_test_support',
- '../compositor/compositor.gyp:compositor',
- '../compositor/compositor.gyp:compositor_test_support',
- '../events/events.gyp:events',
- '../events/events.gyp:events_test_support',
- '../events/platform/events_platform.gyp:events_platform',
- '../gfx/gfx.gyp:gfx',
- '../gfx/gfx.gyp:gfx_geometry',
- '../gfx/gfx.gyp:gfx_range',
- 'resources/views_resources.gyp:views_resources',
- 'views',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- '<@(views_test_support_sources)',
- # These are not listed in views_test_support_sources as they are not
- # used by the gn target that pulls in views_test_support_sources.
- 'test/native_widget_factory_desktop.cc',
- 'test/platform_test_helper.cc',
- 'test/platform_test_helper.h',
- ],
- 'conditions': [
- ['use_aura==1', {
- 'sources': [ '<@(views_test_support_aura_sources)' ],
- 'dependencies': [
- '../aura/aura.gyp:aura',
- '../aura/aura.gyp:aura_test_support',
- '../wm/wm.gyp:wm',
- ],
- }],
- ['use_aura==1 and use_x11==1 and chromeos==0', {
- 'sources': [ '<@(views_test_support_desktop_aura_x11_sources)' ],
- }],
- ],
- }, # target_name: views_test_support
- {
- # GN version: //ui/views:views_unittests
- 'target_name': 'views_unittests',
- 'type': 'executable',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/base.gyp:base_i18n',
- '../../base/base.gyp:test_support_base',
- '../../skia/skia.gyp:skia',
- '../../testing/gtest.gyp:gtest',
- '../../third_party/icu/icu.gyp:icui18n',
- '../../third_party/icu/icu.gyp:icuuc',
- '../../url/url.gyp:url_lib',
- '../accessibility/accessibility.gyp:accessibility',
- '../base/ime/ui_base_ime.gyp:ui_base_ime',
- '../base/ui_base.gyp:ui_base',
- '../base/ui_base.gyp:ui_base_test_support',
- '../compositor/compositor.gyp:compositor',
- '../events/events.gyp:events',
- '../events/events.gyp:events_base',
- '../events/events.gyp:events_test_support',
- '../gfx/gfx.gyp:gfx',
- '../gfx/gfx.gyp:gfx_geometry',
- '../gfx/gfx.gyp:gfx_range',
- '../native_theme/native_theme.gyp:native_theme',
- '../resources/ui_resources.gyp:ui_resources',
- '../resources/ui_resources.gyp:ui_test_pak',
- '../strings/ui_strings.gyp:ui_strings',
- 'resources/views_resources.gyp:views_resources',
- 'views',
- 'views_test_support',
- ],
- 'include_dirs': [
- '..',
- ],
- 'sources': [
- '<@(views_unittests_sources)',
- ],
- 'conditions': [
- ['OS=="win"', {
- 'dependencies': [
- '../../third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
- ],
- 'link_settings': {
- 'libraries': [
- '-limm32.lib',
- '-loleacc.lib',
- '-lcomctl32.lib',
- ]
- },
- 'include_dirs': [
- '../third_party/wtl/include',
- ],
- 'msvs_settings': {
- 'VCManifestTool': {
- 'AdditionalManifestFiles': [
- '$(ProjectDir)\\test\\views_unittest.manifest',
- ],
- },
- },
- }],
- ['use_x11==1', {
- 'dependencies': [
- '../../build/linux/system.gyp:x11',
- '../../build/linux/system.gyp:xext',
- '../events/devices/events_devices.gyp:events_devices',
- '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
- ],
- }],
- ['use_aura==1', {
- 'sources': [ '<@(views_unittests_aura_sources)' ],
- 'dependencies': [
- '../aura/aura.gyp:aura',
- '../aura/aura.gyp:aura_test_support',
- '../touch_selection/ui_touch_selection.gyp:ui_touch_selection',
- '../wm/wm.gyp:wm',
- ],
- 'conditions': [
- ['chromeos == 0', {
- 'sources': [ '<@(views_unittests_desktop_aura_sources)' ],
- }],
- ['chromeos == 0 and use_x11==1', {
- 'sources': [ '<@(views_unittests_desktop_aurax11_sources)' ],
- }],
- ]
- }],
- ['chromeos==0', {
- 'sources': [ '<@(views_unittests_desktop_sources)' ],
- }],
- ['use_x11==1', {
- 'dependencies': [
- '../events/platform/x11/x11_events_platform.gyp:x11_events_platform',
- ],
- }],
- ['OS=="mac"', {
- # views_unittests not yet compiling on Mac. http://crbug.com/378134
- 'sources!': [
- 'bubble/bubble_window_targeter_unittest.cc',
- 'controls/native/native_view_host_unittest.cc',
- 'widget/window_reorderer_unittest.cc',
- ],
- 'dependencies': [
- '../accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac',
- ],
- }],
- ],
- }, # target_name: views_unittests
- ], # targets
- 'conditions': [
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'views_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'views_unittests',
- ],
- 'includes': [
- '../../build/isolate.gypi',
- ],
- 'sources': [
- 'views_unittests.isolate',
- ],
- 'conditions': [
- ['use_x11==1',
- {
- 'dependencies': [
- '../../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
- ],
- }
- ],
- ],
- },
- ],
- }],
- ['OS=="mac"', {
- 'targets': [
- {
- # GN version: //ui/views:macviews_interactive_ui_tests
- 'target_name': 'macviews_interactive_ui_tests',
- 'type': 'executable',
- 'dependencies': [
- '../../base/base.gyp:base',
- '../../base/base.gyp:test_support_base',
- '../../skia/skia.gyp:skia',
- '../../testing/gtest.gyp:gtest',
- '../base/ui_base.gyp:ui_base_test_support',
- '../compositor/compositor.gyp:compositor_test_support',
- '../resources/ui_resources.gyp:ui_resources',
- '../resources/ui_resources.gyp:ui_test_pak',
- '../strings/ui_strings.gyp:ui_strings',
- 'views',
- 'views_test_support',
- ],
- 'sources': [
- 'cocoa/bridged_native_widget_interactive_uitest.mm',
- 'run_all_unittests_main.cc',
- 'views_test_suite.cc',
- 'views_test_suite.h',
- 'widget/native_widget_mac_interactive_uitest.mm',
- ],
- 'conditions': [
- ['use_aura == 1', {
- 'dependencies': [
- '../aura/aura.gyp:aura',
- '../wm/wm.gyp:wm',
- ],
- }],
- ],
- }, # target_name: macviews_interactive_ui_tests
- ], # targets
- }],
- ], # conditions
-}
diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc
index 082f2f1eff6..9127e7272f7 100644
--- a/chromium/ui/views/views_delegate.cc
+++ b/chromium/ui/views/views_delegate.cc
@@ -93,7 +93,7 @@ content::WebContents* ViewsDelegate::CreateWebContents(
return nullptr;
}
-base::TimeDelta ViewsDelegate::GetDefaultTextfieldObscuredRevealDuration() {
+base::TimeDelta ViewsDelegate::GetTextfieldPasswordRevealDuration() {
return base::TimeDelta();
}
diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h
index 54b5c4383e8..4ef9dd7b415 100644
--- a/chromium/ui/views/views_delegate.h
+++ b/chromium/ui/views/views_delegate.h
@@ -164,8 +164,8 @@ class VIEWS_EXPORT ViewsDelegate {
virtual void OnBeforeWidgetInit(Widget::InitParams* params,
internal::NativeWidgetDelegate* delegate) = 0;
- // Returns the default obscured text reveal duration.
- virtual base::TimeDelta GetDefaultTextfieldObscuredRevealDuration();
+ // Returns the password reveal duration for Textfield.
+ virtual base::TimeDelta GetTextfieldPasswordRevealDuration();
// Returns true if the operating system's window manager will always provide a
// title bar with caption buttons (ignoring the setting to
diff --git a/chromium/ui/views/views_unittests.isolate b/chromium/ui/views/views_unittests.isolate
deleted file mode 100644
index d58415f3942..00000000000
--- a/chromium/ui/views/views_unittests.isolate
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (c) 2016 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.
-{
- 'conditions': [
- ['use_x11==0', {
- 'variables': {
- 'command': [
- '../../testing/test_env.py',
- '<(PRODUCT_DIR)/views_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- },
- }],
- ['use_x11==1', {
- 'variables': {
- 'command': [
- '../../testing/xvfb.py',
- '<(PRODUCT_DIR)',
- '<(PRODUCT_DIR)/views_unittests<(EXECUTABLE_SUFFIX)',
- '--brave-new-test-launcher',
- '--test-launcher-bot-mode',
- '--asan=<(asan)',
- '--msan=<(msan)',
- '--tsan=<(tsan)',
- ],
- 'files': [
- '../../testing/xvfb.py',
- '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
- ],
- },
- }],
- ['OS=="linux" or OS=="mac" or OS=="win"', {
- 'variables': {
- 'files': [
- '../../testing/test_env.py',
- '<(PRODUCT_DIR)/ui_test.pak',
- ],
- },
- }],
- ['OS=="linux"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/libosmesa.so',
- ],
- },
- }],
- ['OS=="mac"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/osmesa.so',
- ],
- },
- }],
- ['OS=="win"', {
- 'variables': {
- 'files': [
- '<(PRODUCT_DIR)/osmesa.dll',
- ],
- },
- }],
- ],
- 'includes': [
- '../../base/base.isolate',
- ],
-}
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 1d416a62584..6437f9737d7 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
@@ -23,8 +23,8 @@
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
#include "ui/base/x/selection_utils.h"
-#include "ui/base/x/x11_foreign_window_manager.h"
#include "ui/base/x/x11_util.h"
+#include "ui/base/x/x11_window_event_manager.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
@@ -38,45 +38,142 @@
#include "ui/wm/public/drag_drop_client.h"
#include "ui/wm/public/drag_drop_delegate.h"
+// Reading recommended for understanding the implementation in this file:
+//
+// * The X Window System Concepts section in The X New Developer’s Guide
+// * The X Selection Mechanism paper by Keith Packard
+// * The Peer-to-Peer Communication by Means of Selections section in the
+// ICCCM (X Consortium's Inter-Client Communication Conventions Manual)
+// * The XDND specification, Drag-and-Drop Protocol for the X Window System
+// * The XDS specification, The Direct Save Protocol for the X Window System
+//
+// All the readings are freely available online.
+
using aura::client::DragDropDelegate;
using ui::OSExchangeData;
namespace {
-const int kMinXdndVersion = 5;
+// The lowest XDND protocol version that we understand.
+//
+// The XDND protocol specification says that we must support all versions
+// between 3 and the version we advertise in the XDndAware property.
+constexpr int kMinXdndVersion = 3;
+
+// The value used in the XdndAware property.
+//
+// The XDND protocol version used between two windows will be the minimum
+// between the two versions advertised in the XDndAware property.
+constexpr int kMaxXdndVersion = 5;
-const int kWillAcceptDrop = 1;
-const int kWantFurtherPosEvents = 2;
+constexpr int kWillAcceptDrop = 1;
+constexpr int kWantFurtherPosEvents = 2;
+// These actions have the same meaning as in the W3C Drag and Drop spec.
const char kXdndActionCopy[] = "XdndActionCopy";
const char kXdndActionMove[] = "XdndActionMove";
const char kXdndActionLink[] = "XdndActionLink";
+
+// "The target will do something that the source would not understand." The
+// source only needs to provide a copy of the dragged data.
+const char kXdndActionPrivate[] = "XdndActionPrivate";
+
+// The target should ask the user what action it wants to perform. Intended to
+// match Windows' right-click drag and drop, which shows a dropdown.
+const char kXdndActionAsk[] = "XdndActionAsk";
+
+// Triggers the XDS protocol.
const char kXdndActionDirectSave[] = "XdndActionDirectSave";
+// Window property that will receive the drag and drop selection data.
const char kChromiumDragReciever[] = "_CHROMIUM_DRAG_RECEIVER";
-const char kXdndSelection[] = "XdndSelection";
+
+// Window property that contains the possible actions that will be presented to
+// the user when the drag and drop action is kXdndActionAsk.
+const char kXdndActionList[] = "XdndActionList";
+
+// Window property that tells other applications the window understands XDND.
+const char kXdndAware[] = "XdndAware";
+
+// Window property on the source window and message used by the XDS protocol.
+// This atom name intentionally includes the XDS protocol version (0).
+// After the source sends the XdndDrop message, this property stores the
+// (path-less) name of the file to be saved, and has the type text/plain, with
+// an optional charset attribute.
+// When receiving an XdndDrop event, the target needs to check for the
+// XdndDirectSave property on the source window. The target then modifies the
+// XdndDirectSave on the source window, and sends an XdndDirectSave message to
+// the source.
+// After the target sends the XdndDirectSave message, this property stores an
+// URL indicating the location where the source should save the file.
const char kXdndDirectSave0[] = "XdndDirectSave0";
+// Window property pointing to a proxy window to receive XDND target messages.
+// The XDND source must check the proxy window must for the XdndAware property,
+// and must send all XDND messages to the proxy instead of the target. However,
+// the target field in the messages must still represent the original target
+// window (the window pointed to by the cursor).
+const char kXdndProxy[] = "XdndProxy";
+
+// Window property that holds the supported drag and drop data types.
+// This property is set on the XDND source window when the drag and drop data
+// can be converted to more than 3 types.
+const char kXdndTypeList[] = "XdndTypeList";
+
+// Selection used by the XDND protocol to transfer data between applications.
+const char kXdndSelection[] = "XdndSelection";
+
+// Message sent from an XDND source to the target when the user confirms the
+// drag and drop operation.
+const char kXdndDrop[] = "XdndDrop";
+
+// Message sent from an XDND source to the target to start the XDND protocol.
+// The target must wait for an XDndPosition event before querying the data.
+const char kXdndEnter[] = "XdndEnter";
+
+// Message sent from an XDND target to the source in respose to an XdndDrop.
+// The message must be sent whether the target acceepts the drop or not.
+const char kXdndFinished[] = "XdndFinished";
+
+// Message sent from an XDND source to the target when the user cancels the drag
+// and drop operation.
+const char kXdndLeave[] = "XdndLeave";
+
+// Message sent by the XDND source when the cursor position changes.
+// The source will also send an XdndPosition event right after the XdndEnter
+// event, to tell the target about the initial cursor position and the desired
+// drop action.
+// The time stamp in the XdndPosition must be used when requesting selection
+// information.
+// After the target optionally acquires selection information, it must tell the
+// source if it can accept the drop via an XdndStatus message.
+const char kXdndPosition[] = "XdndPosition";
+
+// Message sent by the XDND target in response to an XdndPosition message.
+// The message informs the source if the target will accept the drop, and what
+// action will be taken if the drop is accepted.
+const char kXdndStatus[] = "XdndStatus";
+
const char* kAtomsToCache[] = {
kChromiumDragReciever,
- "XdndActionAsk",
+ kXdndActionAsk,
kXdndActionCopy,
kXdndActionDirectSave,
kXdndActionLink,
- "XdndActionList",
+ kXdndActionList,
kXdndActionMove,
- "XdndActionPrivate",
- "XdndAware",
+ kXdndActionPrivate,
+ kXdndAware,
kXdndDirectSave0,
- "XdndDrop",
- "XdndEnter",
- "XdndFinished",
- "XdndLeave",
- "XdndPosition",
- "XdndProxy", // Proxy windows?
+ kXdndDrop,
+ kXdndEnter,
+ kXdndFinished,
+ kXdndLeave,
+ kXdndPosition,
+ kXdndProxy,
kXdndSelection,
- "XdndStatus",
- "XdndTypeList",
+ kXdndStatus,
+ kXdndTypeList,
ui::Clipboard::kMimeTypeText,
NULL
};
@@ -131,7 +228,7 @@ const uint32_t kMinAlpha = 32;
const float kDragWidgetOpacity = .75f;
static base::LazyInstance<
- std::map< ::Window, views::DesktopDragDropClientAuraX11*> >::Leaky
+ std::map<::Window, views::DesktopDragDropClientAuraX11*> >::Leaky
g_live_client_map = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -153,23 +250,19 @@ class DesktopDragDropClientAuraX11::X11DragContext
// copied from the other window before we process the XdndPosition
// message. If we have that data already, dispatch immediately. Otherwise,
// delay dispatching until we do.
- void OnStartXdndPositionMessage(DesktopDragDropClientAuraX11* client,
+ void OnXdndPositionMessage(DesktopDragDropClientAuraX11* client,
::Atom suggested_action,
::Window source_window,
+ ::Time time_stamp,
const gfx::Point& screen_point);
- // Called to request the next target from the source window. This is only
- // done on the first XdndPosition; after that, we cache the data offered by
- // the source window.
- void RequestNextTarget();
-
// Called when XSelection data has been copied to our process.
void OnSelectionNotify(const XSelectionEvent& xselection);
// Clones the fetched targets.
const ui::SelectionFormatMap& fetched_targets() { return fetched_targets_; }
- // Reads the "XdndActionList" property from |source_window| and copies it
+ // Reads the kXdndActionList property from |source_window| and copies it
// into |actions|.
void ReadActions();
@@ -180,6 +273,11 @@ class DesktopDragDropClientAuraX11::X11DragContext
DesktopDragDropClientAuraX11* source_client() { return source_client_; }
private:
+ // Called to request the next target from the source window. This is only
+ // done on the first XdndPosition; after that, we cache the data offered by
+ // the source window.
+ void RequestNextTarget();
+
// Masks the X11 atom |xdnd_operation|'s views representation onto
// |drag_operation|.
void MaskOperation(::Atom xdnd_operation, int* drag_operation) const;
@@ -197,14 +295,13 @@ class DesktopDragDropClientAuraX11::X11DragContext
// The XID of the window that's initiated the drag.
unsigned long source_window_;
+ // Events that we have selected on |source_window_|.
+ std::unique_ptr<ui::XScopedEventSelector> source_window_events_;
+
// The DesktopDragDropClientAuraX11 for |source_window_| if |source_window_|
// belongs to a Chrome window.
DesktopDragDropClientAuraX11* source_client_;
- // Used to unselect PropertyChangeMask on |source_window_| if |source_window_|
- // does not belong to a Chrome window when X11DragContext is destroyed.
- int foreign_window_manager_source_window_id_;
-
// The client we inform once we're done with requesting data.
DesktopDragDropClientAuraX11* drag_drop_client_;
@@ -215,19 +312,24 @@ class DesktopDragDropClientAuraX11::X11DragContext
// Where the cursor is on screen.
gfx::Point screen_point_;
+ // The time stamp of the last XdndPosition event we received. The XDND
+ // specification mandates that we use this time stamp when querying the source
+ // about the drag and drop data.
+ ::Time position_time_stamp_;
+
// A SelectionFormatMap of data that we have in our process.
ui::SelectionFormatMap fetched_targets_;
// The names of various data types offered by the other window that we
// haven't fetched and put in |fetched_targets_| yet.
- std::vector<Atom> unfetched_targets_;
+ std::vector<::Atom> unfetched_targets_;
// XdndPosition messages have a suggested action. Qt applications exclusively
// use this, instead of the XdndActionList which is backed by |actions_|.
- Atom suggested_action_;
+ ::Atom suggested_action_;
// Possible actions.
- std::vector<Atom> actions_;
+ std::vector<::Atom> actions_;
DISALLOW_COPY_AND_ASSIGN(X11DragContext);
};
@@ -241,34 +343,39 @@ DesktopDragDropClientAuraX11::X11DragContext::X11DragContext(
source_window_(event.data.l[0]),
source_client_(
DesktopDragDropClientAuraX11::GetForWindow(source_window_)),
- foreign_window_manager_source_window_id_(0),
drag_drop_client_(NULL),
waiting_to_handle_position_(false),
suggested_action_(None) {
if (!source_client_) {
- bool get_types = ((event.data.l[1] & 1) != 0);
+ bool get_types_from_property = ((event.data.l[1] & 1) != 0);
- if (get_types) {
+ if (get_types_from_property) {
if (!ui::GetAtomArrayProperty(source_window_,
- "XdndTypeList",
+ kXdndTypeList,
&unfetched_targets_)) {
return;
}
} else {
// data.l[2,3,4] contain the first three types. Unused slots can be None.
for (int i = 0; i < 3; ++i) {
- if (event.data.l[2+i] != None) {
- unfetched_targets_.push_back(event.data.l[2+i]);
+ if (event.data.l[2 + i] != None) {
+ unfetched_targets_.push_back(event.data.l[2 + i]);
}
}
}
+#if DCHECK_IS_ON()
+ DVLOG(1) << "XdndEnter has " << unfetched_targets_.size() << " data types";
+ for (::Atom target : unfetched_targets_) {
+ DVLOG(1) << "XdndEnter data type: " << target;
+ }
+#endif // DCHECK_IS_ON()
+
// The window doesn't have a DesktopDragDropClientAuraX11, that means it's
// created by some other process. Listen for messages on it.
ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
- foreign_window_manager_source_window_id_ =
- ui::XForeignWindowManager::GetInstance()->RequestEvents(
- source_window_, PropertyChangeMask);
+ source_window_events_.reset(
+ new ui::XScopedEventSelector(source_window_, PropertyChangeMask));
// We must perform a full sync here because we could be racing
// |source_window_|.
@@ -287,15 +394,14 @@ DesktopDragDropClientAuraX11::X11DragContext::~X11DragContext() {
if (!source_client_) {
// Unsubscribe from message events.
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
- ui::XForeignWindowManager::GetInstance()->CancelRequest(
- foreign_window_manager_source_window_id_);
}
}
-void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
+void DesktopDragDropClientAuraX11::X11DragContext::OnXdndPositionMessage(
DesktopDragDropClientAuraX11* client,
::Atom suggested_action,
::Window source_window,
+ ::Time time_stamp,
const gfx::Point& screen_point) {
DCHECK_EQ(source_window_, source_window);
suggested_action_ = suggested_action;
@@ -305,6 +411,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
// the position message and ask the other window for its data.
screen_point_ = screen_point;
drag_drop_client_ = client;
+ position_time_stamp_ = time_stamp;
waiting_to_handle_position_ = true;
fetched_targets_ = ui::SelectionFormatMap();
@@ -315,6 +422,10 @@ void DesktopDragDropClientAuraX11::X11DragContext::OnStartXdndPositionMessage(
}
void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() {
+ DCHECK(!unfetched_targets_.empty());
+ DCHECK(drag_drop_client_);
+ DCHECK(waiting_to_handle_position_);
+
::Atom target = unfetched_targets_.back();
unfetched_targets_.pop_back();
@@ -323,7 +434,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::RequestNextTarget() {
target,
atom_cache_->GetAtom(kChromiumDragReciever),
local_window_,
- CurrentTime);
+ position_time_stamp_);
}
void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify(
@@ -334,13 +445,24 @@ void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify(
return;
}
DCHECK(drag_drop_client_);
- DCHECK_EQ(event.property, atom_cache_->GetAtom(kChromiumDragReciever));
- scoped_refptr<base::RefCountedMemory> data;
- ::Atom type = None;
- if (ui::GetRawBytesOfProperty(local_window_, event.property,
- &data, NULL, &type)) {
- fetched_targets_.Insert(event.target, data);
+ DVLOG(1) << "SelectionNotify, format " << event.target;
+
+ if (event.property != None) {
+ DCHECK_EQ(event.property, atom_cache_->GetAtom(kChromiumDragReciever));
+
+ scoped_refptr<base::RefCountedMemory> data;
+ ::Atom type = None;
+ if (ui::GetRawBytesOfProperty(local_window_, event.property,
+ &data, NULL, &type)) {
+ fetched_targets_.Insert(event.target, data);
+ }
+ } else {
+ // The source failed to convert the drop data to the format (target in X11
+ // parlance) that we asked for. This happens, even though we only ask for
+ // the formats advertised by the source. http://crbug.com/628099
+ LOG(ERROR) << "XConvertSelection failed for source-advertised target "
+ << event.target;
}
if (!unfetched_targets_.empty()) {
@@ -354,9 +476,9 @@ void DesktopDragDropClientAuraX11::X11DragContext::OnSelectionNotify(
void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() {
if (!source_client_) {
- std::vector<Atom> atom_array;
+ std::vector<::Atom> atom_array;
if (!ui::GetAtomArrayProperty(source_window_,
- "XdndActionList",
+ kXdndActionList,
&atom_array)) {
actions_.clear();
} else {
@@ -372,7 +494,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() {
int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const {
int drag_operation = ui::DragDropTypes::DRAG_NONE;
- for (std::vector<Atom>::const_iterator it = actions_.begin();
+ for (std::vector<::Atom>::const_iterator it = actions_.begin();
it != actions_.end(); ++it) {
MaskOperation(*it, &drag_operation);
}
@@ -401,7 +523,7 @@ bool DesktopDragDropClientAuraX11::X11DragContext::CanDispatchEvent(
uint32_t DesktopDragDropClientAuraX11::X11DragContext::DispatchEvent(
const ui::PlatformEvent& event) {
if (event->type == PropertyNotify &&
- event->xproperty.atom == atom_cache_->GetAtom("XdndActionList")) {
+ event->xproperty.atom == atom_cache_->GetAtom(kXdndActionList)) {
ReadActions();
return ui::POST_DISPATCH_STOP_PROPAGATION;
}
@@ -435,8 +557,8 @@ DesktopDragDropClientAuraX11::DesktopDragDropClientAuraX11(
g_live_client_map.Get()[xwindow] = this;
// Mark that we are aware of drag and drop concepts.
- unsigned long xdnd_version = kMinXdndVersion;
- XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndAware"),
+ unsigned long xdnd_version = kMaxXdndVersion;
+ XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndAware),
XA_ATOM, 32, PropModeReplace,
reinterpret_cast<unsigned char*>(&xdnd_version), 1);
}
@@ -453,7 +575,7 @@ DesktopDragDropClientAuraX11::~DesktopDragDropClientAuraX11() {
// static
DesktopDragDropClientAuraX11* DesktopDragDropClientAuraX11::GetForWindow(
::Window window) {
- std::map< ::Window, DesktopDragDropClientAuraX11*>::const_iterator it =
+ std::map<::Window, DesktopDragDropClientAuraX11*>::const_iterator it =
g_live_client_map.Get().find(window);
if (it == g_live_client_map.Get().end())
return NULL;
@@ -466,11 +588,21 @@ void DesktopDragDropClientAuraX11::Init() {
void DesktopDragDropClientAuraX11::OnXdndEnter(
const XClientMessageEvent& event) {
- DVLOG(1) << "XdndEnter";
-
int version = (event.data.l[1] & 0xff000000) >> 24;
- if (version < 3) {
- LOG(ERROR) << "Received old XdndEnter message.";
+ DVLOG(1) << "OnXdndEnter, version " << version;
+
+ if (version < kMinXdndVersion) {
+ // This protocol version is not documented in the XDND standard (last
+ // revised in 1999), so we don't support it. Since don't understand the
+ // protocol spoken by the source, we can't tell it that we can't talk to it.
+ LOG(ERROR) << "XdndEnter message discarded because its version is too old.";
+ return;
+ }
+ if (version > kMaxXdndVersion) {
+ // The XDND version used should be the minimum between the versions
+ // advertised by the source and the target. We advertise kMaxXdndVersion, so
+ // this should never happen when talking to an XDND-compliant application.
+ LOG(ERROR) << "XdndEnter message discarded because its version is too new.";
return;
}
@@ -480,25 +612,26 @@ void DesktopDragDropClientAuraX11::OnXdndEnter(
new X11DragContext(&atom_cache_, xwindow_, event));
// In the Windows implementation, we immediately call DesktopDropTargetWin::
- // Translate(). Here, we wait until we receive an XdndPosition message
- // because the enter message doesn't convey any positioning
- // information.
+ // Translate(). The XDND specification demands that we wait until we receive
+ // an XdndPosition message before we use XConvertSelection or send an
+ // XdndStatus message.
}
void DesktopDragDropClientAuraX11::OnXdndLeave(
const XClientMessageEvent& event) {
- DVLOG(1) << "XdndLeave";
+ DVLOG(1) << "OnXdndLeave";
NotifyDragLeave();
target_current_context_.reset();
}
void DesktopDragDropClientAuraX11::OnXdndPosition(
const XClientMessageEvent& event) {
- DVLOG(1) << "XdndPosition";
+ DVLOG(1) << "OnXdndPosition";
unsigned long source_window = event.data.l[0];
int x_root_window = event.data.l[2] >> 16;
int y_root_window = event.data.l[2] & 0xffff;
+ ::Time time_stamp = event.data.l[3];
::Atom suggested_action = event.data.l[4];
if (!target_current_context_.get()) {
@@ -506,16 +639,14 @@ void DesktopDragDropClientAuraX11::OnXdndPosition(
return;
}
- // If we already have all the data from this drag, we complete it
- // immediately.
- target_current_context_->OnStartXdndPositionMessage(
- this, suggested_action, source_window,
+ target_current_context_->OnXdndPositionMessage(
+ this, suggested_action, source_window, time_stamp,
gfx::Point(x_root_window, y_root_window));
}
void DesktopDragDropClientAuraX11::OnXdndStatus(
const XClientMessageEvent& event) {
- DVLOG(1) << "XdndStatus";
+ DVLOG(1) << "OnXdndStatus";
unsigned long source_window = event.data.l[0];
@@ -581,7 +712,7 @@ void DesktopDragDropClientAuraX11::OnXdndStatus(
void DesktopDragDropClientAuraX11::OnXdndFinished(
const XClientMessageEvent& event) {
- DVLOG(1) << "XdndFinished";
+ DVLOG(1) << "OnXdndFinished";
unsigned long source_window = event.data.l[0];
if (source_current_window_ != source_window)
return;
@@ -598,7 +729,7 @@ void DesktopDragDropClientAuraX11::OnXdndFinished(
void DesktopDragDropClientAuraX11::OnXdndDrop(
const XClientMessageEvent& event) {
- DVLOG(1) << "XdndDrop";
+ DVLOG(1) << "OnXdndDrop";
unsigned long source_window = event.data.l[0];
@@ -607,8 +738,9 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
aura::client::DragDropDelegate* delegate =
aura::client::GetDragDropDelegate(target_window_);
if (delegate) {
- ui::OSExchangeData data(new ui::OSExchangeDataProviderAuraX11(
- xwindow_, target_current_context_->fetched_targets()));
+ ui::OSExchangeData data(
+ base::MakeUnique<ui::OSExchangeDataProviderAuraX11>(
+ xwindow_, target_current_context_->fetched_targets()));
ui::DropTargetEvent event(data,
target_window_location_,
@@ -634,7 +766,7 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
XEvent xev;
xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndFinished");
+ xev.xclient.message_type = atom_cache_.GetAtom(kXdndFinished);
xev.xclient.format = 32;
xev.xclient.window = source_window;
xev.xclient.data.l[0] = xwindow_;
@@ -646,6 +778,7 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
void DesktopDragDropClientAuraX11::OnSelectionNotify(
const XSelectionEvent& xselection) {
+ DVLOG(1) << "OnSelectionNotify";
if (target_current_context_)
target_current_context_->OnSelectionNotify(xselection);
@@ -680,7 +813,7 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
source_provider_->TakeOwnershipOfSelection();
- std::vector< ::Atom> actions = GetOfferedDragOperations();
+ std::vector<::Atom> actions = GetOfferedDragOperations();
if (!source_provider_->file_contents_name().empty()) {
actions.push_back(atom_cache_.GetAtom(kXdndActionDirectSave));
ui::SetStringProperty(
@@ -689,7 +822,7 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
atom_cache_.GetAtom(ui::Clipboard::kMimeTypeText),
source_provider_->file_contents_name().AsUTF8Unsafe());
}
- ui::SetAtomArrayProperty(xwindow_, "XdndActionList", "ATOM", actions);
+ ui::SetAtomArrayProperty(xwindow_, kXdndActionList, "ATOM", actions);
gfx::ImageSkia drag_image = source_provider_->GetDragImage();
if (IsValidDragImage(drag_image)) {
@@ -729,7 +862,7 @@ int DesktopDragDropClientAuraX11::StartDragAndDrop(
source_provider_ = NULL;
g_current_drag_drop_client = NULL;
drag_operation_ = 0;
- XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("XdndActionList"));
+ XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndActionList));
XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom(kXdndDirectSave0));
return negotiated_operation_;
@@ -857,14 +990,18 @@ XID DesktopDragDropClientAuraX11::FindWindowFor(
if (target == None)
return None;
+ // TODO(crbug/651775): The proxy window should be reported separately from the
+ // target window. XDND messages should be sent to the proxy, and their
+ // window field should point to the target.
+
// Figure out which window we should test as XdndAware. If |target| has
// XdndProxy, it will set that proxy on target, and if not, |target|'s
// original value will remain.
- ui::GetXIDProperty(target, "XdndProxy", &target);
+ ui::GetXIDProperty(target, kXdndProxy, &target);
int version;
- if (ui::GetIntProperty(target, "XdndAware", &version) &&
- version >= kMinXdndVersion) {
+ if (ui::GetIntProperty(target, kXdndAware, &version) &&
+ version >= kMaxXdndVersion) {
return target;
}
return None;
@@ -878,22 +1015,22 @@ void DesktopDragDropClientAuraX11::SendXClientEvent(::Window xid,
DesktopDragDropClientAuraX11* short_circuit = GetForWindow(xid);
if (short_circuit) {
Atom message_type = xev->xclient.message_type;
- if (message_type == atom_cache_.GetAtom("XdndEnter")) {
+ if (message_type == atom_cache_.GetAtom(kXdndEnter)) {
short_circuit->OnXdndEnter(xev->xclient);
return;
- } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
+ } else if (message_type == atom_cache_.GetAtom(kXdndLeave)) {
short_circuit->OnXdndLeave(xev->xclient);
return;
- } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
+ } else if (message_type == atom_cache_.GetAtom(kXdndPosition)) {
short_circuit->OnXdndPosition(xev->xclient);
return;
- } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
+ } else if (message_type == atom_cache_.GetAtom(kXdndStatus)) {
short_circuit->OnXdndStatus(xev->xclient);
return;
- } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
+ } else if (message_type == atom_cache_.GetAtom(kXdndFinished)) {
short_circuit->OnXdndFinished(xev->xclient);
return;
- } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
+ } else if (message_type == atom_cache_.GetAtom(kXdndDrop)) {
short_circuit->OnXdndDrop(xev->xclient);
return;
}
@@ -981,8 +1118,9 @@ void DesktopDragDropClientAuraX11::DragTranslate(
if (!*delegate)
return;
- data->reset(new OSExchangeData(new ui::OSExchangeDataProviderAuraX11(
- xwindow_, target_current_context_->fetched_targets())));
+ data->reset(new OSExchangeData(
+ base::MakeUnique<ui::OSExchangeDataProviderAuraX11>(
+ xwindow_, target_current_context_->fetched_targets())));
gfx::Point location = root_location;
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
@@ -1051,8 +1189,8 @@ DesktopDragDropClientAuraX11::AtomToDragOperation(::Atom atom) {
return ui::DragDropTypes::DRAG_NONE;
}
-std::vector< ::Atom> DesktopDragDropClientAuraX11::GetOfferedDragOperations() {
- std::vector< ::Atom> operations;
+std::vector<::Atom> DesktopDragDropClientAuraX11::GetOfferedDragOperations() {
+ std::vector<::Atom> operations;
if (drag_operation_ & ui::DragDropTypes::DRAG_COPY)
operations.push_back(atom_cache_.GetAtom(kXdndActionCopy));
if (drag_operation_ & ui::DragDropTypes::DRAG_MOVE)
@@ -1086,7 +1224,7 @@ void DesktopDragDropClientAuraX11::CompleteXdndPosition(
// sets this nor respects it if set.
XEvent xev;
xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndStatus");
+ xev.xclient.message_type = atom_cache_.GetAtom(kXdndStatus);
xev.xclient.format = 32;
xev.xclient.window = source_window;
xev.xclient.data.l[0] = xwindow_;
@@ -1102,11 +1240,11 @@ void DesktopDragDropClientAuraX11::CompleteXdndPosition(
void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) {
XEvent xev;
xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndEnter");
+ xev.xclient.message_type = atom_cache_.GetAtom(kXdndEnter);
xev.xclient.format = 32;
xev.xclient.window = dest_window;
xev.xclient.data.l[0] = xwindow_;
- xev.xclient.data.l[1] = (kMinXdndVersion << 24); // The version number.
+ xev.xclient.data.l[1] = (kMaxXdndVersion << 24); // The version number.
xev.xclient.data.l[2] = 0;
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;
@@ -1116,7 +1254,7 @@ void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) {
if (targets.size() > 3) {
xev.xclient.data.l[1] |= 1;
- ui::SetAtomArrayProperty(xwindow_, "XdndTypeList", "ATOM", targets);
+ ui::SetAtomArrayProperty(xwindow_, kXdndTypeList, "ATOM", targets);
} else {
// Pack the targets into the enter message.
for (size_t i = 0; i < targets.size(); ++i)
@@ -1129,7 +1267,7 @@ void DesktopDragDropClientAuraX11::SendXdndEnter(::Window dest_window) {
void DesktopDragDropClientAuraX11::SendXdndLeave(::Window dest_window) {
XEvent xev;
xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndLeave");
+ xev.xclient.message_type = atom_cache_.GetAtom(kXdndLeave);
xev.xclient.format = 32;
xev.xclient.window = dest_window;
xev.xclient.data.l[0] = xwindow_;
@@ -1148,7 +1286,7 @@ void DesktopDragDropClientAuraX11::SendXdndPosition(
XEvent xev;
xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndPosition");
+ xev.xclient.message_type = atom_cache_.GetAtom(kXdndPosition);
xev.xclient.format = 32;
xev.xclient.window = dest_window;
xev.xclient.data.l[0] = xwindow_;
@@ -1173,7 +1311,7 @@ void DesktopDragDropClientAuraX11::SendXdndPosition(
void DesktopDragDropClientAuraX11::SendXdndDrop(::Window dest_window) {
XEvent xev;
xev.xclient.type = ClientMessage;
- xev.xclient.message_type = atom_cache_.GetAtom("XdndDrop");
+ xev.xclient.message_type = atom_cache_.GetAtom(kXdndDrop);
xev.xclient.format = 32;
xev.xclient.window = dest_window;
xev.xclient.data.l[0] = xwindow_;
@@ -1188,7 +1326,7 @@ void DesktopDragDropClientAuraX11::CreateDragWidget(
const gfx::ImageSkia& image) {
Widget* widget = new Widget;
Widget::InitParams params(Widget::InitParams::TYPE_DRAG);
- params.opacity = Widget::InitParams::OPAQUE_WINDOW;
+ params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.accept_events = false;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
index 875763dad35..76e022d1193 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -4,6 +4,7 @@
#include "ui/views/widget/desktop_aura/desktop_drop_target_win.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/win/win_util.h"
#include "ui/aura/window.h"
@@ -148,7 +149,8 @@ void DesktopDropTargetWin::Translate(
if (!*delegate)
return;
- data->reset(new OSExchangeData(new OSExchangeDataProviderWin(data_object)));
+ data->reset(new OSExchangeData(
+ base::MakeUnique<OSExchangeDataProviderWin>(data_object)));
location = root_location;
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
event->reset(new ui::DropTargetEvent(
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index d49af384df8..b3d06cfd2f8 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -37,6 +37,7 @@
#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#include "ui/views/widget/drop_helper.h"
+#include "ui/views/widget/focus_manager_event_handler.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/tooltip_manager_aura.h"
@@ -208,27 +209,6 @@ class DesktopNativeWidgetAuraWindowTreeClient :
} // namespace
-class FocusManagerEventHandler : public ui::EventHandler {
- public:
- explicit FocusManagerEventHandler(
- DesktopNativeWidgetAura* desktop_native_widget_aura)
- : desktop_native_widget_aura_(desktop_native_widget_aura) {}
-
- // Implementation of ui::EventHandler:
- void OnKeyEvent(ui::KeyEvent* event) override {
- Widget* widget = desktop_native_widget_aura_->GetWidget();
- if (widget && widget->GetFocusManager()->GetFocusedView() &&
- !widget->GetFocusManager()->OnKeyEvent(*event)) {
- event->StopPropagation();
- }
- }
-
- private:
- DesktopNativeWidgetAura* desktop_native_widget_aura_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusManagerEventHandler);
-};
-
class RootWindowDestructionObserver : public aura::WindowObserver {
public:
explicit RootWindowDestructionObserver(DesktopNativeWidgetAura* parent)
@@ -316,6 +296,8 @@ void DesktopNativeWidgetAura::OnHostClosed() {
capture_client_.reset(); // Uses host_->dispatcher() at destruction.
+ focus_manager_event_handler_.reset();
+
// FocusController uses |content_window_|. Destroy it now so that we don't
// have to worry about the possibility of FocusController attempting to use
// |content_window_| after it's been destroyed but before all child windows
@@ -515,8 +497,8 @@ void DesktopNativeWidgetAura::InitNativeWidget(
}
if (params.type == Widget::InitParams::TYPE_WINDOW) {
- focus_manager_event_handler_.reset(new FocusManagerEventHandler(this));
- host_->window()->AddPreTargetHandler(focus_manager_event_handler_.get());
+ focus_manager_event_handler_ = base::MakeUnique<FocusManagerEventHandler>(
+ GetWidget(), host_->window());
}
event_client_.reset(new DesktopEventClient);
@@ -651,6 +633,9 @@ void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
if (content_window_)
desktop_window_tree_host_->SetWindowIcons(window_icon, app_icon);
+
+ NativeWidgetAura::AssignIconToAuraWindow(content_window_, window_icon,
+ app_icon);
}
void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) {
@@ -704,12 +689,9 @@ void DesktopNativeWidgetAura::StackAtTop() {
desktop_window_tree_host_->StackAtTop();
}
-void DesktopNativeWidgetAura::StackBelow(gfx::NativeView native_view) {
-}
-
-void DesktopNativeWidgetAura::SetShape(SkRegion* shape) {
+void DesktopNativeWidgetAura::SetShape(std::unique_ptr<SkRegion> shape) {
if (content_window_)
- desktop_window_tree_host_->SetShape(shape);
+ desktop_window_tree_host_->SetShape(std::move(shape));
}
void DesktopNativeWidgetAura::Close() {
@@ -743,6 +725,7 @@ void DesktopNativeWidgetAura::Hide() {
void DesktopNativeWidgetAura::ShowMaximizedWithBounds(
const gfx::Rect& restored_bounds) {
+ // IsVisible() should check the same objects here for visibility.
if (!content_window_)
return;
desktop_window_tree_host_->ShowMaximizedWithBounds(restored_bounds);
@@ -750,6 +733,7 @@ void DesktopNativeWidgetAura::ShowMaximizedWithBounds(
}
void DesktopNativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
+ // IsVisible() should check the same objects here for visibility.
if (!content_window_)
return;
desktop_window_tree_host_->ShowWindowWithState(state);
@@ -757,7 +741,13 @@ void DesktopNativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
}
bool DesktopNativeWidgetAura::IsVisible() const {
- return content_window_ && desktop_window_tree_host_->IsVisible();
+ // The objects checked here should be the same objects changed in
+ // ShowWithWindowState and ShowMaximizedWithBounds. For example, MS Windows
+ // platform code might show the desktop window tree host early, meaning we
+ // aren't fully visible as we haven't shown the content window. Callers may
+ // short-circuit a call to show this widget if they think its already visible.
+ return content_window_ && content_window_->IsVisible() &&
+ desktop_window_tree_host_->IsVisible();
}
void DesktopNativeWidgetAura::Activate() {
@@ -788,6 +778,11 @@ void DesktopNativeWidgetAura::SetVisibleOnAllWorkspaces(bool always_visible) {
desktop_window_tree_host_->SetVisibleOnAllWorkspaces(always_visible);
}
+bool DesktopNativeWidgetAura::IsVisibleOnAllWorkspaces() const {
+ return content_window_ &&
+ desktop_window_tree_host_->IsVisibleOnAllWorkspaces();
+}
+
void DesktopNativeWidgetAura::Maximize() {
if (content_window_)
desktop_window_tree_host_->Maximize();
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index 1e57f7f2c58..a6a05912fa2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -128,8 +128,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void SetSize(const gfx::Size& size) override;
void StackAbove(gfx::NativeView native_view) override;
void StackAtTop() override;
- void StackBelow(gfx::NativeView native_view) override;
- void SetShape(SkRegion* shape) override;
+ void SetShape(std::unique_ptr<SkRegion> shape) override;
void Close() override;
void CloseNow() override;
void Show() override;
@@ -143,6 +142,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void SetAlwaysOnTop(bool always_on_top) override;
bool IsAlwaysOnTop() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
void Maximize() override;
void Minimize() override;
bool IsMaximized() const override;
@@ -231,7 +231,6 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
const gfx::Point& new_origin) override;
private:
- friend class FocusManagerEventHandler;
friend class RootWindowDestructionObserver;
// To save a clear on platforms where the window is never transparent, the
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 5865426151c..ff2437ee1e4 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
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
@@ -101,6 +102,21 @@ TEST_F(DesktopNativeWidgetAuraTest, NativeViewInitiallyHidden) {
EXPECT_FALSE(widget.GetNativeView()->IsVisible());
}
+// Verifies that if the DesktopWindowTreeHost is already shown, the native view
+// still reports not visible as we haven't shown the content window.
+TEST_F(DesktopNativeWidgetAuraTest, WidgetNotVisibleOnlyWindowTreeHostShown) {
+ Widget widget;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ init_params.native_widget = new DesktopNativeWidgetAura(&widget);
+ widget.Init(init_params);
+ DesktopNativeWidgetAura* desktop_native_widget_aura =
+ static_cast<DesktopNativeWidgetAura*>(widget.native_widget());
+ desktop_native_widget_aura->host()->Show();
+ EXPECT_FALSE(widget.IsVisible());
+}
+
// Verify that the cursor state is shared between two native widgets.
TEST_F(DesktopNativeWidgetAuraTest, GlobalCursorState) {
// Create two native widgets, each owning different root windows.
@@ -239,10 +255,10 @@ TEST_F(DesktopNativeWidgetAuraTest, WidgetCanBeDestroyedFromNestedLoop) {
// |RunWithDispatcher()| below.
base::RunLoop run_loop;
base::Closure quit_runloop = run_loop.QuitClosure();
- message_loop()->PostTask(FROM_HERE,
- base::Bind(&QuitNestedLoopAndCloseWidget,
- base::Passed(&widget),
- base::Unretained(&quit_runloop)));
+ message_loop()->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&QuitNestedLoopAndCloseWidget, base::Passed(&widget),
+ base::Unretained(&quit_runloop)));
run_loop.Run();
}
@@ -509,6 +525,8 @@ TEST_F(DesktopAuraWidgetTest, CloseWidgetDuringMouseReleased) {
RunCloseWidgetDuringDispatchTest(this, ui::ET_MOUSE_RELEASED);
}
+namespace {
+
// Provides functionality to create a window modal dialog.
class ModalDialogDelegate : public DialogDelegateView {
public:
@@ -522,6 +540,8 @@ class ModalDialogDelegate : public DialogDelegateView {
DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
};
+} // namespace
+
// This test verifies that whether mouse events when a modal dialog is
// displayed are eaten or recieved by the dialog.
TEST_F(WidgetTest, WindowMouseModalityTest) {
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 06335ed0071..96f20cca216 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -72,7 +72,7 @@ std::vector<display::Display> GetFallbackDisplayList() {
gfx::Rect bounds_in_pixels(0, 0, width, height);
display::Display gfx_display(0, bounds_in_pixels);
if (!display::Display::HasForceDeviceScaleFactor() &&
- !ui::IsDisplaySizeBlackListed(physical_size)) {
+ !display::IsDisplaySizeBlackListed(physical_size)) {
const float device_scale_factor = GetDeviceScaleFactor();
DCHECK_LE(1.0f, device_scale_factor);
gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels);
@@ -327,14 +327,16 @@ std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
if (!is_connected)
continue;
+ bool is_primary_display = output_id == primary_display_id;
+
if (output_info->crtc) {
gfx::XScopedPtr<XRRCrtcInfo,
gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
crtc(XRRGetCrtcInfo(xdisplay_, resources.get(), output_info->crtc));
int64_t display_id = -1;
- if (!ui::EDIDParserX11(output_id).GetDisplayId(static_cast<uint8_t>(i),
- &display_id)) {
+ if (!display::EDIDParserX11(output_id).GetDisplayId(
+ static_cast<uint8_t>(i), &display_id)) {
// It isn't ideal, but if we can't parse the EDID data, fallback on the
// display number.
display_id = i;
@@ -349,7 +351,9 @@ std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
if (has_work_area) {
gfx::Rect intersection_in_pixels = crtc_bounds;
- intersection_in_pixels.Intersect(work_area_in_pixels);
+ if (is_primary_display) {
+ intersection_in_pixels.Intersect(work_area_in_pixels);
+ }
// SetScaleAndBounds() above does the conversion from pixels to DIP for
// us, but set_work_area does not, so we need to do it here.
display.set_work_area(gfx::Rect(
@@ -374,7 +378,7 @@ std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
break;
}
- if (output_id == primary_display_id)
+ if (is_primary_display)
primary_display_index_ = displays.size();
displays.push_back(display);
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
index 9136f26665e..17c38520e74 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -19,7 +19,7 @@ class Window;
namespace client {
class DragDropClient;
}
-}
+} // namespace aura
namespace gfx {
class ImageSkia;
@@ -95,8 +95,8 @@ class VIEWS_EXPORT DesktopWindowTreeHost {
virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0;
// Sets the shape of the root window. If |native_region| is NULL then the
- // window reverts to rectangular. Takes ownership of |native_region|.
- virtual void SetShape(SkRegion* native_region) = 0;
+ // window reverts to rectangular.
+ virtual void SetShape(std::unique_ptr<SkRegion> native_region) = 0;
virtual void Activate() = 0;
virtual void Deactivate() = 0;
@@ -113,6 +113,7 @@ class VIEWS_EXPORT DesktopWindowTreeHost {
virtual bool IsAlwaysOnTop() const = 0;
virtual void SetVisibleOnAllWorkspaces(bool always_visible) = 0;
+ virtual bool IsVisibleOnAllWorkspaces() const = 0;
// Returns true if the title changed.
virtual bool SetWindowTitle(const base::string16& title) = 0;
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 de96b6309b1..964fe4a0b59 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
@@ -304,35 +304,35 @@ gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const {
return display::win::ScreenWin::ScreenToDIPRect(GetHWND(), pixel_bounds);
}
-void DesktopWindowTreeHostWin::SetShape(SkRegion* native_region) {
- if (native_region) {
- // TODO(wez): This would be a lot simpler if we were passed an SkPath.
- // See crbug.com/410593.
- SkRegion* shape = native_region;
- SkRegion device_region;
- if (display::win::GetDPIScale() > 1.0) {
- shape = &device_region;
- const float& scale = display::win::GetDPIScale();
- std::vector<SkIRect> rects;
- for (SkRegion::Iterator it(*native_region); !it.done(); it.next()) {
- const SkIRect& rect = it.rect();
- SkRect scaled_rect =
- SkRect::MakeLTRB(rect.left() * scale, rect.top() * scale,
- rect.right() * scale, rect.bottom() * scale);
- SkIRect rounded_scaled_rect;
- scaled_rect.roundOut(&rounded_scaled_rect);
- rects.push_back(rounded_scaled_rect);
- }
- if (!rects.empty())
- device_region.setRects(&rects[0], rects.size());
- }
+void DesktopWindowTreeHostWin::SetShape(
+ std::unique_ptr<SkRegion> native_region) {
+ if (!native_region) {
+ message_handler_->SetRegion(nullptr);
+ return;
+ }
- message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*shape));
- } else {
- message_handler_->SetRegion(NULL);
+ // TODO(wez): This would be a lot simpler if we were passed an SkPath.
+ // See crbug.com/410593.
+ SkRegion* shape = native_region.get();
+ SkRegion device_region;
+ const float scale = display::win::ScreenWin::GetScaleFactorForHWND(GetHWND());
+ if (scale > 1.0) {
+ shape = &device_region;
+ std::vector<SkIRect> rects;
+ for (SkRegion::Iterator it(*native_region); !it.done(); it.next()) {
+ const SkIRect& rect = it.rect();
+ SkRect scaled_rect =
+ SkRect::MakeLTRB(rect.left() * scale, rect.top() * scale,
+ rect.right() * scale, rect.bottom() * scale);
+ SkIRect rounded_scaled_rect;
+ scaled_rect.roundOut(&rounded_scaled_rect);
+ rects.push_back(rounded_scaled_rect);
+ }
+ if (!rects.empty())
+ device_region.setRects(&rects[0], rects.size());
}
- delete native_region;
+ message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*shape));
}
void DesktopWindowTreeHostWin::Activate() {
@@ -380,7 +380,11 @@ bool DesktopWindowTreeHostWin::IsAlwaysOnTop() const {
}
void DesktopWindowTreeHostWin::SetVisibleOnAllWorkspaces(bool always_visible) {
- // Windows does not have the concept of workspaces.
+ // Chrome does not yet support Windows 10 desktops.
+}
+
+bool DesktopWindowTreeHostWin::IsVisibleOnAllWorkspaces() const {
+ return false;
}
bool DesktopWindowTreeHostWin::SetWindowTitle(const base::string16& title) {
@@ -928,7 +932,7 @@ void DesktopWindowTreeHostWin::HandleWindowSizeChanging() {
compositor()->DisableSwapUntilResize();
}
-void DesktopWindowTreeHostWin::HandleWindowSizeChanged() {
+void DesktopWindowTreeHostWin::HandleWindowSizeUnchanged() {
// A resize may not have occurred if the window size happened not to have
// changed (can occur on Windows 10 when snapping a window to the side of
// the screen). In that case do a resize to the current size to reenable
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 e71604dd928..884df902ab2 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
@@ -68,7 +68,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
gfx::Rect GetRestoredBounds() const override;
std::string GetWorkspace() const override;
gfx::Rect GetWorkAreaBoundsInScreen() const override;
- void SetShape(SkRegion* native_region) override;
+ void SetShape(std::unique_ptr<SkRegion> native_region) override;
void Activate() override;
void Deactivate() override;
bool IsActive() const override;
@@ -81,6 +81,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void SetAlwaysOnTop(bool always_on_top) override;
bool IsAlwaysOnTop() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
bool SetWindowTitle(const base::string16& title) override;
void ClearNativeFocus() override;
Widget::MoveLoopResult RunMoveLoop(
@@ -195,7 +196,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void PostHandleMSG(UINT message, WPARAM w_param, LPARAM l_param) override;
bool HandleScrollEvent(const ui::ScrollEvent& event) override;
void HandleWindowSizeChanging() override;
- void HandleWindowSizeChanged() override;
+ void HandleWindowSizeUnchanged() override;
void HandleWindowScaleFactorChanged(float window_scale_factor) override;
Widget* GetWidget();
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 82ba30c804f..816faa3f312 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
@@ -32,12 +32,14 @@
#include "ui/base/ime/input_method.h"
#include "ui/base/x/x11_util.h"
#include "ui/base/x/x11_util_internal.h"
+#include "ui/base/x/x11_window_event_manager.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
#include "ui/events/devices/x11/device_list_cache_x11.h"
#include "ui/events/devices/x11/touch_factory_x11.h"
#include "ui/events/event_utils.h"
+#include "ui/events/null_event_targeter.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/geometry/insets.h"
@@ -91,6 +93,7 @@ const char* kAtomsToCache[] = {
"UTF8_STRING",
"WM_DELETE_WINDOW",
"WM_PROTOCOLS",
+ "_NET_ACTIVE_WINDOW",
"_NET_FRAME_EXTENTS",
"_NET_WM_CM_S0",
"_NET_WM_DESKTOP",
@@ -155,6 +158,24 @@ std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) {
return result;
}
+int XI2ModeToXMode(int xi2_mode) {
+ switch (xi2_mode) {
+ case XINotifyNormal:
+ return NotifyNormal;
+ case XINotifyGrab:
+ case XINotifyPassiveGrab:
+ return NotifyGrab;
+ case XINotifyUngrab:
+ case XINotifyPassiveUngrab:
+ return NotifyUngrab;
+ case XINotifyWhileGrabbed:
+ return NotifyWhileGrabbed;
+ default:
+ NOTREACHED();
+ return NotifyNormal;
+ }
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -181,9 +202,14 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
window_parent_(NULL),
custom_window_shape_(false),
urgency_hint_set_(false),
+ has_pointer_grab_(false),
activatable_(true),
- close_widget_factory_(this) {
-}
+ has_pointer_(false),
+ has_window_focus_(false),
+ has_pointer_focus_(false),
+ modal_dialog_xid_(0),
+ close_widget_factory_(this),
+ weak_factory_(this) {}
DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
window()->ClearProperty(kHostForRootWindow);
@@ -230,29 +256,156 @@ gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
return window_shape_.get();
}
-void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
- bool active) {
- if (active) {
+void DesktopWindowTreeHostX11::BeforeActivationStateChanged() {
+ was_active_ = IsActive();
+ had_pointer_ = has_pointer_;
+ had_pointer_grab_ = has_pointer_grab_;
+ had_window_focus_ = has_window_focus_;
+}
+
+void DesktopWindowTreeHostX11::AfterActivationStateChanged() {
+ if (had_pointer_grab_ && !has_pointer_grab_)
+ dispatcher()->OnHostLostMouseGrab();
+
+ bool had_pointer_capture = had_pointer_ || had_pointer_grab_;
+ bool has_pointer_capture = has_pointer_ || has_pointer_grab_;
+ if (had_pointer_capture && !has_pointer_capture)
+ OnHostLostWindowCapture();
+
+ if (!was_active_ && IsActive()) {
FlashFrame(false);
OnHostActivated();
+ // TODO(thomasanderson): Remove this window shuffling and use XWindowCache
+ // instead.
open_windows().remove(xwindow_);
open_windows().insert(open_windows().begin(), xwindow_);
- } else {
- ReleaseCapture();
}
- desktop_native_widget_aura_->HandleActivationChanged(active);
+ if (was_active_ != IsActive()) {
+ desktop_native_widget_aura_->HandleActivationChanged(IsActive());
+ native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
+ }
+}
+
+void DesktopWindowTreeHostX11::OnCrossingEvent(bool enter,
+ bool focus_in_window_or_ancestor,
+ int mode,
+ int detail) {
+ // NotifyInferior on a crossing event means the pointer moved into or out of a
+ // child window, but the pointer is still within |xwindow_|.
+ if (detail == NotifyInferior)
+ return;
+
+ BeforeActivationStateChanged();
+
+ if (mode == NotifyGrab)
+ has_pointer_grab_ = enter;
+ else if (mode == NotifyUngrab)
+ has_pointer_grab_ = false;
+
+ has_pointer_ = enter;
+ if (focus_in_window_or_ancestor && !has_window_focus_) {
+ // If we reach this point, we know the focus is in an ancestor or the
+ // pointer root. The definition of |has_pointer_focus_| is (An ancestor
+ // window or the PointerRoot is focused) && |has_pointer_|. Therefore, we
+ // can just use |has_pointer_| in the assignment. The transitions for when
+ // the focus changes are handled in OnFocusEvent().
+ has_pointer_focus_ = has_pointer_;
+ }
+
+ AfterActivationStateChanged();
+}
+
+void DesktopWindowTreeHostX11::OnFocusEvent(bool focus_in,
+ int mode,
+ int detail) {
+ // NotifyInferior on a focus event means the focus moved into or out of a
+ // child window, but the focus is still within |xwindow_|.
+ if (detail == NotifyInferior)
+ return;
+
+ bool notify_grab = mode == NotifyGrab || mode == NotifyUngrab;
+
+ BeforeActivationStateChanged();
+
+ // For every focus change, the X server sends normal focus events which are
+ // useful for tracking |has_window_focus_|, but supplements these events with
+ // NotifyPointer events which are only useful for tracking pointer focus.
+
+ // For |has_pointer_focus_| and |has_window_focus_|, we continue tracking
+ // state during a grab, but ignore grab/ungrab events themselves.
+ if (!notify_grab && detail != NotifyPointer)
+ has_window_focus_ = focus_in;
+
+ if (!notify_grab && has_pointer_) {
+ switch (detail) {
+ case NotifyAncestor:
+ case NotifyVirtual:
+ // If we reach this point, we know |has_pointer_| was true before and
+ // after this event. Since the definition of |has_pointer_focus_| is
+ // (An ancestor window or the PointerRoot is focused) && |has_pointer_|,
+ // we only need to worry about transitions on the first conjunct.
+ // Therefore, |has_pointer_focus_| will become true when:
+ // 1. Focus moves from |xwindow_| to an ancestor
+ // (FocusOut with NotifyAncestor)
+ // 2. Focus moves from a decendant of |xwindow_| to an ancestor
+ // (FocusOut with NotifyVirtual)
+ // |has_pointer_focus_| will become false when:
+ // 1. Focus moves from an ancestor to |xwindow_|
+ // (FocusIn with NotifyAncestor)
+ // 2. Focus moves from an ancestor to a child of |xwindow_|
+ // (FocusIn with NotifyVirtual)
+ has_pointer_focus_ = !focus_in;
+ break;
+ case NotifyPointer:
+ // The remaining cases for |has_pointer_focus_| becoming true are:
+ // 3. Focus moves from |xwindow_| to the PointerRoot
+ // 4. Focus moves from a decendant of |xwindow_| to the PointerRoot
+ // 5. Focus moves from None to the PointerRoot
+ // 6. Focus moves from Other to the PointerRoot
+ // 7. Focus moves from None to an ancestor of |xwindow_|
+ // 8. Focus moves from Other to an ancestor fo |xwindow_|
+ // In each case, we will get a FocusIn with a detail of NotifyPointer.
+ // The remaining cases for |has_pointer_focus_| becoming false are:
+ // 3. Focus moves from the PointerRoot to |xwindow_|
+ // 4. Focus moves from the PointerRoot to a decendant of |xwindow|
+ // 5. Focus moves from the PointerRoot to None
+ // 6. Focus moves from an ancestor of |xwindow_| to None
+ // 7. Focus moves from the PointerRoot to Other
+ // 8. Focus moves from an ancestor of |xwindow_| to Other
+ // In each case, we will get a FocusOut with a detail of NotifyPointer.
+ has_pointer_focus_ = focus_in;
+ break;
+ case NotifyNonlinear:
+ case NotifyNonlinearVirtual:
+ // We get Nonlinear(Virtual) events when
+ // 1. Focus moves from Other to |xwindow_|
+ // (FocusIn with NotifyNonlinear)
+ // 2. Focus moves from Other to a decendant of |xwindow_|
+ // (FocusIn with NotifyNonlinearVirtual)
+ // 3. Focus moves from |xwindow_| to Other
+ // (FocusOut with NotifyNonlinear)
+ // 4. Focus moves from a decendant of |xwindow_| to Other
+ // (FocusOut with NotifyNonlinearVirtual)
+ // |has_pointer_focus_| should be false before and after this event.
+ has_pointer_focus_ = false;
+ default:
+ break;
+ }
+ }
+
+ ignore_keyboard_input_ = false;
- native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
+ AfterActivationStateChanged();
}
void DesktopWindowTreeHostX11::AddObserver(
- views::DesktopWindowTreeHostObserverX11* observer) {
+ DesktopWindowTreeHostObserverX11* observer) {
observer_list_.AddObserver(observer);
}
void DesktopWindowTreeHostX11::RemoveObserver(
- views::DesktopWindowTreeHostObserverX11* observer) {
+ DesktopWindowTreeHostObserverX11* observer) {
observer_list_.RemoveObserver(observer);
}
@@ -308,8 +461,8 @@ void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
window()->SetProperty(kViewsWindowForRootWindow, content_window_);
window()->SetProperty(kHostForRootWindow, this);
- // Ensure that the X11DesktopHandler exists so that it dispatches activation
- // messages to us.
+ // Ensure that the X11DesktopHandler exists so that it tracks create/destroy
+ // notify events.
X11DesktopHandler::get();
// TODO(erg): Unify this code once the other consumer goes away.
@@ -406,7 +559,7 @@ void DesktopWindowTreeHostX11::ShowWindowWithState(
ui::WindowShowState show_state) {
if (compositor())
compositor()->SetVisible(true);
- if (!window_mapped_)
+ if (!IsVisible())
MapWindow(show_state);
switch (show_state) {
@@ -423,14 +576,6 @@ void DesktopWindowTreeHostX11::ShowWindowWithState(
break;
}
- // Makes the window activated by default if the state is not INACTIVE or
- // MINIMIZED.
- if (show_state != ui::SHOW_STATE_INACTIVE &&
- show_state != ui::SHOW_STATE_MINIMIZED &&
- activatable_) {
- Activate();
- }
-
native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
}
@@ -443,7 +588,7 @@ void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
}
bool DesktopWindowTreeHostX11::IsVisible() const {
- return window_mapped_;
+ return window_mapped_ && !wait_for_unmap_;
}
void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
@@ -568,17 +713,28 @@ gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
}
std::string DesktopWindowTreeHostX11::GetWorkspace() const {
- int workspace_id;
- if (ui::GetIntProperty(xwindow_, "_NET_WM_DESKTOP", &workspace_id))
- return base::IntToString(workspace_id);
- return std::string();
+ if (workspace_.empty())
+ const_cast<DesktopWindowTreeHostX11*>(this)->UpdateWorkspace();
+ return workspace_;
+}
+
+bool DesktopWindowTreeHostX11::UpdateWorkspace() {
+ int workspace_int;
+ if (!ui::GetWindowDesktop(xwindow_, &workspace_int))
+ return false;
+ std::string workspace_str = base::IntToString(workspace_int);
+ if (workspace_ == workspace_str)
+ return false;
+ workspace_ = workspace_str;
+ return true;
}
gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
return ToDIPRect(GetWorkAreaBoundsInPixels());
}
-void DesktopWindowTreeHostX11::SetShape(SkRegion* native_region) {
+void DesktopWindowTreeHostX11::SetShape(
+ std::unique_ptr<SkRegion> native_region) {
custom_window_shape_ = false;
window_shape_.reset();
@@ -598,28 +754,86 @@ void DesktopWindowTreeHostX11::SetShape(SkRegion* native_region) {
}
custom_window_shape_ = true;
- delete native_region;
}
ResetWindowRegion();
}
void DesktopWindowTreeHostX11::Activate() {
- if (!window_mapped_)
+ if (!IsVisible() || !activatable_)
return;
- X11DesktopHandler::get()->ActivateWindow(xwindow_);
+ BeforeActivationStateChanged();
+
+ ignore_keyboard_input_ = false;
+
+ // wmii says that it supports _NET_ACTIVE_WINDOW but does not.
+ // https://code.google.com/p/wmii/issues/detail?id=266
+ static bool wm_supports_active_window =
+ ui::GuessWindowManager() != ui::WM_WMII &&
+ ui::WmSupportsHint(atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"));
+
+ Time timestamp = ui::X11EventSource::GetInstance()->GetTimestamp();
+
+ if (wm_supports_active_window) {
+ XEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+ xclient.type = ClientMessage;
+ xclient.xclient.window = xwindow_;
+ xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
+ xclient.xclient.format = 32;
+ xclient.xclient.data.l[0] = 1; // Specified we are an app.
+ xclient.xclient.data.l[1] = timestamp;
+ // TODO(thomasanderson): if another chrome window is active, specify that in
+ // data.l[2]. The EWMH spec claims this may make the WM more likely to
+ // service our _NET_ACTIVE_WINDOW request.
+ xclient.xclient.data.l[2] = None;
+ xclient.xclient.data.l[3] = 0;
+ xclient.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay_, x_root_window_, False,
+ SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
+ } else {
+ XRaiseWindow(xdisplay_, xwindow_);
+ // Directly ask the X server to give focus to the window. Note that the call
+ // will raise an X error if the window is not mapped.
+ XSetInputFocus(xdisplay_, xwindow_, RevertToParent, timestamp);
+ // At this point, we know we will receive focus, and some tests depend on a
+ // window being IsActive() immediately after an Activate(), so just set this
+ // state now.
+ has_pointer_focus_ = false;
+ has_window_focus_ = true;
+ }
+ AfterActivationStateChanged();
}
void DesktopWindowTreeHostX11::Deactivate() {
- if (!IsActive())
- return;
+ BeforeActivationStateChanged();
+
+ // Ignore future input events.
+ ignore_keyboard_input_ = true;
ReleaseCapture();
- X11DesktopHandler::get()->DeactivateWindow(xwindow_);
+ XLowerWindow(xdisplay_, xwindow_);
+
+ AfterActivationStateChanged();
}
bool DesktopWindowTreeHostX11::IsActive() const {
- return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
+ // Focus and stacking order are independent in X11. Since we cannot guarantee
+ // a window is topmost iff it has focus, just use the focus state to determine
+ // if a window is active. Note that Activate() and Deactivate() change the
+ // stacking order in addition to changing the focus state.
+ bool is_active =
+ (has_window_focus_ || has_pointer_focus_) && !ignore_keyboard_input_;
+
+ // is_active => window_mapped_
+ // !window_mapped_ => !is_active
+ DCHECK(!is_active || window_mapped_);
+
+ // |has_window_focus_| and |has_pointer_focus_| are mutually exclusive.
+ DCHECK(!has_window_focus_ || !has_pointer_focus_);
+
+ return is_active;
}
void DesktopWindowTreeHostX11::Maximize() {
@@ -640,7 +854,7 @@ void DesktopWindowTreeHostX11::Maximize() {
// Some WMs do not respect maximization hints on unmapped windows, so we
// save this one for later too.
- should_maximize_after_map_ = !window_mapped_;
+ should_maximize_after_map_ = !IsVisible();
// When we are in the process of requesting to maximize a window, we can
// accurately keep track of our restored bounds instead of relying on the
@@ -705,6 +919,7 @@ void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
return;
}
+ workspace_ = base::IntToString(kAllDesktops);
XEvent xevent;
memset (&xevent, 0, sizeof (xevent));
xevent.type = ClientMessage;
@@ -721,6 +936,14 @@ void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
&xevent);
}
+bool DesktopWindowTreeHostX11::IsVisibleOnAllWorkspaces() const {
+ // We don't need a check for _NET_WM_STATE_STICKY because that would specify
+ // that the window remain in a fixed position even if the viewport scrolls.
+ // This is different from the type of workspace that's associated with
+ // _NET_WM_DESKTOP.
+ return GetWorkspace() == base::IntToString(kAllDesktops);
+}
+
bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
if (window_title_ == title)
return false;
@@ -735,7 +958,7 @@ bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
reinterpret_cast<const unsigned char*>(utf8str.c_str()),
utf8str.size());
XTextProperty xtp;
- char *c_utf8_str = const_cast<char *>(utf8str.c_str());
+ char* c_utf8_str = const_cast<char*>(utf8str.c_str());
if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1,
XUTF8StringStyle, &xtp) == Success) {
XSetWMName(xdisplay_, xwindow_, &xtp);
@@ -952,7 +1175,7 @@ void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
gfx::Transform DesktopWindowTreeHostX11::GetRootTransform() const {
display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
- if (window_mapped_) {
+ if (IsVisible()) {
aura::Window* win = const_cast<aura::Window*>(window());
display = display::Screen::GetScreen()->GetDisplayNearestWindow(win);
}
@@ -977,9 +1200,8 @@ void DesktopWindowTreeHostX11::ShowImpl() {
}
void DesktopWindowTreeHostX11::HideImpl() {
- if (window_mapped_) {
+ if (IsVisible()) {
XWithdrawWindow(xdisplay_, xwindow_, 0);
- window_mapped_ = false;
wait_for_unmap_ = true;
}
native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
@@ -998,6 +1220,8 @@ void DesktopWindowTreeHostX11::SetBounds(
XWindowChanges changes = {0};
unsigned value_mask = 0;
+ delayed_resize_task_.Cancel();
+
if (size_changed) {
// Update the minimum and maximum sizes in case they have changed.
UpdateMinAndMaxSize();
@@ -1065,7 +1289,9 @@ void DesktopWindowTreeHostX11::SetCapture() {
if (old_capturer)
old_capturer->OnHostLostWindowCapture();
- GrabPointer(xwindow_, true, None);
+ // If the pointer is already in |xwindow_|, we will not get a crossing event
+ // with a mode of NotifyGrab, so we must record the grab state manually.
+ has_pointer_grab_ |= !GrabPointer(xwindow_, true, None);
}
void DesktopWindowTreeHostX11::ReleaseCapture() {
@@ -1075,6 +1301,7 @@ void DesktopWindowTreeHostX11::ReleaseCapture() {
// asynchronous is likely inconsequential.
g_current_capture = NULL;
UngrabPointer();
+ has_pointer_grab_ = false;
OnHostLostWindowCapture();
}
@@ -1135,24 +1362,33 @@ void DesktopWindowTreeHostX11::InitX11Window(
if (swa.override_redirect)
attribute_mask |= CWOverrideRedirect;
- Visual* visual;
- int depth;
- ui::ChooseVisualForWindow(&visual, &depth);
- if (depth == 32) {
- attribute_mask |= CWColormap;
- swa.colormap =
- XCreateColormap(xdisplay_, x_root_window_, visual, AllocNone);
+ bool enable_transparent_visuals;
+ switch (params.opacity) {
+ case Widget::InitParams::OPAQUE_WINDOW:
+ enable_transparent_visuals = false;
+ break;
+ case Widget::InitParams::TRANSLUCENT_WINDOW:
+ enable_transparent_visuals = true;
+ break;
+ case Widget::InitParams::INFER_OPACITY:
+ default:
+ enable_transparent_visuals = params.type == Widget::InitParams::TYPE_DRAG;
+ }
- // x.org will BadMatch if we don't set a border when the depth isn't the
- // same as the parent depth.
- attribute_mask |= CWBorderPixel;
- swa.border_pixel = 0;
+ Visual* visual = CopyFromParent;
+ int depth = CopyFromParent;
+ Colormap colormap = CopyFromParent;
+ ui::XVisualManager::GetInstance()->ChooseVisualForWindow(
+ enable_transparent_visuals, &visual, &depth, &colormap,
+ &use_argb_visual_);
- // A compositing manager is required to support transparency.
- use_argb_visual_ =
- XGetSelectionOwner(xdisplay_, atom_cache_.GetAtom("_NET_WM_CM_S0")) !=
- None;
- }
+ attribute_mask |= CWColormap;
+ swa.colormap = colormap;
+
+ // x.org will BadMatch if we don't set a border when the depth isn't the
+ // same as the parent depth.
+ attribute_mask |= CWBorderPixel;
+ swa.border_pixel = 0;
bounds_in_pixels_ = ToPixelRect(params.bounds);
bounds_in_pixels_.set_size(AdjustSize(bounds_in_pixels_.size()));
@@ -1163,7 +1399,7 @@ void DesktopWindowTreeHostX11::InitX11Window(
depth, InputOutput, visual, attribute_mask, &swa);
if (ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
- open_windows().push_back(xwindow_);
+ open_windows().push_front(xwindow_);
// TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
@@ -1173,7 +1409,7 @@ void DesktopWindowTreeHostX11::InitX11Window(
ExposureMask | VisibilityChangeMask |
StructureNotifyMask | PropertyChangeMask |
PointerMotionMask;
- XSelectInput(xdisplay_, xwindow_, event_mask);
+ xwindow_events_.reset(new ui::XScopedEventSelector(xwindow_, event_mask));
XFlush(xdisplay_);
if (ui::IsXInput2Available())
@@ -1230,6 +1466,7 @@ void DesktopWindowTreeHostX11::InitX11Window(
if (is_always_on_top_)
state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
+ workspace_.clear();
if (params.visible_on_all_workspaces) {
state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
@@ -1402,7 +1639,7 @@ void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
}
void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
- if (!window_mapped_)
+ if (!IsVisible())
return;
gfx::Size minimum_in_pixels =
@@ -1458,7 +1695,6 @@ void DesktopWindowTreeHostX11::UpdateWMUserTime(
PropModeReplace,
reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1);
- X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
}
}
@@ -1546,7 +1782,8 @@ void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
}
void DesktopWindowTreeHostX11::DispatchKeyEvent(ui::KeyEvent* event) {
- GetInputMethod()->DispatchKeyEvent(event);
+ if (native_widget_delegate_->AsWidget()->IsActive())
+ GetInputMethod()->DispatchKeyEvent(event);
}
void DesktopWindowTreeHostX11::ConvertEventToDifferentHost(
@@ -1578,7 +1815,7 @@ void DesktopWindowTreeHostX11::ResetWindowRegion() {
if (!IsMaximized() && !IsFullscreen()) {
gfx::Path window_mask;
- views::Widget* widget = native_widget_delegate_->AsWidget();
+ Widget* widget = native_widget_delegate_->AsWidget();
if (widget->non_client_view()) {
// Some frame views define a custom (non-rectangular) window mask. If
// so, use it to define the window shape. If not, fall through.
@@ -1659,17 +1896,16 @@ void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
// If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
// when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
// http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
- unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
- 0 : X11DesktopHandler::get()->wm_user_time_ms();
+ ignore_keyboard_input_ = show_state == ui::SHOW_STATE_INACTIVE;
+ unsigned long wm_user_time_ms =
+ ignore_keyboard_input_
+ ? 0
+ : ui::X11EventSource::GetInstance()->GetTimestamp();
if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
- XChangeProperty(xdisplay_,
- xwindow_,
- atom_cache_.GetAtom("_NET_WM_USER_TIME"),
- XA_CARDINAL,
- 32,
- PropModeReplace,
- reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
- 1);
+ XChangeProperty(
+ xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_USER_TIME"),
+ XA_CARDINAL, 32, PropModeReplace,
+ reinterpret_cast<const unsigned char*>(&wm_user_time_ms), 1);
}
ui::X11EventSource* event_source = ui::X11EventSource::GetInstance();
@@ -1731,15 +1967,15 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
switch (xev->type) {
case EnterNotify:
case LeaveNotify: {
+ OnCrossingEvent(xev->type == EnterNotify, xev->xcrossing.focus,
+ xev->xcrossing.mode, xev->xcrossing.detail);
+
// Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
// NativeViewGLSurfaceGLX adds a child to |xwindow_|.
- // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
- // necessary. crbug.com/385716
- if (xev->xcrossing.detail == NotifyInferior)
- break;
-
- ui::MouseEvent mouse_event(xev);
- DispatchMouseEvent(&mouse_event);
+ if (xev->xcrossing.detail != NotifyInferior) {
+ ui::MouseEvent mouse_event(xev);
+ DispatchMouseEvent(&mouse_event);
+ }
break;
}
case Expose: {
@@ -1755,8 +1991,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
}
case KeyRelease: {
// There is no way to deactivate a window in X11 so ignore input if
- // window is supposed to be 'inactive'. See comments in
- // X11DesktopHandler::DeactivateWindow() for more details.
+ // window is supposed to be 'inactive'.
if (!IsActive() && !HasCapture())
break;
@@ -1787,17 +2022,10 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
}
break;
}
- case FocusOut:
- if (xev->xfocus.mode != NotifyGrab) {
- ReleaseCapture();
- OnHostLostWindowCapture();
- X11DesktopHandler::get()->ProcessXEvent(xev);
- } else {
- dispatcher()->OnHostLostMouseGrab();
- }
- break;
case FocusIn:
- X11DesktopHandler::get()->ProcessXEvent(xev);
+ case FocusOut:
+ OnFocusEvent(xev->type == FocusIn, event->xfocus.mode,
+ event->xfocus.detail);
break;
case ConfigureNotify: {
DCHECK_EQ(xwindow_, xev->xconfigure.window);
@@ -1838,6 +2066,23 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
if (!factory->ShouldProcessXI2Event(xev))
break;
+ XIEnterEvent* enter_event = static_cast<XIEnterEvent*>(xev->xcookie.data);
+ switch (static_cast<XIEvent*>(xev->xcookie.data)->evtype) {
+ case XI_Enter:
+ case XI_Leave:
+ OnCrossingEvent(enter_event->evtype == XI_Enter, enter_event->focus,
+ XI2ModeToXMode(enter_event->mode),
+ enter_event->detail);
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+ case XI_FocusIn:
+ case XI_FocusOut:
+ OnFocusEvent(enter_event->evtype == XI_FocusIn,
+ XI2ModeToXMode(enter_event->mode), enter_event->detail);
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+ default:
+ break;
+ }
+
ui::EventType type = ui::EventTypeFromNative(xev);
XEvent last_event;
int num_coalesced = 0;
@@ -1919,7 +2164,12 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
break;
}
case UnmapNotify: {
+ window_mapped_ = false;
wait_for_unmap_ = false;
+ has_pointer_ = false;
+ has_pointer_grab_ = false;
+ has_pointer_focus_ = false;
+ has_window_focus_ = false;
FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
observer_list_,
OnWindowUnmapped(xwindow_));
@@ -1996,12 +2246,14 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
}
case PropertyNotify: {
::Atom changed_atom = xev->xproperty.atom;
- if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
+ if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE")) {
OnWMStateUpdated();
- else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
+ } else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS")) {
OnFrameExtentsUpdated();
- else if (changed_atom == atom_cache_.GetAtom("_NET_WM_DESKTOP"))
- OnHostWorkspaceChanged();
+ } else if (changed_atom == atom_cache_.GetAtom("_NET_WM_DESKTOP")) {
+ if (UpdateWorkspace())
+ OnHostWorkspaceChanged();
+ }
break;
}
case SelectionNotify: {
@@ -2053,6 +2305,31 @@ gfx::Rect DesktopWindowTreeHostX11::ToPixelRect(
return gfx::ToEnclosingRect(rect_in_pixels);
}
+XID DesktopWindowTreeHostX11::GetModalDialog() {
+ return modal_dialog_xid_;
+}
+
+std::unique_ptr<base::Closure>
+ DesktopWindowTreeHostX11::DisableEventListening(XID dialog) {
+ DCHECK(dialog);
+ DCHECK(!modal_dialog_xid_);
+ modal_dialog_xid_ = dialog;
+ // ScopedWindowTargeter is used to temporarily replace the event-targeter
+ // with NullEventTargeter to make |dialog| modal.
+ targeter_for_modal_.reset(new aura::ScopedWindowTargeter(window(),
+ std::unique_ptr<ui::EventTargeter>(new ui::NullEventTargeter)));
+
+ return base::MakeUnique<base::Closure>(base::Bind(
+ &DesktopWindowTreeHostX11::EnableEventListening,
+ weak_factory_.GetWeakPtr()));
+}
+
+void DesktopWindowTreeHostX11::EnableEventListening() {
+ DCHECK(modal_dialog_xid_);
+ modal_dialog_xid_ = 0;
+ targeter_for_modal_.reset();
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHost, public:
@@ -2066,7 +2343,7 @@ DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
// static
ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
- const views::LinuxUI* linux_ui = views::LinuxUI::instance();
+ const LinuxUI* linux_ui = LinuxUI::instance();
if (linux_ui) {
ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
if (native_theme)
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 fa262f13528..a4b68b38221 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
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "ui/aura/scoped_window_targeter.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/cursor/cursor_loader_x11.h"
#include "ui/events/platform/platform_event_dispatcher.h"
@@ -32,6 +33,7 @@ class ImageSkiaRep;
namespace ui {
class EventHandler;
+class XScopedEventSelector;
}
namespace views {
@@ -72,12 +74,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// otherwise.
::Region GetWindowShape() const;
- // Called by X11DesktopHandler to notify us that the native windowing system
- // has changed our activation.
- void HandleNativeWidgetActivationChanged(bool active);
-
- void AddObserver(views::DesktopWindowTreeHostObserverX11* observer);
- void RemoveObserver(views::DesktopWindowTreeHostObserverX11* observer);
+ void AddObserver(DesktopWindowTreeHostObserverX11* observer);
+ void RemoveObserver(DesktopWindowTreeHostObserverX11* observer);
// Swaps the current handler for events in the non client view with |handler|.
void SwapNonClientEventHandler(std::unique_ptr<ui::EventHandler> handler);
@@ -86,6 +84,13 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// internal list of open windows.
static void CleanUpWindowList(void (*func)(aura::Window* window));
+ // Disables event listening to make |dialog| modal.
+ std::unique_ptr<base::Closure> DisableEventListening(XID dialog);
+
+ // Returns XID of dialog currently displayed. When it returns 0,
+ // there is no dialog on the host window.
+ XID GetModalDialog();
+
protected:
// Overridden from DesktopWindowTreeHost:
void Init(aura::Window* content_window,
@@ -111,7 +116,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
gfx::Rect GetRestoredBounds() const override;
std::string GetWorkspace() const override;
gfx::Rect GetWorkAreaBoundsInScreen() const override;
- void SetShape(SkRegion* native_region) override;
+ void SetShape(std::unique_ptr<SkRegion> native_region) override;
void Activate() override;
void Deactivate() override;
bool IsActive() const override;
@@ -124,6 +129,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
void SetAlwaysOnTop(bool always_on_top) override;
bool IsAlwaysOnTop() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
bool SetWindowTitle(const base::string16& title) override;
void ClearNativeFocus() override;
Widget::MoveLoopResult RunMoveLoop(
@@ -185,6 +191,27 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
void OnFrameExtentsUpdated();
+ // Record the activation state.
+ void BeforeActivationStateChanged();
+
+ // Handle the state change since BeforeActivationStateChanged().
+ void AfterActivationStateChanged();
+
+ // Called on an XEnterWindowEvent, XLeaveWindowEvent, XIEnterEvent, or an
+ // XILeaveEvent.
+ void OnCrossingEvent(bool enter,
+ bool focus_in_window_or_ancestor,
+ int mode,
+ int detail);
+
+ // Called on an XFocusInEvent, XFocusOutEvent, XIFocusInEvent, or an
+ // XIFocusOutEvent.
+ void OnFocusEvent(bool focus_in, int mode, int detail);
+
+ // Makes a round trip to the X server to get the enclosing workspace for this
+ // window. Returns true iff |workspace_| was changed.
+ bool UpdateWorkspace();
+
// Updates |xwindow_|'s minimum and maximum size.
void UpdateMinAndMaxSize();
@@ -247,11 +274,17 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
gfx::Rect ToDIPRect(const gfx::Rect& rect_in_pixels) const;
gfx::Rect ToPixelRect(const gfx::Rect& rect_in_dip) const;
+ // Enables event listening after closing |dialog|.
+ void EnableEventListening();
+
// X11 things
// The display and the native X window hosting the root window.
XDisplay* xdisplay_;
::Window xwindow_;
+ // Events selected on |xwindow_|.
+ std::unique_ptr<ui::XScopedEventSelector> xwindow_events_;
+
// The native root window.
::Window x_root_window_;
@@ -261,6 +294,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
bool window_mapped_;
// Should we wait for an UnmapNotify before trying to remap the window?
+ // If |wait_for_unmap_| is true, we have sent an XUnmapWindow request to the
+ // server and have yet to receive an UnmapNotify.
bool wait_for_unmap_;
// The bounds of |xwindow_|.
@@ -284,6 +319,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// |xwindow_|'s maximum size.
gfx::Size max_size_in_pixels_;
+ // The workspace containing |xwindow_|.
+ std::string workspace_;
+
// The window manager state bits.
std::set< ::Atom> window_properties_;
@@ -348,11 +386,49 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// the frame when |xwindow_| gains focus or handles a mouse button event.
bool urgency_hint_set_;
+ // Does |xwindow_| have the pointer grab (XI2 or normal)?
+ bool has_pointer_grab_;
+
bool activatable_;
+ // The focus-tracking state variables are as described in
+ // gtk/docs/focus_tracking.txt
+ //
+ // |xwindow_| is active iff:
+ // (|has_window_focus_| || |has_pointer_focus_|) &&
+ // !|ignore_keyboard_input_|
+
+ // Is the pointer in |xwindow_| or one of its children?
+ bool has_pointer_;
+
+ // Is |xwindow_| or one of its children focused?
+ bool has_window_focus_;
+
+ // (An ancestor window or the PointerRoot is focused) && |has_pointer_|.
+ // |has_pointer_focus_| == true is the odd case where we will receive keyboard
+ // input when |has_window_focus_| == false. |has_window_focus_| and
+ // |has_pointer_focus_| are mutually exclusive.
+ bool has_pointer_focus_;
+
+ // X11 does not support defocusing windows; you can only focus a different
+ // window. If we would like to be defocused, we just ignore keyboard input we
+ // no longer care about.
+ bool ignore_keyboard_input_;
+
+ // Used for tracking activation state in {Before|After}ActivationStateChanged.
+ bool was_active_;
+ bool had_pointer_;
+ bool had_pointer_grab_;
+ bool had_window_focus_;
+
base::CancelableCallback<void()> delayed_resize_task_;
+ std::unique_ptr<aura::ScopedWindowTargeter> targeter_for_modal_;
+
+ XID modal_dialog_xid_;
+
base::WeakPtrFactory<DesktopWindowTreeHostX11> close_widget_factory_;
+ base::WeakPtrFactory<DesktopWindowTreeHostX11> weak_factory_;
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 af342ffd29e..117b3868a85 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
@@ -270,6 +270,9 @@ TEST_F(DesktopWindowTreeHostX11Test, InputMethodFocus) {
// widget->GetInputMethod()->GetTextInputType());
widget->Activate();
+ ActivationWaiter waiter(
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+ waiter.Wait();
EXPECT_TRUE(widget->IsActive());
EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
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 52a3827f2bc..5426fe48922 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
@@ -53,10 +53,9 @@ class WMStateWaiter : public X11PropertyChangeWaiter {
: X11PropertyChangeWaiter(window, "_NET_WM_STATE"),
hint_(hint),
wait_till_set_(wait_till_set) {
-
- const char* kAtomsToCache[] = {
+ const char* const kAtomsToCache[] = {
hint,
- NULL
+ nullptr
};
atom_cache_.reset(new ui::X11AtomCache(gfx::GetXDisplay(), kAtomsToCache));
}
@@ -90,7 +89,7 @@ class WMStateWaiter : public X11PropertyChangeWaiter {
// A NonClientFrameView with a window mask with the bottom right corner cut out.
class ShapedNonClientFrameView : public NonClientFrameView {
public:
- explicit ShapedNonClientFrameView() {
+ ShapedNonClientFrameView() {
}
~ShapedNonClientFrameView() override {}
@@ -287,12 +286,12 @@ TEST_F(DesktopWindowTreeHostX11Test, Shape) {
shape2.lineTo(100, 0);
shape2.close();
- SkRegion* shape_region = new SkRegion;
+ auto shape_region = base::MakeUnique<SkRegion>();
shape_region->setPath(shape2, SkRegion(shape2.getBounds().round()));
- std::unique_ptr<Widget> widget2(CreateWidget(NULL));
+ std::unique_ptr<Widget> widget2(CreateWidget(nullptr));
widget2->Show();
- widget2->SetShape(shape_region);
+ widget2->SetShape(std::move(shape_region));
ui::X11EventSource::GetInstance()->DispatchXEvents();
XID xid2 = widget2->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
@@ -346,10 +345,10 @@ TEST_F(DesktopWindowTreeHostX11Test, WindowManagerTogglesFullscreen) {
// Emulate the window manager exiting fullscreen via a window manager
// accelerator key. It should not affect the widget's fullscreen state.
{
- const char* kAtomsToCache[] = {
+ const char* const kAtomsToCache[] = {
"_NET_WM_STATE",
"_NET_WM_STATE_FULLSCREEN",
- NULL
+ nullptr
};
Display* display = gfx::GetXDisplay();
ui::X11AtomCache atom_cache(display, kAtomsToCache);
@@ -397,10 +396,10 @@ TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
// Minimize by sending _NET_WM_STATE_HIDDEN
{
- const char* kAtomsToCache[] = {
+ const char* const kAtomsToCache[] = {
"_NET_WM_STATE",
"_NET_WM_STATE_HIDDEN",
- NULL
+ nullptr
};
ui::X11AtomCache atom_cache(display, kAtomsToCache);
@@ -429,10 +428,10 @@ TEST_F(DesktopWindowTreeHostX11Test, ToggleMinimizePropogateToContentWindow) {
// Show from minimized by sending _NET_WM_STATE_FOCUSED
{
- const char* kAtomsToCache[] = {
+ const char* const kAtomsToCache[] = {
"_NET_WM_STATE",
"_NET_WM_STATE_FOCUSED",
- NULL
+ nullptr
};
ui::X11AtomCache atom_cache(display, kAtomsToCache);
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
index 8ec4b1e7b9a..6f4d6630284 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.cc
@@ -8,20 +8,21 @@
#include <X11/Xlib.h>
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "ui/aura/env.h"
#include "ui/aura/window_event_dispatcher.h"
-#include "ui/base/x/x11_foreign_window_manager.h"
#include "ui/base/x/x11_menu_list.h"
#include "ui/base/x/x11_util.h"
+#include "ui/base/x/x11_window_event_manager.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/x/x11_error_tracker.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
namespace {
-const char* kAtomsToCache[] = {
- "_NET_ACTIVE_WINDOW",
- NULL
+const char* const kAtomsToCache[] = {
+ "_NET_CURRENT_DESKTOP",
+ nullptr
};
// Our global instance. Deleted when our Env() is deleted.
@@ -42,30 +43,14 @@ X11DesktopHandler* X11DesktopHandler::get() {
X11DesktopHandler::X11DesktopHandler()
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
- x_active_window_(None),
- wm_user_time_ms_(CurrentTime),
- current_window_(None),
- current_window_active_state_(NOT_ACTIVE),
- atom_cache_(xdisplay_, kAtomsToCache),
- wm_supports_active_window_(false) {
+ atom_cache_(xdisplay_, kAtomsToCache) {
if (ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
aura::Env::GetInstance()->AddObserver(this);
- XWindowAttributes attr;
- XGetWindowAttributes(xdisplay_, x_root_window_, &attr);
- XSelectInput(xdisplay_, x_root_window_,
- attr.your_event_mask | PropertyChangeMask |
- StructureNotifyMask | SubstructureNotifyMask);
-
- if (ui::GuessWindowManager() == ui::WM_WMII) {
- // wmii says that it supports _NET_ACTIVE_WINDOW but does not.
- // https://code.google.com/p/wmii/issues/detail?id=266
- wm_supports_active_window_ = false;
- } else {
- wm_supports_active_window_ =
- ui::WmSupportsHint(atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"));
- }
+ x_root_window_events_.reset(new ui::XScopedEventSelector(
+ x_root_window_,
+ PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask));
}
X11DesktopHandler::~X11DesktopHandler() {
@@ -74,105 +59,27 @@ X11DesktopHandler::~X11DesktopHandler() {
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
-void X11DesktopHandler::ActivateWindow(::Window window) {
- if ((current_window_ == None || current_window_ == window) &&
- current_window_active_state_ == NOT_ACTIVE) {
- // |window| is most likely still active wrt to the X server. Undo the
- // changes made in DeactivateWindow().
- OnActiveWindowChanged(window, ACTIVE);
-
- // Go through the regular activation path such that calling
- // DeactivateWindow() and ActivateWindow() immediately afterwards results
- // in an active X window.
- }
-
- if (wm_supports_active_window_) {
- DCHECK_EQ(gfx::GetXDisplay(), xdisplay_);
-
- // If the window is not already active, send a hint to activate it
- if (x_active_window_ != window) {
- if (wm_user_time_ms_ == CurrentTime) {
- set_wm_user_time_ms(
- ui::X11EventSource::GetInstance()->UpdateLastSeenServerTime());
- }
- XEvent xclient;
- memset(&xclient, 0, sizeof(xclient));
- xclient.type = ClientMessage;
- xclient.xclient.window = window;
- xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
- xclient.xclient.format = 32;
- xclient.xclient.data.l[0] = 1; // Specified we are an app.
- xclient.xclient.data.l[1] = wm_user_time_ms_;
- xclient.xclient.data.l[2] = None;
- xclient.xclient.data.l[3] = 0;
- xclient.xclient.data.l[4] = 0;
-
- XSendEvent(xdisplay_, x_root_window_, False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- &xclient);
- } else {
- OnActiveWindowChanged(window, ACTIVE);
- }
- } else {
- XRaiseWindow(xdisplay_, window);
- // Directly ask the X server to give focus to the window. Note
- // that the call will raise an X error if the window is not
- // mapped.
- XSetInputFocus(xdisplay_, window, RevertToParent, CurrentTime);
-
- OnActiveWindowChanged(window, ACTIVE);
- }
-}
-
-void X11DesktopHandler::set_wm_user_time_ms(Time time_ms) {
- if (time_ms != CurrentTime) {
- int64_t event_time_64 = time_ms;
- int64_t time_difference = wm_user_time_ms_ - event_time_64;
- // Ignore timestamps that go backwards. However, X server time is a 32-bit
- // millisecond counter, so if the time goes backwards by more than half the
- // range of the 32-bit counter, treat it as a rollover.
- if (time_difference < 0 || time_difference > (UINT32_MAX >> 1))
- wm_user_time_ms_ = time_ms;
- }
+void X11DesktopHandler::AddObserver(X11DesktopHandlerObserver* observer) {
+ observers_.AddObserver(observer);
}
-void X11DesktopHandler::DeactivateWindow(::Window window) {
- if (!IsActiveWindow(window))
- return;
-
- XLowerWindow(xdisplay_, window);
-
- // Per ICCCM: http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
- // "Clients should not give up the input focus of their own volition.
- // They should ignore input that they receive instead."
- //
- // There is nothing else that we can do. Pretend that we have been
- // deactivated and ignore keyboard input in DesktopWindowTreeHostX11.
- OnActiveWindowChanged(window, NOT_ACTIVE);
+void X11DesktopHandler::RemoveObserver(X11DesktopHandlerObserver* observer) {
+ observers_.RemoveObserver(observer);
}
-bool X11DesktopHandler::IsActiveWindow(::Window window) const {
- return window == current_window_ && current_window_active_state_ == ACTIVE;
+std::string X11DesktopHandler::GetWorkspace() {
+ if (workspace_.empty())
+ UpdateWorkspace();
+ return workspace_;
}
-void X11DesktopHandler::ProcessXEvent(XEvent* event) {
- // Ignore focus events that are being sent only because the pointer is over
- // our window, even if the input focus is in a different window.
- if (event->xfocus.detail == NotifyPointer)
- return;
-
- switch (event->type) {
- case FocusIn:
- if (current_window_ != event->xfocus.window)
- OnActiveWindowChanged(event->xfocus.window, ACTIVE);
- break;
- case FocusOut:
- if (current_window_ == event->xfocus.window)
- OnActiveWindowChanged(None, NOT_ACTIVE);
- break;
- default:
- NOTREACHED();
+bool X11DesktopHandler::UpdateWorkspace() {
+ int desktop;
+ if (ui::GetCurrentDesktop(&desktop)) {
+ workspace_ = base::IntToString(desktop);
+ return true;
}
+ return false;
}
bool X11DesktopHandler::CanDispatchEvent(const ui::PlatformEvent& event) {
@@ -184,31 +91,20 @@ bool X11DesktopHandler::CanDispatchEvent(const ui::PlatformEvent& event) {
uint32_t X11DesktopHandler::DispatchEvent(const ui::PlatformEvent& event) {
switch (event->type) {
case PropertyNotify: {
- // Check for a change to the active window.
- CHECK_EQ(x_root_window_, event->xproperty.window);
- ::Atom active_window_atom = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW");
- if (event->xproperty.atom == active_window_atom) {
- ::Window window;
- if (ui::GetXIDProperty(x_root_window_, "_NET_ACTIVE_WINDOW", &window) &&
- window) {
- x_active_window_ = window;
- OnActiveWindowChanged(window, ACTIVE);
- } else {
- x_active_window_ = None;
+ if (event->xproperty.atom ==
+ atom_cache_.GetAtom("_NET_CURRENT_DESKTOP")) {
+ if (UpdateWorkspace()) {
+ FOR_EACH_OBSERVER(views::X11DesktopHandlerObserver, observers_,
+ OnWorkspaceChanged(workspace_));
}
}
break;
}
-
case CreateNotify:
OnWindowCreatedOrDestroyed(event->type, event->xcreatewindow.window);
break;
case DestroyNotify:
OnWindowCreatedOrDestroyed(event->type, event->xdestroywindow.window);
- // If the current active window is being destroyed, reset our tracker.
- if (x_active_window_ == event->xdestroywindow.window) {
- x_active_window_ = None;
- }
break;
default:
NOTREACHED();
@@ -225,30 +121,6 @@ void X11DesktopHandler::OnWillDestroyEnv() {
delete this;
}
-void X11DesktopHandler::OnActiveWindowChanged(::Window xid,
- ActiveState active_state) {
- if (current_window_ == xid && current_window_active_state_ == active_state)
- return;
-
- if (current_window_active_state_ == ACTIVE) {
- DesktopWindowTreeHostX11* old_host =
- views::DesktopWindowTreeHostX11::GetHostForXID(current_window_);
- if (old_host)
- old_host->HandleNativeWidgetActivationChanged(false);
- }
-
- // Update the current window ID to effectively change the active widget.
- current_window_ = xid;
- current_window_active_state_ = active_state;
-
- if (active_state == ACTIVE) {
- DesktopWindowTreeHostX11* new_host =
- views::DesktopWindowTreeHostX11::GetHostForXID(xid);
- if (new_host)
- new_host->HandleNativeWidgetActivationChanged(true);
- }
-}
-
void X11DesktopHandler::OnWindowCreatedOrDestroyed(int event_type,
XID window) {
// Menus created by Chrome can be drag and drop targets. Since they are
@@ -266,11 +138,6 @@ void X11DesktopHandler::OnWindowCreatedOrDestroyed(int event_type,
} else {
ui::XMenuList::GetInstance()->MaybeUnregisterMenu(window);
}
-
- if (event_type == DestroyNotify) {
- // Notify the XForeignWindowManager that |window| has been destroyed.
- ui::XForeignWindowManager::GetInstance()->OnWindowDestroyed(window);
- }
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
index 47a1ff1a7ff..06d78ba8941 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
@@ -13,17 +13,23 @@
#include <vector>
#include "base/macros.h"
+#include "base/observer_list.h"
#include "ui/aura/env_observer.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/views/views_export.h"
+#include "ui/views/widget/desktop_aura/x11_desktop_handler_observer.h"
namespace base {
template <typename T> struct DefaultSingletonTraits;
}
+namespace ui {
+class XScopedEventSelector;
+}
+
namespace views {
// A singleton that owns global objects related to the desktop and listens for
@@ -35,27 +41,12 @@ class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher,
// Returns the singleton handler.
static X11DesktopHandler* get();
- // Gets/sets the X11 server time of the most recent mouse click, touch or
- // key press on a Chrome window.
- int wm_user_time_ms() const { return wm_user_time_ms_; }
- void set_wm_user_time_ms(Time time_ms);
-
- // Sends a request to the window manager to activate |window|.
- // This method should only be called if the window is already mapped.
- void ActivateWindow(::Window window);
+ // Adds/removes X11DesktopHandlerObservers.
+ void AddObserver(X11DesktopHandlerObserver* observer);
+ void RemoveObserver(X11DesktopHandlerObserver* observer);
- // Attempts to get the window manager to deactivate |window| by moving it to
- // the bottom of the stack. Regardless of whether |window| was actually
- // deactivated, sets the window as inactive in our internal state.
- void DeactivateWindow(::Window window);
-
- // Checks if the current active window is |window|.
- bool IsActiveWindow(::Window window) const;
-
- // Processes activation/focus related events. Some of these events are
- // dispatched to the X11 window dispatcher, and not to the X11 root-window
- // dispatcher. The window dispatcher sends these events to here.
- void ProcessXEvent(XEvent* event);
+ // Gets the current workspace ID.
+ std::string GetWorkspace();
// ui::PlatformEventDispatcher
bool CanDispatchEvent(const ui::PlatformEvent& event) override;
@@ -66,44 +57,30 @@ class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher,
void OnWillDestroyEnv() override;
private:
- enum ActiveState {
- ACTIVE,
- NOT_ACTIVE
- };
-
X11DesktopHandler();
~X11DesktopHandler() override;
- // Handles changes in activation.
- void OnActiveWindowChanged(::Window window, ActiveState active_state);
-
// Called when |window| has been created or destroyed. |window| may not be
// managed by Chrome.
void OnWindowCreatedOrDestroyed(int event_type, XID window);
+ // Makes a round trip to the X server to get the current workspace.
+ bool UpdateWorkspace();
+
// The display and the native X window hosting the root window.
XDisplay* xdisplay_;
// The native root window.
::Window x_root_window_;
- // The last known active X window
- ::Window x_active_window_;
-
- // The X11 server time of the most recent mouse click, touch, or key press
- // on a Chrome window.
- Time wm_user_time_ms_;
-
- // The active window according to X11 server.
- ::Window current_window_;
-
- // Whether we should treat |current_window_| as active. In particular, we
- // pretend that a window is deactivated after a call to DeactivateWindow().
- ActiveState current_window_active_state_;
+ // Events selected on x_root_window_.
+ std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_;
ui::X11AtomCache atom_cache_;
- bool wm_supports_active_window_;
+ base::ObserverList<X11DesktopHandlerObserver> observers_;
+
+ std::string workspace_;
DISALLOW_COPY_AND_ASSIGN(X11DesktopHandler);
};
diff --git a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h
new file mode 100644
index 00000000000..252ca213343
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler_observer.h
@@ -0,0 +1,26 @@
+// Copyright 2016 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_HANDLER_OBSERVER_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_X11_DESKTOP_HANDLER_OBSERVER_H_
+
+#include <string>
+
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class VIEWS_EXPORT X11DesktopHandlerObserver {
+ public:
+ // Called when the (platform-specific) workspace ID changes to
+ // |new_workspace|.
+ virtual void OnWorkspaceChanged(const std::string& new_workspace) = 0;
+
+ protected:
+ virtual ~X11DesktopHandlerObserver() {}
+};
+
+} // namespace views
+
+#endif // UI_DISPLAY_DESKTOP_OBSERVER_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 22dc294f8fb..9ca36c2da39 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
@@ -45,7 +45,7 @@ class MinimizeWaiter : public X11PropertyChangeWaiter {
public:
explicit MinimizeWaiter(XID window)
: X11PropertyChangeWaiter(window, "_NET_WM_STATE") {
- const char* kAtomsToCache[] = { "_NET_WM_STATE_HIDDEN", NULL };
+ const char* const kAtomsToCache[] = {"_NET_WM_STATE_HIDDEN", nullptr};
atom_cache_.reset(new ui::X11AtomCache(gfx::GetXDisplay(), kAtomsToCache));
}
@@ -84,7 +84,7 @@ class StackingClientListWaiter : public X11PropertyChangeWaiter {
void Wait() override {
// StackingClientListWaiter may be created after
// _NET_CLIENT_LIST_STACKING already contains |expected_windows|.
- if (!ShouldKeepOnWaiting(NULL))
+ if (!ShouldKeepOnWaiting(nullptr))
return;
X11PropertyChangeWaiter::Wait();
@@ -248,7 +248,7 @@ TEST_F(X11TopmostWindowFinderTest, Basic) {
EXPECT_EQ(window1, FindTopmostLocalProcessWindowAt(150, 150));
EXPECT_EQ(xid2, FindTopmostXWindowAt(250, 150));
- EXPECT_EQ(NULL, FindTopmostLocalProcessWindowAt(250, 150));
+ EXPECT_FALSE(FindTopmostLocalProcessWindowAt(250, 150));
EXPECT_EQ(xid3, FindTopmostXWindowAt(250, 250));
EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(250, 250));
@@ -262,14 +262,12 @@ TEST_F(X11TopmostWindowFinderTest, Basic) {
EXPECT_NE(xid1, FindTopmostXWindowAt(1000, 1000));
EXPECT_NE(xid2, FindTopmostXWindowAt(1000, 1000));
EXPECT_NE(xid3, FindTopmostXWindowAt(1000, 1000));
- EXPECT_EQ(NULL, FindTopmostLocalProcessWindowAt(1000, 1000));
+ EXPECT_FALSE(FindTopmostLocalProcessWindowAt(1000, 1000));
EXPECT_EQ(window1,
FindTopmostLocalProcessWindowWithIgnore(150, 150, window3));
- EXPECT_EQ(NULL,
- FindTopmostLocalProcessWindowWithIgnore(250, 250, window3));
- EXPECT_EQ(NULL,
- FindTopmostLocalProcessWindowWithIgnore(150, 250, window3));
+ EXPECT_FALSE(FindTopmostLocalProcessWindowWithIgnore(250, 250, window3));
+ EXPECT_FALSE(FindTopmostLocalProcessWindowWithIgnore(150, 250, window3));
EXPECT_EQ(window1,
FindTopmostLocalProcessWindowWithIgnore(150, 195, window3));
@@ -320,11 +318,10 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- SkRegion* skregion1 = new SkRegion;
+ auto skregion1 = base::MakeUnique<SkRegion>();
skregion1->op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
skregion1->op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
- // Widget takes ownership of |skregion1|.
- widget1->SetShape(skregion1);
+ widget1->SetShape(std::move(skregion1));
SkRegion skregion2;
skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
@@ -360,10 +357,10 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- SkRegion* skregion1 = new SkRegion;
+ auto skregion1 = base::MakeUnique<SkRegion>();
skregion1->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op);
// Widget takes ownership of |skregion1|.
- widget1->SetShape(skregion1);
+ widget1->SetShape(std::move(skregion1));
XID xids[] = { xid1 };
StackingClientListWaiter stack_waiter(xids, arraysize(xids));
@@ -381,13 +378,12 @@ TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) {
std::unique_ptr<Widget> widget1(
CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- SkRegion* skregion1 = new SkRegion;
+ auto skregion1 = base::MakeUnique<SkRegion>();
skregion1->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op);
- // Widget takes ownership of |skregion1|.
- widget1->SetShape(skregion1);
+ widget1->SetShape(std::move(skregion1));
// Remove the shape - this is now just a normal window.
- widget1->SetShape(NULL);
+ widget1->SetShape(nullptr);
XID xids[] = { xid1 };
StackingClientListWaiter stack_waiter(xids, arraysize(xids));
@@ -415,7 +411,7 @@ TEST_F(X11TopmostWindowFinderTest, Menu) {
CWOverrideRedirect,
&swa);
{
- const char* kAtomsToCache[] = { "_NET_WM_WINDOW_TYPE_MENU", NULL };
+ const char* const kAtomsToCache[] = {"_NET_WM_WINDOW_TYPE_MENU", nullptr};
ui::X11AtomCache atom_cache(gfx::GetXDisplay(), kAtomsToCache);
ui::SetAtomProperty(menu_xid,
"_NET_WM_WINDOW_TYPE",
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
index cbf3f35638c..1258c61c9cd 100644
--- 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
@@ -10,15 +10,19 @@
#include <utility>
#include "base/bind.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.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/x/x11_util.h"
+#include "ui/base/x/x11_window_event_manager.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
@@ -71,6 +75,8 @@ bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
}
uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+
// This method processes all events while the move loop is active.
if (!in_move_loop_)
return ui::POST_DISPATCH_PERFORM_DEFAULT;
@@ -89,7 +95,7 @@ uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& 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::MessageLoopForUI::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&X11WholeScreenMoveLoop::DispatchMouseMovement,
weak_factory_.GetWeakPtr()));
@@ -136,7 +142,7 @@ bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
// restored when the move loop finishes.
initial_cursor_ = source->GetHost()->last_cursor();
- grab_input_window_ = CreateDragInputWindow(gfx::GetXDisplay());
+ CreateDragInputWindow(gfx::GetXDisplay());
// Only grab mouse capture of |grab_input_window_| if |source| does not have
// capture.
@@ -227,6 +233,7 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
// Restore the previous dispatcher.
nested_dispatcher_.reset();
delegate_->OnMoveLoopEnded();
+ grab_input_window_events_.reset();
XDestroyWindow(display, grab_input_window_);
grab_input_window_ = None;
@@ -236,7 +243,6 @@ void X11WholeScreenMoveLoop::EndMoveLoop() {
bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
XDisplay* display = gfx::GetXDisplay();
- XGrabServer(display);
// Pass "owner_events" as false so that X sends all mouse events to
// |grab_input_window_|.
@@ -245,7 +251,6 @@ bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
DLOG(ERROR) << "Grabbing pointer for dragging failed: "
<< ui::GetX11ErrorString(display, ret);
}
- XUngrabServer(display);
XFlush(display);
return ret == GrabSuccess;
}
@@ -259,21 +264,22 @@ void X11WholeScreenMoveLoop::GrabEscKey() {
}
}
-Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
+void X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
XSetWindowAttributes swa;
memset(&swa, 0, sizeof(swa));
- swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
- KeyPressMask | KeyReleaseMask | StructureNotifyMask;
swa.override_redirect = True;
- Window window = XCreateWindow(display,
- DefaultRootWindow(display),
- -100, -100, 10, 10,
- 0, CopyFromParent, InputOnly, CopyFromParent,
- attribute_mask, &swa);
- XMapRaised(display, window);
- ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(window);
- return window;
+ grab_input_window_ = XCreateWindow(display, DefaultRootWindow(display), -100,
+ -100, 10, 10, 0, CopyFromParent, InputOnly,
+ CopyFromParent, attribute_mask, &swa);
+ uint32_t event_mask = ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | KeyPressMask | KeyReleaseMask |
+ StructureNotifyMask;
+ grab_input_window_events_.reset(
+ new ui::XScopedEventSelector(grab_input_window_, event_mask));
+
+ XMapRaised(display, grab_input_window_);
+ ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(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
index c1eb5515ef8..7ab2dfc8cde 100644
--- 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
@@ -27,6 +27,7 @@ class Window;
namespace ui {
class MouseEvent;
class ScopedEventDispatcher;
+class XScopedEventSelector;
}
namespace views {
@@ -58,7 +59,7 @@ class X11WholeScreenMoveLoop : public X11MoveLoop,
void GrabEscKey();
// Creates an input-only window to be used during the drag.
- XID CreateDragInputWindow(XDisplay* display);
+ void CreateDragInputWindow(XDisplay* display);
// Dispatch mouse movement event to |delegate_| in a posted task.
void DispatchMouseMovement();
@@ -79,6 +80,9 @@ class X11WholeScreenMoveLoop : public X11MoveLoop,
// 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_;
diff --git a/chromium/ui/views/widget/drop_helper.h b/chromium/ui/views/widget/drop_helper.h
index 4e740aafe3d..8c2c44fd690 100644
--- a/chromium/ui/views/widget/drop_helper.h
+++ b/chromium/ui/views/widget/drop_helper.h
@@ -7,6 +7,8 @@
#include "base/macros.h"
+#include "ui/views/views_export.h"
+
namespace gfx {
class Point;
} // namespace gfx
@@ -26,7 +28,7 @@ class View;
// DropHelper is intended to be used by a class that interacts with the system
// drag and drop. The system class invokes OnDragOver as the mouse moves,
// then either OnDragExit or OnDrop when the drop is done.
-class DropHelper {
+class VIEWS_EXPORT DropHelper {
public:
explicit DropHelper(View* root_view);
~DropHelper();
diff --git a/chromium/ui/views/widget/focus_manager_event_handler.cc b/chromium/ui/views/widget/focus_manager_event_handler.cc
new file mode 100644
index 00000000000..f87e4381ce2
--- /dev/null
+++ b/chromium/ui/views/widget/focus_manager_event_handler.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 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/focus_manager_event_handler.h"
+
+#include "ui/aura/window.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+FocusManagerEventHandler::FocusManagerEventHandler(Widget* widget,
+ aura::Window* window)
+ : widget_(widget), window_(window) {
+ DCHECK(window_);
+ window_->AddPreTargetHandler(this);
+}
+
+FocusManagerEventHandler::~FocusManagerEventHandler() {
+ window_->RemovePreTargetHandler(this);
+}
+
+void FocusManagerEventHandler::OnKeyEvent(ui::KeyEvent* event) {
+ if (widget_ && widget_->GetFocusManager()->GetFocusedView() &&
+ !widget_->GetFocusManager()->OnKeyEvent(*event)) {
+ event->StopPropagation();
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/focus_manager_event_handler.h b/chromium/ui/views/widget/focus_manager_event_handler.h
new file mode 100644
index 00000000000..fcba5ac2673
--- /dev/null
+++ b/chromium/ui/views/widget/focus_manager_event_handler.h
@@ -0,0 +1,40 @@
+// Copyright 2016 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_FOCUS_MANAGER_EVENT_HANDLER_H_
+#define UI_VIEWS_WIDGET_FOCUS_MANAGER_EVENT_HANDLER_H_
+
+#include "base/macros.h"
+#include "ui/events/event_handler.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+
+class Widget;
+
+// This class forwards KeyEvents to the FocusManager associated with a widget.
+// This allows KeyEvents to be processed before other targets.
+class FocusManagerEventHandler : public ui::EventHandler {
+ public:
+ FocusManagerEventHandler(Widget* widget, aura::Window* window);
+ ~FocusManagerEventHandler() override;
+
+ // Implementation of ui::EventHandler:
+ void OnKeyEvent(ui::KeyEvent* event) override;
+
+ private:
+ Widget* widget_;
+
+ // |window_| is the event target that is associated with this class.
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusManagerEventHandler);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_FOCUS_MANAGER_EVENT_HANDLER_H_
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index a455eddf268..874417b0b86 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -35,6 +35,7 @@
#include "ui/views/drag_utils.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/drop_helper.h"
+#include "ui/views/widget/focus_manager_event_handler.h"
#include "ui/views/widget/native_widget_delegate.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/tooltip_manager_aura.h"
@@ -97,6 +98,23 @@ void NativeWidgetAura::RegisterNativeWidgetForWindow(
window->set_user_data(native_widget);
}
+// static
+void NativeWidgetAura::AssignIconToAuraWindow(aura::Window* window,
+ const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) {
+ if (!window)
+ return;
+
+ if (window_icon.isNull() && app_icon.isNull()) {
+ window->ClearProperty(aura::client::kWindowIconKey);
+ return;
+ }
+
+ window->SetProperty(
+ aura::client::kWindowIconKey,
+ new gfx::ImageSkia(!window_icon.isNull() ? window_icon : app_icon));
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetAura, internal::NativeWidgetPrivate implementation:
@@ -184,6 +202,11 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
aura::client::SetDragDropDelegate(window_, this);
}
+ if (params.type == Widget::InitParams::TYPE_WINDOW) {
+ focus_manager_event_handler_ =
+ base::MakeUnique<FocusManagerEventHandler>(GetWidget(), window_);
+ }
+
aura::client::SetActivationDelegate(window_, this);
window_reorderer_.reset(new WindowReorderer(window_,
@@ -355,7 +378,7 @@ bool NativeWidgetAura::SetWindowTitle(const base::string16& title) {
void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
- // Aura doesn't have window icons.
+ AssignIconToAuraWindow(window_, window_icon, app_icon);
}
void NativeWidgetAura::InitModalType(ui::ModalType modal_type) {
@@ -442,17 +465,9 @@ void NativeWidgetAura::StackAtTop() {
window_->parent()->StackChildAtTop(window_);
}
-void NativeWidgetAura::StackBelow(gfx::NativeView native_view) {
- if (window_ && window_->parent() &&
- window_->parent() == native_view->parent())
- window_->parent()->StackChildBelow(window_, native_view);
-}
-
-void NativeWidgetAura::SetShape(SkRegion* region) {
+void NativeWidgetAura::SetShape(std::unique_ptr<SkRegion> region) {
if (window_)
- window_->layer()->SetAlphaShape(base::WrapUnique(region));
- else
- delete region;
+ window_->layer()->SetAlphaShape(std::move(region));
}
void NativeWidgetAura::Close() {
@@ -562,6 +577,10 @@ void NativeWidgetAura::SetVisibleOnAllWorkspaces(bool always_visible) {
// Not implemented on chromeos or for child widgets.
}
+bool NativeWidgetAura::IsVisibleOnAllWorkspaces() const {
+ return false;
+}
+
void NativeWidgetAura::Maximize() {
if (window_)
window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
@@ -849,6 +868,8 @@ void NativeWidgetAura::OnWindowDestroying(aura::Window* window) {
// If the aura::Window is destroyed, we can no longer show tooltips.
tooltip_manager_.reset();
+
+ focus_manager_event_handler_.reset();
}
void NativeWidgetAura::OnWindowDestroyed(aura::Window* window) {
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
index 8ef32c57e6b..d10746f556f 100644
--- a/chromium/ui/views/widget/native_widget_aura.h
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -30,6 +30,7 @@ class FontList;
namespace views {
class DropHelper;
+class FocusManagerEventHandler;
class TooltipManagerAura;
class WindowReorderer;
@@ -50,6 +51,11 @@ class VIEWS_EXPORT NativeWidgetAura
internal::NativeWidgetPrivate* native_widget,
aura::Window* window);
+ // Assign an icon to aura window.
+ static void AssignIconToAuraWindow(aura::Window* window,
+ const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon);
+
// Overridden from internal::NativeWidgetPrivate:
void InitNativeWidget(const Widget::InitParams& params) override;
void OnWidgetInitDone() override;
@@ -88,8 +94,7 @@ class VIEWS_EXPORT NativeWidgetAura
void SetSize(const gfx::Size& size) override;
void StackAbove(gfx::NativeView native_view) override;
void StackAtTop() override;
- void StackBelow(gfx::NativeView native_view) override;
- void SetShape(SkRegion* shape) override;
+ void SetShape(std::unique_ptr<SkRegion> shape) override;
void Close() override;
void CloseNow() override;
void Show() override;
@@ -103,6 +108,7 @@ class VIEWS_EXPORT NativeWidgetAura
void SetAlwaysOnTop(bool always_on_top) override;
bool IsAlwaysOnTop() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
void Maximize() override;
void Minimize() override;
bool IsMaximized() const override;
@@ -194,8 +200,6 @@ class VIEWS_EXPORT NativeWidgetAura
internal::NativeWidgetDelegate* delegate() { return delegate_; }
private:
- class ActiveWindowObserver;
-
bool IsDocked() const;
void SetInitialFocus(ui::WindowShowState show_state);
@@ -226,6 +230,9 @@ class VIEWS_EXPORT NativeWidgetAura
std::unique_ptr<DropHelper> drop_helper_;
int last_drop_operation_;
+ // Native widget's handler to receive events before the event target.
+ std::unique_ptr<FocusManagerEventHandler> focus_manager_event_handler_;
+
// The following factory is used for calls to close the NativeWidgetAura
// instance.
base::WeakPtrFactory<NativeWidgetAura> close_widget_factory_;
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
index 5e785ec681e..59867c02b54 100644
--- a/chromium/ui/views/widget/native_widget_mac.h
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -25,7 +25,7 @@ class BridgedNativeWidget;
class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
public:
- NativeWidgetMac(internal::NativeWidgetDelegate* delegate);
+ explicit NativeWidgetMac(internal::NativeWidgetDelegate* delegate);
~NativeWidgetMac() override;
// Retrieves the bridge associated with the given NSWindow. Returns null if
@@ -83,8 +83,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
void SetSize(const gfx::Size& size) override;
void StackAbove(gfx::NativeView native_view) override;
void StackAtTop() override;
- void StackBelow(gfx::NativeView native_view) override;
- void SetShape(SkRegion* shape) override;
+ void SetShape(std::unique_ptr<SkRegion> shape) override;
void Close() override;
void CloseNow() override;
void Show() override;
@@ -98,6 +97,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
void SetAlwaysOnTop(bool always_on_top) override;
bool IsAlwaysOnTop() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
+ bool IsVisibleOnAllWorkspaces() const override;
void Maximize() override;
void Minimize() override;
bool IsMaximized() const override;
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index eca39288062..8ddf80139c2 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -8,9 +8,11 @@
#include <utility>
+#import "base/mac/bind_objc_block.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
#import "ui/base/cocoa/window_size_constants.h"
#include "ui/gfx/font_list.h"
@@ -104,6 +106,7 @@ void NativeWidgetMac::OnWindowWillClose() {
// is still a valid pointer, then reset it.
if (bridge_) {
delegate_->OnNativeWidgetDestroying();
+ [GetNativeWindow() setDelegate:nil];
bridge_.reset();
}
delegate_->OnNativeWidgetDestroyed();
@@ -330,11 +333,7 @@ void NativeWidgetMac::StackAtTop() {
NOTIMPLEMENTED();
}
-void NativeWidgetMac::StackBelow(gfx::NativeView native_view) {
- NOTIMPLEMENTED();
-}
-
-void NativeWidgetMac::SetShape(SkRegion* shape) {
+void NativeWidgetMac::SetShape(std::unique_ptr<SkRegion> shape) {
NOTIMPLEMENTED();
}
@@ -367,7 +366,13 @@ void NativeWidgetMac::Close() {
// like -performClose:, first remove the window from AppKit's display
// list to avoid crashes like http://crbug.com/156101.
[window orderOut:nil];
- [window performSelector:@selector(close) withObject:nil afterDelay:0];
+
+ // Many tests assume that base::RunLoop().RunUntilIdle() is always sufficient
+ // to execute a close. However, in rare cases, -performSelector:..afterDelay:0
+ // does not do this. So post a regular task.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindBlock(^{
+ [window close];
+ }));
}
void NativeWidgetMac::CloseNow() {
@@ -455,6 +460,10 @@ void NativeWidgetMac::SetVisibleOnAllWorkspaces(bool always_visible) {
gfx::SetNSWindowVisibleOnAllWorkspaces(GetNativeWindow(), always_visible);
}
+bool NativeWidgetMac::IsVisibleOnAllWorkspaces() const {
+ return false;
+}
+
void NativeWidgetMac::Maximize() {
NOTIMPLEMENTED(); // See IsMaximized().
}
diff --git a/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm b/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm
index 1b37e4bcd9d..8f224aa3776 100644
--- a/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_accessibility_unittest.mm
@@ -14,6 +14,7 @@
#import "ui/accessibility/platform/ax_platform_node_mac.h"
#include "ui/base/ime/text_input_type.h"
#import "ui/gfx/mac/coordinate_conversion.h"
+#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
@@ -168,6 +169,33 @@ TEST_F(NativeWidgetMacAccessibilityTest, PositionAttribute) {
AttributeValueAtMidpoint(NSAccessibilityPositionAttribute));
}
+// Test for NSAccessibilityHelpAttribute.
+TEST_F(NativeWidgetMacAccessibilityTest, HelpAttribute) {
+ Label* label = new Label(base::SysNSStringToUTF16(kTestPlaceholderText));
+ label->SetSize(GetWidgetBounds().size());
+ EXPECT_NSEQ(nil, AttributeValueAtMidpoint(NSAccessibilityHelpAttribute));
+ label->SetTooltipText(base::SysNSStringToUTF16(kTestPlaceholderText));
+ widget()->GetContentsView()->AddChildView(label);
+ EXPECT_NSEQ(kTestPlaceholderText,
+ AttributeValueAtMidpoint(NSAccessibilityHelpAttribute));
+}
+
+// Test for NSAccessibilityWindowAttribute and
+// NSAccessibilityTopLevelUIElementAttribute.
+TEST_F(NativeWidgetMacAccessibilityTest, WindowAndTopLevelUIElementAttributes) {
+ FlexibleRoleTestView* view = new FlexibleRoleTestView(ui::AX_ROLE_GROUP);
+ view->SetSize(GetWidgetBounds().size());
+ widget()->GetContentsView()->AddChildView(view);
+ // Make sure it's |view| in the hit test by checking its accessibility role.
+ EXPECT_EQ(NSAccessibilityGroupRole,
+ AttributeValueAtMidpoint(NSAccessibilityRoleAttribute));
+ EXPECT_NSEQ(widget()->GetNativeWindow(),
+ AttributeValueAtMidpoint(NSAccessibilityWindowAttribute));
+ EXPECT_NSEQ(
+ widget()->GetNativeWindow(),
+ AttributeValueAtMidpoint(NSAccessibilityTopLevelUIElementAttribute));
+}
+
// Tests for accessibility attributes on a views::Textfield.
// TODO(patricialor): Test against Cocoa-provided attributes as well to ensure
// consistency between Cocoa and toolkit-views.
@@ -276,4 +304,38 @@ TEST_F(NativeWidgetMacAccessibilityTest, TextfieldEditableAttributes) {
NSAccessibilityVisibleCharacterRangeAttribute) rangeValue]));
}
+// Test writing accessibility attributes via an accessibility client.
+TEST_F(NativeWidgetMacAccessibilityTest, TextfieldWritableAttributes) {
+ Textfield* textfield = AddChildTextfield(GetWidgetBounds().size());
+
+ // Get the textfield accessibility object.
+ NSPoint midpoint = gfx::ScreenPointToNSPoint(GetWidgetBounds().CenterPoint());
+ id ax_node = [widget()->GetNativeWindow() accessibilityHitTest:midpoint];
+ EXPECT_TRUE(ax_node);
+
+ // Make sure it's the correct accessibility object.
+ id value =
+ [ax_node accessibilityAttributeValue:NSAccessibilityValueAttribute];
+ EXPECT_NSEQ(kTestStringValue, value);
+
+ // Write a new NSAccessibilityValueAttribute.
+ EXPECT_TRUE(
+ [ax_node accessibilityIsAttributeSettable:NSAccessibilityValueAttribute]);
+ [ax_node accessibilitySetValue:kTestPlaceholderText
+ forAttribute:NSAccessibilityValueAttribute];
+ EXPECT_NSEQ(kTestPlaceholderText,
+ AttributeValueAtMidpoint(NSAccessibilityValueAttribute));
+ EXPECT_EQ(base::SysNSStringToUTF16(kTestPlaceholderText), textfield->text());
+
+ // Test a read-only textfield.
+ textfield->SetReadOnly(true);
+ EXPECT_FALSE(
+ [ax_node accessibilityIsAttributeSettable:NSAccessibilityValueAttribute]);
+ [ax_node accessibilitySetValue:kTestStringValue
+ forAttribute:NSAccessibilityValueAttribute];
+ EXPECT_NSEQ(kTestPlaceholderText,
+ AttributeValueAtMidpoint(NSAccessibilityValueAttribute));
+ EXPECT_EQ(base::SysNSStringToUTF16(kTestPlaceholderText), textfield->text());
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index c8124a9dec4..0dec9ded500 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -6,14 +6,12 @@
#import <Cocoa/Cocoa.h>
-#include "base/location.h"
#import "base/mac/foundation_util.h"
-#import "base/mac/scoped_nsobject.h"
#import "base/mac/scoped_nsautorelease_pool.h"
+#import "base/mac/scoped_nsobject.h"
#import "base/mac/scoped_objc_class_swizzler.h"
#include "base/macros.h"
#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_timeouts.h"
@@ -260,6 +258,29 @@ class SimpleBubbleView : public BubbleDialogDelegateView {
DISALLOW_COPY_AND_ASSIGN(SimpleBubbleView);
};
+class CustomTooltipView : public View {
+ public:
+ CustomTooltipView(const base::string16& tooltip, View* tooltip_handler)
+ : tooltip_(tooltip), tooltip_handler_(tooltip_handler) {}
+
+ // View:
+ bool GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const override {
+ *tooltip = tooltip_;
+ return true;
+ }
+
+ View* GetTooltipHandlerForPoint(const gfx::Point& point) override {
+ return tooltip_handler_ ? tooltip_handler_ : this;
+ }
+
+ private:
+ base::string16 tooltip_;
+ View* tooltip_handler_; // Weak
+
+ DISALLOW_COPY_AND_ASSIGN(CustomTooltipView);
+};
+
// Test visibility states triggered externally.
TEST_F(NativeWidgetMacTest, HideAndShowExternally) {
Widget* widget = CreateTopLevelPlatformWidget();
@@ -419,10 +440,10 @@ TEST_F(NativeWidgetMacTest, DISABLED_OrderFrontAfterMiniaturize) {
// Wait and check that child is really visible.
// TODO(kirr): remove the fixed delay.
- base::MessageLoop::current()->PostDelayedTask(
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
base::TimeDelta::FromSeconds(2));
- base::MessageLoop::current()->Run();
+ base::RunLoop().Run();
EXPECT_FALSE(widget->IsMinimized());
EXPECT_TRUE(widget->IsVisible());
@@ -809,6 +830,43 @@ TEST_F(NativeWidgetMacTest, Tooltips) {
widget->CloseNow();
}
+// Tests case when mouse events are handled in one Widget,
+// but tooltip belongs to another.
+// It happens in menus when a submenu is shown and the parent gets the
+// MouseExit event.
+TEST_F(NativeWidgetMacTest, TwoWidgetTooltips) {
+ // Init two widgets, one above another.
+ Widget* widget_below = CreateTopLevelPlatformWidget();
+ widget_below->SetBounds(gfx::Rect(50, 50, 200, 200));
+
+ Widget* widget_above =
+ CreateChildPlatformWidget(widget_below->GetNativeView());
+ widget_above->SetBounds(gfx::Rect(100, 0, 100, 200));
+
+ const base::string16 tooltip_above = base::ASCIIToUTF16("Front");
+ CustomTooltipView* view_above = new CustomTooltipView(tooltip_above, nullptr);
+ view_above->SetBoundsRect(widget_above->GetContentsView()->bounds());
+ widget_above->GetContentsView()->AddChildView(view_above);
+
+ CustomTooltipView* view_below =
+ new CustomTooltipView(base::ASCIIToUTF16("Back"), view_above);
+ view_below->SetBoundsRect(widget_below->GetContentsView()->bounds());
+ widget_below->GetContentsView()->AddChildView(view_below);
+
+ widget_below->Show();
+ widget_above->Show();
+
+ // Move mouse above second widget and check that it returns tooltip
+ // for second. Despite that event was handled in the first one.
+ ui::test::EventGenerator event_generator(GetContext(),
+ widget_below->GetNativeWindow());
+ event_generator.MoveMouseTo(gfx::Point(120, 60));
+ EXPECT_EQ(tooltip_above, TooltipTextForWidget(widget_below));
+
+ widget_above->CloseNow();
+ widget_below->CloseNow();
+}
+
namespace {
// Delegate to make Widgets of a provided ui::ModalType.
@@ -1318,6 +1376,42 @@ TEST_F(NativeWidgetMacTest, InvalidateShadow) {
test_api.SimulateFrameSwap(gfx::Size(123, 456));
EXPECT_EQ(2, [window invalidateShadowCount]);
+ // Hiding the window does not require shadow invalidation.
+ widget->Hide();
+ test_api.SimulateFrameSwap(gfx::Size(123, 456));
+ EXPECT_EQ(2, [window invalidateShadowCount]);
+
+ // Showing a translucent window after hiding it, should trigger shadow
+ // invalidation.
+ widget->Show();
+ test_api.SimulateFrameSwap(gfx::Size(123, 456));
+ EXPECT_EQ(3, [window invalidateShadowCount]);
+
+ widget->CloseNow();
+}
+
+// Test that the contentView opacity corresponds to the window type.
+TEST_F(NativeWidgetMacTest, ContentOpacity) {
+ NativeWidgetMacTestWindow* window;
+ Widget::InitParams init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+
+ EXPECT_EQ(init_params.opacity, Widget::InitParams::INFER_OPACITY);
+ Widget* widget = CreateWidgetWithTestWindow(init_params, &window);
+
+ // Infer should default to opaque on Mac.
+ EXPECT_TRUE([[window contentView] isOpaque]);
+ widget->CloseNow();
+
+ init_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
+ widget = CreateWidgetWithTestWindow(init_params, &window);
+ EXPECT_FALSE([[window contentView] isOpaque]);
+ widget->CloseNow();
+
+ // Test opaque explicitly.
+ init_params.opacity = Widget::InitParams::OPAQUE_WINDOW;
+ widget = CreateWidgetWithTestWindow(init_params, &window);
+ EXPECT_TRUE([[window contentView] isOpaque]);
widget->CloseNow();
}
diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h
index 39d31b608fc..71b44c40468 100644
--- a/chromium/ui/views/widget/native_widget_private.h
+++ b/chromium/ui/views/widget/native_widget_private.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_
#define UI_VIEWS_WIDGET_NATIVE_WIDGET_PRIVATE_H_
+#include <memory>
#include <string>
#include "base/strings/string16.h"
@@ -176,8 +177,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual void SetSize(const gfx::Size& size) = 0;
virtual void StackAbove(gfx::NativeView native_view) = 0;
virtual void StackAtTop() = 0;
- virtual void StackBelow(gfx::NativeView native_view) = 0;
- virtual void SetShape(SkRegion* shape) = 0;
+ virtual void SetShape(std::unique_ptr<SkRegion> shape) = 0;
virtual void Close() = 0;
virtual void CloseNow() = 0;
virtual void Show() = 0;
@@ -193,6 +193,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual void SetAlwaysOnTop(bool always_on_top) = 0;
virtual bool IsAlwaysOnTop() const = 0;
virtual void SetVisibleOnAllWorkspaces(bool always_visible) = 0;
+ virtual bool IsVisibleOnAllWorkspaces() const = 0;
virtual void Maximize() = 0;
virtual void Minimize() = 0;
virtual bool IsMaximized() const = 0;
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index 62b4b566809..68e6acd9c8a 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -553,12 +553,8 @@ void Widget::StackAtTop() {
native_widget_->StackAtTop();
}
-void Widget::StackBelow(gfx::NativeView native_view) {
- native_widget_->StackBelow(native_view);
-}
-
-void Widget::SetShape(SkRegion* shape) {
- native_widget_->SetShape(shape);
+void Widget::SetShape(std::unique_ptr<SkRegion> shape) {
+ native_widget_->SetShape(std::move(shape));
}
void Widget::Close() {
@@ -666,6 +662,10 @@ void Widget::SetVisibleOnAllWorkspaces(bool always_visible) {
native_widget_->SetVisibleOnAllWorkspaces(always_visible);
}
+bool Widget::IsVisibleOnAllWorkspaces() const {
+ return native_widget_->IsVisibleOnAllWorkspaces();
+}
+
void Widget::Maximize() {
native_widget_->Maximize();
}
@@ -1206,7 +1206,14 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) {
}
if (root_view)
root_view->OnMouseReleased(*event);
- if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0)
+ if ((event->flags() & ui::EF_IS_NON_CLIENT) == 0 &&
+ // If none of the "normal" buttons are pressed, this event may be from
+ // one of the newer mice that have buttons bound to browser forward
+ // back actions. Don't squelch the event and let the default handler
+ // process it.
+ (event->flags() &
+ (ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON |
+ ui::EF_RIGHT_MOUSE_BUTTON)) != 0)
event->SetHandled();
return;
@@ -1452,7 +1459,7 @@ void Widget::SetInitialBoundsForFramelessWindow(const gfx::Rect& bounds) {
native_widget_->CenterWindow(size);
} else {
// Use the supplied initial bounds.
- SetBoundsConstrained(bounds);
+ SetBounds(bounds);
}
}
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index 0376866fc25..06c8f12a46c 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -8,7 +8,6 @@
#include <map>
#include <memory>
#include <set>
-#include <stack>
#include <string>
#include <vector>
@@ -49,10 +48,6 @@ class Point;
class Rect;
}
-namespace mus {
-class Window;
-}
-
namespace ui {
class Accelerator;
class Compositor;
@@ -62,7 +57,8 @@ class Layer;
class NativeTheme;
class OSExchangeData;
class ThemeProvider;
-}
+class Window;
+} // namespace ui
namespace views {
@@ -170,12 +166,15 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
enum WindowOpacity {
// Infer fully opaque or not. For WinAura, top-level windows that are not
- // of TYPE_WINDOW are translucent so that they can be made to fade in. In
- // all other cases, windows are fully opaque.
+ // of TYPE_WINDOW are translucent so that they can be made to fade in.
+ // For LinuxAura, only windows that are TYPE_DRAG are translucent. In all
+ // other cases, windows are fully opaque.
INFER_OPACITY,
// Fully opaque.
OPAQUE_WINDOW,
- // Possibly translucent/transparent.
+ // Possibly translucent/transparent. Widgets that fade in or out using
+ // SetOpacity() but do not make use of an alpha channel should use
+ // INFER_OPACITY.
TRANSLUCENT_WINDOW,
};
@@ -245,7 +244,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
ui::WindowShowState show_state;
gfx::NativeView parent;
// Used only by mus and is necessitated by mus not being a NativeView.
- mus::Window* parent_mus = nullptr;
+ ui::Window* parent_mus = nullptr;
// Specifies the initial bounds of the Widget. Default is empty, which means
// the NativeWidget may specify a default size. If the parent is specified,
// |bounds| is in the parent's coordinate system. If the parent is not
@@ -475,12 +474,9 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
void StackAbove(gfx::NativeView native_view);
void StackAtTop();
- // Places the widget below the specified NativeView.
- void StackBelow(gfx::NativeView native_view);
-
// Sets a shape on the widget. Passing a NULL |shape| reverts the widget to
- // be rectangular. Takes ownership of |shape|.
- void SetShape(SkRegion* shape);
+ // be rectangular.
+ void SetShape(std::unique_ptr<SkRegion> shape);
// Hides the widget then closes it after a return to the message loop.
virtual void Close();
@@ -524,6 +520,12 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Sets the widget to be visible on all work spaces.
void SetVisibleOnAllWorkspaces(bool always_visible);
+ // Is this widget currently visible on all workspaces?
+ // A call to SetVisibleOnAllWorkspaces(true) won't necessarily mean
+ // IsVisbleOnAllWorkspaces() == true (for example, when the platform doesn't
+ // support workspaces).
+ bool IsVisibleOnAllWorkspaces() const;
+
// Maximizes/minimizes/restores the window.
void Maximize();
void Minimize();
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index c5f9d97490c..917124976c4 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -79,11 +79,7 @@ bool WidgetDelegate::ShouldShowWindowTitle() const {
}
bool WidgetDelegate::ShouldShowCloseButton() const {
-#if defined(OS_MACOSX)
- return false;
-#else
return true;
-#endif
}
bool WidgetDelegate::ShouldHandleSystemCommands() const {
@@ -208,6 +204,10 @@ const Widget* WidgetDelegateView::GetWidget() const {
return View::GetWidget();
}
+views::View* WidgetDelegateView::GetContentsView() {
+ return this;
+}
+
const char* WidgetDelegateView::GetClassName() const {
return kViewClassName;
}
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index 8a344c55623..2ce16e971af 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -211,6 +211,7 @@ class VIEWS_EXPORT WidgetDelegateView : public WidgetDelegate, public View {
void DeleteDelegate() override;
Widget* GetWidget() override;
const Widget* GetWidget() const override;
+ views::View* GetContentsView() override;
// View:
const char* GetClassName() const override;
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index 45ea0283446..f7b3e691bfa 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -7,7 +7,6 @@
#include <set>
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -48,11 +47,6 @@
#include "base/mac/mac_util.h"
#endif
-#if defined(USE_X11) && !defined(OS_CHROMEOS)
-#include "ui/base/x/x11_util_internal.h" // nogncheck
-#include "ui/gfx/x/x11_switches.h" // nogncheck
-#endif
-
namespace views {
namespace test {
@@ -935,11 +929,7 @@ TEST_F(WidgetObserverTest, WidgetBoundsChangedNative) {
// Move, but don't change the size.
widget->SetBounds(gfx::Rect(110, 110, 170, 100));
- // Currently fails on Mus. http://crbug.com/622575.
- if (IsMus())
- EXPECT_FALSE(widget_bounds_changed());
- else
- EXPECT_TRUE(widget_bounds_changed());
+ EXPECT_TRUE(widget_bounds_changed());
reset();
// Moving to the same place does nothing.
@@ -1996,8 +1986,6 @@ class GetNativeThemeFromDestructorView : public WidgetDelegateView {
GetNativeThemeFromDestructorView() {}
~GetNativeThemeFromDestructorView() override { VerifyNativeTheme(); }
- View* GetContentsView() override { return this; }
-
private:
void VerifyNativeTheme() {
ASSERT_TRUE(GetNativeTheme() != NULL);
@@ -2088,6 +2076,7 @@ class WidgetBoundsObserver : public WidgetObserver {
// WidgetObserver:
void OnWidgetDestroying(Widget* widget) override {
EXPECT_TRUE(widget->GetNativeWindow());
+ EXPECT_TRUE(Widget::GetWidgetForNativeWindow(widget->GetNativeWindow()));
bounds_ = widget->GetWindowBoundsInScreen();
}
@@ -3640,6 +3629,8 @@ TEST_F(WidgetTest, WidgetRemovalsObserverCalledWhenMovingBetweenWidgets) {
#if defined(OS_WIN)
+namespace {
+
// Provides functionality to create a window modal dialog.
class ModalDialogDelegate : public DialogDelegateView {
public:
@@ -3655,6 +3646,8 @@ private:
DISALLOW_COPY_AND_ASSIGN(ModalDialogDelegate);
};
+} // namespace
+
// Tests the case where an intervening owner popup window is destroyed out from
// under the currently active modal top-level window. In this instance, the
// remaining top-level windows should be re-enabled.
@@ -3743,16 +3736,6 @@ void InitializeWidgetForOpacity(
Widget& widget,
Widget::InitParams init_params,
const Widget::InitParams::WindowOpacity opacity) {
-#if defined(USE_X11)
- // On Linux, transparent visuals is currently not activated by default.
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- command_line->AppendSwitch(switches::kEnableTransparentVisuals);
-
- int depth = 0;
- ui::ChooseVisualForWindow(NULL, &depth);
- EXPECT_EQ(depth, 32);
-#endif
-
init_params.opacity = opacity;
init_params.show_state = ui::SHOW_STATE_NORMAL;
init_params.bounds = gfx::Rect(0, 0, 500, 500);
@@ -3760,31 +3743,79 @@ void InitializeWidgetForOpacity(
init_params.native_widget =
CreatePlatformDesktopNativeWidgetImpl(init_params, &widget, nullptr);
widget.Init(init_params);
+}
+
+class CompositingWidgetTest : public views::test::WidgetTest {
+ public:
+ CompositingWidgetTest()
+ : widget_types_{Widget::InitParams::TYPE_WINDOW,
+ Widget::InitParams::TYPE_PANEL,
+ Widget::InitParams::TYPE_WINDOW_FRAMELESS,
+ Widget::InitParams::TYPE_CONTROL,
+ Widget::InitParams::TYPE_POPUP,
+ Widget::InitParams::TYPE_MENU,
+ Widget::InitParams::TYPE_TOOLTIP,
+ Widget::InitParams::TYPE_BUBBLE,
+ Widget::InitParams::TYPE_DRAG} {}
+ ~CompositingWidgetTest() override {}
+
+ void CheckAllWidgetsForOpacity(
+ const Widget::InitParams::WindowOpacity opacity) {
+ for (const auto& widget_type : widget_types_) {
+#if defined(OS_MACOSX)
+ // Tooltips are native on Mac. See BridgedNativeWidget::Init.
+ if (widget_type == Widget::InitParams::TYPE_TOOLTIP)
+ continue;
+#elif defined(OS_WIN)
+ // Other widget types would require to create a parent window and the
+ // the purpose of this test is mainly X11 in the first place.
+ if (widget_type != Widget::InitParams::TYPE_WINDOW)
+ continue;
+#endif
+ Widget widget;
+ InitializeWidgetForOpacity(widget, CreateParams(widget_type), opacity);
+
+ // Use NativeWidgetAura directly.
+ if (IsMus() &&
+ (widget_type == Widget::InitParams::TYPE_WINDOW_FRAMELESS ||
+ widget_type == Widget::InitParams::TYPE_CONTROL))
+ continue;
+
+ EXPECT_EQ(IsNativeWindowTransparent(widget.GetNativeWindow()),
+ widget.ShouldWindowContentsBeTransparent());
+
+ // When using the Mandoline UI Service, the translucency does not rely on
+ // the widget type.
+ if (IsMus())
+ continue;
#if defined(USE_X11)
- EXPECT_TRUE(widget.IsTranslucentWindowOpacitySupported());
+ if (HasCompositingManager() &&
+ (widget_type == Widget::InitParams::TYPE_DRAG ||
+ widget_type == Widget::InitParams::TYPE_WINDOW)) {
+ EXPECT_TRUE(widget.IsTranslucentWindowOpacitySupported());
+ } else {
+ EXPECT_FALSE(widget.IsTranslucentWindowOpacitySupported());
+ }
#endif
-}
+ }
+ }
+
+ protected:
+ const std::vector<Widget::InitParams::Type> widget_types_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositingWidgetTest);
+};
} // namespace
// Test opacity when compositing is enabled.
-TEST_F(WidgetTest, Transparency_DesktopWidgetInferOpacity) {
- Widget widget;
- InitializeWidgetForOpacity(widget,
- CreateParams(Widget::InitParams::TYPE_WINDOW),
- Widget::InitParams::INFER_OPACITY);
- EXPECT_EQ(IsNativeWindowTransparent(widget.GetNativeWindow()),
- widget.ShouldWindowContentsBeTransparent());
+TEST_F(CompositingWidgetTest, Transparency_DesktopWidgetInferOpacity) {
+ CheckAllWidgetsForOpacity(Widget::InitParams::INFER_OPACITY);
}
-TEST_F(WidgetTest, Transparency_DesktopWidgetOpaque) {
- Widget widget;
- InitializeWidgetForOpacity(widget,
- CreateParams(Widget::InitParams::TYPE_WINDOW),
- Widget::InitParams::OPAQUE_WINDOW);
- EXPECT_EQ(IsNativeWindowTransparent(widget.GetNativeWindow()),
- widget.ShouldWindowContentsBeTransparent());
+TEST_F(CompositingWidgetTest, Transparency_DesktopWidgetOpaque) {
+ CheckAllWidgetsForOpacity(Widget::InitParams::OPAQUE_WINDOW);
}
// Failing on Mac. http://cbrug.com/623421
@@ -3795,13 +3826,8 @@ TEST_F(WidgetTest, Transparency_DesktopWidgetOpaque) {
#define MAYBE_Transparency_DesktopWidgetTranslucent \
Transparency_DesktopWidgetTranslucent
#endif
-TEST_F(WidgetTest, MAYBE_Transparency_DesktopWidgetTranslucent) {
- Widget widget;
- InitializeWidgetForOpacity(widget,
- CreateParams(Widget::InitParams::TYPE_WINDOW),
- Widget::InitParams::TRANSLUCENT_WINDOW);
- EXPECT_EQ(IsNativeWindowTransparent(widget.GetNativeWindow()),
- widget.ShouldWindowContentsBeTransparent());
+TEST_F(CompositingWidgetTest, MAYBE_Transparency_DesktopWidgetTranslucent) {
+ CheckAllWidgetsForOpacity(Widget::InitParams::TRANSLUCENT_WINDOW);
}
#endif // !defined(OS_CHROMEOS)
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index b035fd32716..020d0a1f9e0 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -29,6 +29,7 @@
#include "ui/base/win/shell.h"
#include "ui/base/win/touch_input.h"
#include "ui/display/win/dpi.h"
+#include "ui/display/win/screen_win.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/keyboard_code_conversion_win.h"
@@ -221,14 +222,6 @@ bool IsTopLevelWindow(HWND window) {
return !parent || (parent == ::GetDesktopWindow());
}
-void AddScrollStylesToWindow(HWND window) {
- if (::IsWindow(window)) {
- long current_style = ::GetWindowLong(window, GWL_STYLE);
- ::SetWindowLong(window, GWL_STYLE,
- current_style | WS_VSCROLL | WS_HSCROLL);
- }
-}
-
const int kTouchDownContextResetTimeout = 500;
// Windows does not flag synthesized mouse messages from touch in all cases.
@@ -322,6 +315,7 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
restored_enabled_(false),
current_cursor_(NULL),
previous_cursor_(NULL),
+ dpi_(0),
active_mouse_tracking_flags_(0),
is_right_mouse_pressed_on_caption_(false),
lock_updates_count_(0),
@@ -330,7 +324,6 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
is_first_nccalc_(true),
menu_depth_(0),
id_generator_(0),
- needs_scroll_styles_(false),
in_size_loop_(false),
touch_down_contexts_(0),
last_mouse_hwheel_time_(0),
@@ -355,28 +348,20 @@ void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) {
// Create the window.
WindowImpl::Init(parent, bounds);
- // TODO(ananta)
- // Remove the scrolling hack code once we have scrolling working well.
-#if defined(ENABLE_SCROLL_HACK)
- // Certain trackpad drivers on Windows have bugs where in they don't generate
- // WM_MOUSEWHEEL messages for the trackpoint and trackpad scrolling gestures
- // unless there is an entry for Chrome with the class name of the Window.
- // These drivers check if the window under the trackpoint has the WS_VSCROLL/
- // WS_HSCROLL style and if yes they generate the legacy WM_VSCROLL/WM_HSCROLL
- // messages. We add these styles to ensure that trackpad/trackpoint scrolling
- // work.
- // TODO(ananta)
- // Look into moving the WS_VSCROLL and WS_HSCROLL style setting logic to the
- // CalculateWindowStylesFromInitParams function. Doing it there seems to
- // cause some interactive tests to fail. Investigation needed.
- if (IsTopLevelWindow(hwnd())) {
- long current_style = ::GetWindowLong(hwnd(), GWL_STYLE);
- if (!(current_style & WS_POPUP)) {
- AddScrollStylesToWindow(hwnd());
- needs_scroll_styles_ = true;
- }
+
+ if (delegate_->HasFrame() && base::win::IsProcessPerMonitorDpiAware()) {
+ static auto enable_child_window_dpi_message_func = []() {
+ // Derived signature; not available in headers.
+ // This call gets Windows to scale the non-client area when WM_DPICHANGED
+ // is fired.
+ using EnableChildWindowDpiMessagePtr = LRESULT (WINAPI*)(HWND, BOOL);
+ return reinterpret_cast<EnableChildWindowDpiMessagePtr>(
+ GetProcAddress(GetModuleHandle(L"user32.dll"),
+ "EnableChildWindowDpiMessage"));
+ }();
+ if (enable_child_window_dpi_message_func)
+ enable_child_window_dpi_message_func(hwnd(), TRUE);
}
-#endif
prop_window_target_.reset(new ui::ViewProp(hwnd(),
ui::WindowEventTarget::kWin32InputEventTarget,
@@ -801,8 +786,7 @@ void HWNDMessageHandler::SetCursor(HCURSOR cursor) {
}
void HWNDMessageHandler::FrameTypeChanged() {
- if (!custom_window_region_.is_valid() &&
- delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN)
+ if (!custom_window_region_.is_valid() && IsFrameSystemDrawn())
dwm_transition_desired_ = true;
if (!dwm_transition_desired_ || !IsFullscreen())
PerformDwmTransition();
@@ -1132,6 +1116,9 @@ void HWNDMessageHandler::ClientAreaSizeChanged() {
return;
gfx::Size s = GetClientAreaBounds().size();
delegate_->HandleClientSizeChanged(s);
+
+ current_window_size_message_++;
+ sent_window_size_changing_ = false;
}
bool HWNDMessageHandler::GetClientAreaInsets(gfx::Insets* insets) const {
@@ -1168,8 +1155,7 @@ void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) {
// the delegate to allow for a custom hit mask.
if ((window_ex_style() & WS_EX_COMPOSITED) == 0 &&
!custom_window_region_.is_valid() &&
- (delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN ||
- !delegate_->HasNonClientView())) {
+ (IsFrameSystemDrawn() || !delegate_->HasNonClientView())) {
if (force)
SetWindowRgn(hwnd(), NULL, redraw);
return;
@@ -1275,9 +1261,14 @@ void HWNDMessageHandler::ForceRedrawWindow(int attempts) {
InvalidateRect(hwnd(), NULL, FALSE);
}
+bool HWNDMessageHandler::IsFrameSystemDrawn() const {
+ FrameMode frame_mode = delegate_->GetFrameMode();
+ return frame_mode == FrameMode::SYSTEM_DRAWN ||
+ frame_mode == FrameMode::SYSTEM_DRAWN_NO_CONTROLS;
+}
+
bool HWNDMessageHandler::HasSystemFrame() const {
- return delegate_->HasFrame() &&
- delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN;
+ return delegate_->HasFrame() && IsFrameSystemDrawn();
}
// Message handlers ------------------------------------------------------------
@@ -1367,6 +1358,9 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) {
base::Bind(&HWNDMessageHandler::OnSessionChange,
base::Unretained(this))));
+ float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd());
+ dpi_ = display::win::GetDPIFromScalingFactor(scale_factor);
+
// TODO(beng): move more of NWW::OnCreate here.
return 0;
}
@@ -1412,9 +1406,18 @@ LRESULT HWNDMessageHandler::OnDpiChanged(UINT msg,
if (LOWORD(w_param) != HIWORD(w_param))
NOTIMPLEMENTED() << "Received non-square scaling factors";
+ // The first WM_DPICHANGED originates from EnableChildWindowDpiMessage during
+ // initialization. We don't want to propagate this as the client is already
+ // set at the current scale factor and may cause the window to display too
+ // soon. See http://crbug.com/625076.
+ int dpi = LOWORD(w_param);
+ if (dpi_ == dpi)
+ return 0;
+
+ dpi_ = dpi;
SetBoundsInternal(gfx::Rect(*reinterpret_cast<RECT*>(l_param)), false);
delegate_->HandleWindowScaleFactorChanged(
- display::win::GetScalingFactorFromDPI(LOWORD(w_param)));
+ display::win::GetScalingFactorFromDPI(dpi_));
return 0;
}
@@ -1424,13 +1427,6 @@ void HWNDMessageHandler::OnEnterMenuLoop(BOOL from_track_popup_menu) {
}
void HWNDMessageHandler::OnEnterSizeMove() {
- // Please refer to the comments in the OnSize function about the scrollbar
- // hack.
- // Hide the Windows scrollbar if the scroll styles are present to ensure
- // that a paint flicker does not occur while sizing.
- if (in_size_loop_ && needs_scroll_styles_)
- ShowScrollBar(hwnd(), SB_BOTH, FALSE);
-
delegate_->HandleBeginWMSizeMove();
SetMsgHandled(FALSE);
}
@@ -1449,13 +1445,6 @@ void HWNDMessageHandler::OnExitMenuLoop(BOOL is_shortcut_menu) {
void HWNDMessageHandler::OnExitSizeMove() {
delegate_->HandleEndWMSizeMove();
SetMsgHandled(FALSE);
- // Please refer to the notes in the OnSize function for information about
- // the scrolling hack.
- // We hide the Windows scrollbar in the OnEnterSizeMove function. We need
- // to add the scroll styles back to ensure that scrolling works in legacy
- // trackpoint drivers.
- if (in_size_loop_ && needs_scroll_styles_)
- AddScrollStylesToWindow(hwnd());
// If the window was moved to a monitor which has a fullscreen window active,
// we need to reduce the size of the fullscreen window by 1px.
CheckAndHandleBackgroundFullscreenOnMonitor(hwnd());
@@ -1762,7 +1751,7 @@ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
if (autohide_edges & ViewsDelegate::EDGE_LEFT)
client_rect->left += kAutoHideTaskbarThicknessPx;
if (autohide_edges & ViewsDelegate::EDGE_TOP) {
- if (delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN) {
+ if (IsFrameSystemDrawn()) {
// Tricky bit. Due to a bug in DwmDefWindowProc()'s handling of
// WM_NCHITTEST, having any nonclient area atop the window causes the
// caption buttons to draw onscreen but not respond to mouse
@@ -1823,7 +1812,8 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const gfx::Point& point) {
// If the DWM is rendering the window controls, we need to give the DWM's
// default window procedure first chance to handle hit testing.
- if (HasSystemFrame()) {
+ if (HasSystemFrame() &&
+ delegate_->GetFrameMode() != FrameMode::SYSTEM_DRAWN_NO_CONTROLS) {
LRESULT result;
if (DwmDefWindowProc(hwnd(), WM_NCHITTEST, 0,
MAKELPARAM(point.x(), point.y()), &result)) {
@@ -1839,49 +1829,6 @@ LRESULT HWNDMessageHandler::OnNCHitTest(const gfx::Point& point) {
// us.
LRESULT hit_test_code = DefWindowProc(hwnd(), WM_NCHITTEST, 0,
MAKELPARAM(point.x(), point.y()));
- if (needs_scroll_styles_) {
- switch (hit_test_code) {
- // If we faked the WS_VSCROLL and WS_HSCROLL styles for this window, then
- // Windows returns the HTVSCROLL or HTHSCROLL hit test codes if we hover
- // or click on the non client portions of the window where the OS
- // scrollbars would be drawn. These hittest codes are returned even when
- // the scrollbars are hidden, which is the case in Aura. We fake the
- // hittest code as HTCLIENT in this case to ensure that we receive client
- // mouse messages as opposed to non client mouse messages.
- case HTVSCROLL:
- case HTHSCROLL:
- hit_test_code = HTCLIENT;
- break;
-
- case HTBOTTOMRIGHT: {
- // Normally the HTBOTTOMRIGHT hittest code is received when we hover
- // near the bottom right of the window. However due to our fake scroll
- // styles, we get this code even when we hover around the area where
- // the vertical scrollar down arrow would be drawn.
- // We check if the hittest coordinates lie in this region and if yes
- // we return HTCLIENT.
- int border_width = ::GetSystemMetrics(SM_CXSIZEFRAME);
- int border_height = ::GetSystemMetrics(SM_CYSIZEFRAME);
- int scroll_width = ::GetSystemMetrics(SM_CXVSCROLL);
- int scroll_height = ::GetSystemMetrics(SM_CYVSCROLL);
- RECT window_rect;
- ::GetWindowRect(hwnd(), &window_rect);
- window_rect.bottom -= border_height;
- window_rect.right -= border_width;
- window_rect.left = window_rect.right - scroll_width;
- window_rect.top = window_rect.bottom - scroll_height;
- POINT pt;
- pt.x = point.x();
- pt.y = point.y();
- if (::PtInRect(&window_rect, pt))
- hit_test_code = HTCLIENT;
- break;
- }
-
- default:
- break;
- }
- }
return hit_test_code;
}
@@ -1910,8 +1857,7 @@ void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
// We only do non-client painting if we're not using the system frame.
// It's required to avoid some native painting artifacts from appearing when
// the window is resized.
- if (!delegate_->HasNonClientView() ||
- delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN) {
+ if (!delegate_->HasNonClientView() || IsFrameSystemDrawn()) {
if (ui::win::IsAeroGlassEnabled()) {
// The default WM_NCPAINT handler under Aero Glass doesn't clear the
// nonclient area, so it'll remain the default white color. That area is
@@ -2129,19 +2075,6 @@ void HWNDMessageHandler::OnSize(UINT param, const gfx::Size& size) {
// ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
// invoked OnSize we ensure the RootView has been laid out.
ResetWindowRegion(false, true);
-
- // We add the WS_VSCROLL and WS_HSCROLL styles to top level windows to ensure
- // that legacy trackpad/trackpoint drivers generate the WM_VSCROLL and
- // WM_HSCROLL messages and scrolling works.
- // We want the scroll styles to be present on the window. However we don't
- // want Windows to draw the scrollbars. To achieve this we hide the scroll
- // bars and readd them to the window style in a posted task to ensure that we
- // don't get nested WM_SIZE messages.
- if (needs_scroll_styles_ && !in_size_loop_) {
- ShowScrollBar(hwnd(), SB_BOTH, FALSE);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&AddScrollStylesToWindow, hwnd()));
- }
}
void HWNDMessageHandler::OnSysCommand(UINT notification_code,
@@ -2361,6 +2294,12 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
window_pos->flags & SWP_FRAMECHANGED) {
delegate_->HandleWindowSizeChanging();
sent_window_size_changing_ = true;
+
+ // It's possible that if Aero snap is being entered then the window size
+ // won't actually change. Post a message to ensure swaps will be re-enabled
+ // in that case.
+ PostMessage(hwnd(), WM_WINDOWSIZINGFINISHED, ++current_window_size_message_,
+ 0);
}
if (ScopedFullscreenVisibility::IsHiddenForFullscreen(hwnd())) {
@@ -2394,13 +2333,24 @@ void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) {
if (direct_manipulation_helper_)
direct_manipulation_helper_->Deactivate(hwnd());
}
- if (sent_window_size_changing_) {
- sent_window_size_changing_ = false;
- delegate_->HandleWindowSizeChanged();
- }
+
SetMsgHandled(FALSE);
}
+LRESULT HWNDMessageHandler::OnWindowSizingFinished(UINT message,
+ WPARAM w_param,
+ LPARAM l_param) {
+ // Check if a newer WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED have been
+ // received after this message was posted.
+ if (current_window_size_message_ != w_param)
+ return 0;
+
+ delegate_->HandleWindowSizeUnchanged();
+ sent_window_size_changing_ = false;
+
+ return 0;
+}
+
void HWNDMessageHandler::OnSessionChange(WPARAM status_code) {
// Direct3D presents are ignored while the screen is locked, so force the
// window to be redrawn on unlock.
@@ -2430,15 +2380,15 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message,
// TODO(ananta)
// Windows does not reliably set the touch flag on mouse messages. Look into
// a better way of identifying mouse messages originating from touch.
- if (ui::IsMouseEventFromTouch(message)) {
+ if ((message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL) &&
+ (ui::IsMouseEventFromTouch(message))) {
LPARAM l_param_ht = l_param;
// For mouse events (except wheel events), location is in window coordinates
// and should be converted to screen coordinates for WM_NCHITTEST.
- if (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL) {
- POINT screen_point = CR_POINT_INITIALIZER_FROM_LPARAM(l_param_ht);
- MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
- l_param_ht = MAKELPARAM(screen_point.x, screen_point.y);
- }
+ POINT screen_point = CR_POINT_INITIALIZER_FROM_LPARAM(l_param_ht);
+ MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
+ l_param_ht = MAKELPARAM(screen_point.x, screen_point.y);
+
LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht);
if (hittest == HTCLIENT || hittest == HTNOWHERE)
return 0;
@@ -2594,7 +2544,7 @@ void HWNDMessageHandler::PerformDwmTransition() {
// The non-client view needs to update too.
delegate_->HandleFrameChanged();
- if (IsVisible() && delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN) {
+ if (IsVisible() && IsFrameSystemDrawn()) {
// For some reason, we need to hide the window after we change from a custom
// frame to a native frame. If we don't, the client area will be filled
// with black. This seems to be related to an interaction between DWM and
@@ -2705,8 +2655,13 @@ bool HWNDMessageHandler::HandleMouseInputForCaption(unsigned int message,
break;
}
- case WM_NCMOUSELEAVE:
+ case WM_NCMOUSELEAVE: {
+ // If the DWM is rendering the window controls, we need to give the DWM's
+ // default window procedure the chance to repaint the window border icons
+ if (HasSystemFrame())
+ handled = DwmDefWindowProc(hwnd(), WM_NCMOUSELEAVE, 0, 0, NULL) != 0;
break;
+ }
default:
left_button_down_on_caption_ = false;
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index a04bfa780b2..9b2ad1d08a2 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -59,6 +59,11 @@ class WindowsSessionChangeObserver;
const int WM_NCUAHDRAWCAPTION = 0xAE;
const int WM_NCUAHDRAWFRAME = 0xAF;
+// The HWNDMessageHandler sends this message to itself on
+// WM_WINDOWPOSCHANGING. It's used to inform the client if a
+// WM_WINDOWPOSCHANGED won't be received.
+const int WM_WINDOWSIZINGFINISHED = WM_USER;
+
// IsMsgHandled() and BEGIN_SAFE_MSG_MAP_EX are a modified version of
// BEGIN_MSG_MAP_EX. The main difference is it uses a WeakPtrFactory member
// (|weak_factory|) that is used in _ProcessWindowMessage() and changing
@@ -313,6 +318,11 @@ class VIEWS_EXPORT HWNDMessageHandler :
// onscreen.
void ForceRedrawWindow(int attempts);
+ // Returns whether Windows should help with frame rendering (i.e. we're using
+ // the glass frame).
+ bool IsFrameSystemDrawn() const;
+
+ // Returns true if IsFrameSystemDrawn() and there's actually a frame to draw.
bool HasSystemFrame() const;
// Adds or removes the frame extension into client area with
@@ -373,6 +383,8 @@ class VIEWS_EXPORT HWNDMessageHandler :
// Touch Events.
CR_MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent)
+ CR_MESSAGE_HANDLER_EX(WM_WINDOWSIZINGFINISHED, OnWindowSizingFinished)
+
// Uses the general handler macro since the specific handler macro
// MSG_WM_NCACTIVATE would convert WPARAM type to BOOL type. The high
// word of WPARAM could be set when the window is minimized or restored.
@@ -470,6 +482,7 @@ class VIEWS_EXPORT HWNDMessageHandler :
LRESULT OnTouchEvent(UINT message, WPARAM w_param, LPARAM l_param);
void OnWindowPosChanging(WINDOWPOS* window_pos);
void OnWindowPosChanged(WINDOWPOS* window_pos);
+ LRESULT OnWindowSizingFinished(UINT message, WPARAM w_param, LPARAM l_param);
// Receives Windows Session Change notifications.
void OnSessionChange(WPARAM status_code);
@@ -562,6 +575,9 @@ class VIEWS_EXPORT HWNDMessageHandler :
// The icon created from the bitmap image of the app icon.
base::win::ScopedHICON app_icon_;
+ // The current DPI.
+ int dpi_;
+
// Event handling ------------------------------------------------------------
// The flags currently being used with TrackMouseEvent to track mouse
@@ -606,9 +622,6 @@ class VIEWS_EXPORT HWNDMessageHandler :
// Generates touch-ids for touch-events.
ui::SequentialIDGenerator id_generator_;
- // Indicates if the window needs the WS_VSCROLL and WS_HSCROLL styles.
- bool needs_scroll_styles_;
-
// Set to true if we are in the context of a sizing operation.
bool in_size_loop_;
@@ -642,9 +655,13 @@ class VIEWS_EXPORT HWNDMessageHandler :
bool dwm_transition_desired_;
// True if HandleWindowSizeChanging has been called in the delegate, but not
- // HandleWindowSizeChanged.
+ // HandleClientSizeChanged.
bool sent_window_size_changing_;
+ // This is used to keep track of whether a WM_WINDOWPOSCHANGED has
+ // been received after the WM_WINDOWPOSCHANGING.
+ uint32_t current_window_size_message_ = 0;
+
// Manages observation of Windows Session Change messages.
std::unique_ptr<WindowsSessionChangeObserver>
windows_session_change_observer_;
diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h
index f9e027d6faa..14021805543 100644
--- a/chromium/ui/views/win/hwnd_message_handler_delegate.h
+++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h
@@ -25,8 +25,9 @@ class TouchEvent;
namespace views {
enum class FrameMode {
- SYSTEM_DRAWN, // "glass" frame
- CUSTOM_DRAWN // "opaque" frame
+ SYSTEM_DRAWN, // "glass" frame
+ SYSTEM_DRAWN_NO_CONTROLS, // "glass" frame but with custom window controls
+ CUSTOM_DRAWN // "opaque" frame
};
class InputMethod;
@@ -46,6 +47,7 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// that don't have a visible frame. Those usually have the WS_POPUP style, for
// which Windows will remove the frame automatically if the frame mode is
// SYSTEM_DRAWN.
+ // TODO(bsep): Investigate deleting this when v2 Apps support is removed.
virtual bool HasFrame() const = 0;
virtual void SchedulePaint() = 0;
@@ -239,8 +241,9 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// Called when the window size is about to change.
virtual void HandleWindowSizeChanging() = 0;
- // Called when the window size has finished changing.
- virtual void HandleWindowSizeChanged() = 0;
+ // Called after HandleWindowSizeChanging() when it's determined the window
+ // size didn't actually change.
+ virtual void HandleWindowSizeUnchanged() = 0;
// Called when the window scale factor has changed.
virtual void HandleWindowScaleFactorChanged(float window_scale_factor) = 0;
diff --git a/chromium/ui/views/window/custom_frame_view.cc b/chromium/ui/views/window/custom_frame_view.cc
index 720091ec624..fe392518a1e 100644
--- a/chromium/ui/views/window/custom_frame_view.cc
+++ b/chromium/ui/views/window/custom_frame_view.cc
@@ -31,6 +31,10 @@
#include "ui/views/window/window_resources.h"
#include "ui/views/window/window_shape.h"
+#if defined(OS_WIN)
+#include "ui/display/win/screen_win.h"
+#endif
+
namespace views {
namespace {
@@ -53,11 +57,6 @@ const int kTitleIconOffsetX = 4;
// The space between the title text and the caption buttons.
const int kTitleCaptionSpacing = 5;
-#if !defined(OS_WIN)
-// The icon never shrinks below 16 px on a side.
-const int kIconMinimumSize = 16;
-#endif
-
#if defined(OS_CHROMEOS)
// Chrome OS uses a dark gray.
const SkColor kDefaultColorFrame = SkColorSetRGB(109, 109, 109);
@@ -304,8 +303,10 @@ int CustomFrameView::IconSize() const {
#if defined(OS_WIN)
// This metric scales up if either the titlebar height or the titlebar font
// size are increased.
- return GetSystemMetrics(SM_CYSMICON);
+ return display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYSMICON);
#else
+ // The icon never shrinks below 16 px on a side.
+ const int kIconMinimumSize = 16;
return std::max(GetTitleFontList().GetHeight(), kIconMinimumSize);
#endif
}
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index 55bf0047508..ce9099fb393 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -11,6 +11,7 @@
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/blue_button.h"
+#include "ui/views/controls/button/custom_button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/layout/layout_constants.h"
@@ -38,14 +39,19 @@ bool ShouldShow(View* view) {
}
// Do the layout for a button.
-void LayoutButton(LabelButton* button, gfx::Rect* row_bounds) {
+void LayoutButton(LabelButton* button,
+ gfx::Rect* row_bounds,
+ int button_height) {
if (!button)
return;
const gfx::Size size = button->GetPreferredSize();
row_bounds->set_width(row_bounds->width() - size.width());
- button->SetBounds(row_bounds->right(), row_bounds->y(),
- size.width(), row_bounds->height());
+ DCHECK_LE(button_height, row_bounds->height());
+ button->SetBounds(
+ row_bounds->right(),
+ row_bounds->y() + (row_bounds->height() - button_height) / 2,
+ size.width(), button_height);
row_bounds->set_width(row_bounds->width() - kRelatedButtonHSpacing);
}
@@ -180,12 +186,17 @@ void DialogClientView::Layout() {
const int height = GetButtonsAndExtraViewRowHeight();
gfx::Rect row_bounds(bounds.x(), bounds.bottom() - height,
bounds.width(), height);
+ // If the |extra_view_| is a also button, then the |button_height| is the
+ // maximum height of the three buttons, otherwise it is the maximum height
+ // of the ok and cancel buttons.
+ const int button_height =
+ CustomButton::AsCustomButton(extra_view_) ? height : GetButtonHeight();
if (kIsOkButtonOnLeftSide) {
- LayoutButton(cancel_button_, &row_bounds);
- LayoutButton(ok_button_, &row_bounds);
+ LayoutButton(cancel_button_, &row_bounds, button_height);
+ LayoutButton(ok_button_, &row_bounds, button_height);
} else {
- LayoutButton(ok_button_, &row_bounds);
- LayoutButton(cancel_button_, &row_bounds);
+ LayoutButton(ok_button_, &row_bounds, button_height);
+ LayoutButton(cancel_button_, &row_bounds, button_height);
}
if (extra_view_) {
int custom_padding = 0;
@@ -303,9 +314,11 @@ void DialogClientView::ChildVisibilityChanged(View* child) {
LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) {
const base::string16 title = GetDialogDelegate()->GetDialogButtonLabel(type);
LabelButton* button = nullptr;
+ // The default button is always blue in Harmony.
if (GetDialogDelegate()->GetDefaultDialogButton() == type &&
- GetDialogDelegate()->ShouldDefaultButtonBeBlue()) {
- return MdTextButton::CreateSecondaryUiBlueButton(this, title);
+ (ui::MaterialDesignController::IsSecondaryUiMaterial() ||
+ GetDialogDelegate()->ShouldDefaultButtonBeBlue())) {
+ button = MdTextButton::CreateSecondaryUiBlueButton(this, title);
} else {
button = MdTextButton::CreateSecondaryUiButton(this, title);
}
@@ -316,13 +329,18 @@ LabelButton* DialogClientView::CreateDialogButton(ui::DialogButton type) {
return button;
}
-int DialogClientView::GetButtonsAndExtraViewRowHeight() const {
- int extra_view_height = ShouldShow(extra_view_) ?
- extra_view_->GetPreferredSize().height() : 0;
- int buttons_height = std::max(
+int DialogClientView::GetButtonHeight() const {
+ return std::max(
ok_button_ ? ok_button_->GetPreferredSize().height() : 0,
cancel_button_ ? cancel_button_->GetPreferredSize().height() : 0);
- return std::max(extra_view_height, buttons_height);
+}
+
+int DialogClientView::GetExtraViewHeight() const {
+ return ShouldShow(extra_view_) ? extra_view_->GetPreferredSize().height() : 0;
+}
+
+int DialogClientView::GetButtonsAndExtraViewRowHeight() const {
+ return std::max(GetExtraViewHeight(), GetButtonHeight());
}
gfx::Insets DialogClientView::GetButtonRowInsets() const {
diff --git a/chromium/ui/views/window/dialog_client_view.h b/chromium/ui/views/window/dialog_client_view.h
index 60080b00c8c..3fb88c08b25 100644
--- a/chromium/ui/views/window/dialog_client_view.h
+++ b/chromium/ui/views/window/dialog_client_view.h
@@ -87,6 +87,12 @@ class VIEWS_EXPORT DialogClientView : public ClientView,
// Update |button|'s text and enabled state according to the delegate's state.
void UpdateButton(LabelButton* button, ui::DialogButton type);
+ // Returns the height of the buttons.
+ int GetButtonHeight() const;
+
+ // Returns the height of the extra view.
+ int GetExtraViewHeight() const;
+
// Returns the height of the row containing the buttons and the extra view.
int GetButtonsAndExtraViewRowHeight() const;
diff --git a/chromium/ui/views/window/dialog_client_view_unittest.cc b/chromium/ui/views/window/dialog_client_view_unittest.cc
index c483d254af3..dfe45b56237 100644
--- a/chromium/ui/views/window/dialog_client_view_unittest.cc
+++ b/chromium/ui/views/window/dialog_client_view_unittest.cc
@@ -7,6 +7,7 @@
#include "build/build_config.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/style/platform_style.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
@@ -148,7 +149,8 @@ TEST_F(DialogClientViewTest, UpdateButtons) {
// Reset with just a cancel button.
SetDialogButtons(ui::DIALOG_BUTTON_CANCEL);
EXPECT_EQ(NULL, client_view()->ok_button());
- EXPECT_TRUE(client_view()->cancel_button()->is_default());
+ EXPECT_EQ(client_view()->cancel_button()->is_default(),
+ PlatformStyle::kDialogDefaultButtonCanBeCancel);
EXPECT_EQ(GetUpdatedClientBounds().height(), height_with_buttons);
}
diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc
index 4b8a1f98900..d98274cde71 100644
--- a/chromium/ui/views/window/dialog_delegate.cc
+++ b/chromium/ui/views/window/dialog_delegate.cc
@@ -16,6 +16,7 @@
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/layout_constants.h"
+#include "ui/views/style/platform_style.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_client_view.h"
@@ -119,7 +120,12 @@ bool DialogDelegate::Close() {
void DialogDelegate::UpdateButton(LabelButton* button, ui::DialogButton type) {
button->SetText(GetDialogButtonLabel(type));
button->SetEnabled(IsDialogButtonEnabled(type));
- button->SetIsDefault(type == GetDefaultDialogButton());
+ bool is_default = type == GetDefaultDialogButton();
+ if (!PlatformStyle::kDialogDefaultButtonCanBeCancel &&
+ type == ui::DIALOG_BUTTON_CANCEL) {
+ is_default = false;
+ }
+ button->SetIsDefault(is_default);
}
int DialogDelegate::GetDialogButtons() const {
diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h
index c74f5461ab9..8e122178640 100644
--- a/chromium/ui/views/window/dialog_delegate.h
+++ b/chromium/ui/views/window/dialog_delegate.h
@@ -63,7 +63,7 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
virtual View* CreateFootnoteView();
// For Dialog boxes, if there is a "Cancel" button or no dialog button at all,
- // this is called when the user presses the "Cancel" button or the Esc key.
+ // this is called when the user presses the "Cancel" button.
// It can also be called on a close action if |Close| has not been
// overridden. This function should return true if the window can be closed
// after it returns, or false if it must remain open.
@@ -76,10 +76,11 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
virtual bool Accept();
// Called when the user closes the window without selecting an option,
- // e.g. by pressing the close button on the window or using a window manager
- // gesture. By default, this calls Accept() if the only button in the dialog
- // is Accept, Cancel() otherwise. This function should return true if the
- // window can be closed after it returns, or false if it must remain open.
+ // e.g. by pressing the close button on the window, pressing the Esc key, or
+ // using a window manager gesture. By default, this calls Accept() if the only
+ // button in the dialog is Accept, Cancel() otherwise. This function should
+ // return true if the window can be closed after it returns, or false if it
+ // must remain open.
virtual bool Close();
// Updates the properties and appearance of |button| which has been created
diff --git a/chromium/ui/views/word_lookup_client.h b/chromium/ui/views/word_lookup_client.h
new file mode 100644
index 00000000000..d9c200f5566
--- /dev/null
+++ b/chromium/ui/views/word_lookup_client.h
@@ -0,0 +1,35 @@
+// Copyright 2016 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_WORD_LOOKUP_CLIENT_H_
+#define UI_VIEWS_WORD_LOOKUP_CLIENT_H_
+
+#include "ui/views/views_export.h"
+
+namespace gfx {
+struct DecoratedText;
+class Point;
+}
+
+namespace views {
+
+// An interface implemented by a view which supports word lookups.
+class VIEWS_EXPORT WordLookupClient {
+ public:
+ // Retrieves the word displayed at the given |point| along with its styling
+ // information. |point| is in the coordinate system of the view. If no word is
+ // displayed at the point, returns a nearby word. |baseline_point| should
+ // correspond to the baseline point of the leftmost glyph of the |word| in the
+ // view's coordinates. Returns false, if no word can be retrieved.
+ virtual bool GetDecoratedWordAtPoint(const gfx::Point& point,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) = 0;
+
+ protected:
+ virtual ~WordLookupClient() {}
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WORD_LOOKUP_CLIENT_H_