summaryrefslogtreecommitdiff
path: root/chromium/ui/views
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-10-24 11:30:15 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-10-30 12:56:19 +0000
commit6036726eb981b6c4b42047513b9d3f4ac865daac (patch)
tree673593e70678e7789766d1f732eb51f613a2703b /chromium/ui/views
parent466052c4e7c052268fd931888cd58961da94c586 (diff)
downloadqtwebengine-chromium-6036726eb981b6c4b42047513b9d3f4ac865daac.tar.gz
BASELINE: Update Chromium to 70.0.3538.78
Change-Id: Ie634710bf039e26c1957f4ae45e101bd4c434ae7 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/views')
-rw-r--r--chromium/ui/views/BUILD.gn126
-rw-r--r--chromium/ui/views/DEPS2
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc13
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h2
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc4
-rw-r--r--chromium/ui/views/animation/bounds_animator.h2
-rw-r--r--chromium/ui/views/animation/ink_drop.h2
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc450
-rw-r--r--chromium/ui/views/bubble/bubble_border.h131
-rw-r--r--chromium/ui/views/bubble/bubble_border_unittest.cc328
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.cc (renamed from chromium/ui/views/bubble/bubble_dialog_delegate.cc)34
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.h (renamed from chromium/ui/views/bubble/bubble_dialog_delegate.h)20
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc (renamed from chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc)43
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc27
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h2
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc147
-rw-r--r--chromium/ui/views/bubble/info_bubble.h2
-rw-r--r--chromium/ui/views/bubble/tooltip_icon.cc4
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.cc4
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.h2
-rw-r--r--chromium/ui/views/cocoa/DEPS1
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.h14
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.mm240
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm51
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.h226
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.mm811
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host.h152
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.h230
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm651
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm3
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_unittest.mm311
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm8
-rw-r--r--chromium/ui/views/cocoa/native_widget_mac_nswindow.mm4
-rw-r--r--chromium/ui/views/cocoa/views_nswindow_delegate.mm3
-rw-r--r--chromium/ui/views/controls/button/button.cc1
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc121
-rw-r--r--chromium/ui/views/controls/button/checkbox.h24
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc66
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc46
-rw-r--r--chromium/ui/views/controls/button/radio_button.h3
-rw-r--r--chromium/ui/views/controls/button/radio_button_unittest.cc33
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc41
-rw-r--r--chromium/ui/views/controls/focusable_border.cc21
-rw-r--r--chromium/ui/views/controls/label.h2
-rw-r--r--chromium/ui/views/controls/label_unittest.cc56
-rw-r--r--chromium/ui/views/controls/link.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.h36
-rw-r--r--chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.mm28
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_config.h7
-rw-r--r--chromium/ui/views/controls/menu/menu_config_mac.mm5
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc191
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h15
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc130
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc8
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h17
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc15
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc78
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h12
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc14
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.h2
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc42
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler.h53
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc (renamed from chromium/ui/views/controls/menu/menu_pre_target_handler.cc)29
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h59
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h32
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm34
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm2
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_unittest.cc98
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc4
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc3
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc62
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.h9
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura_unittest.cc4
-rw-r--r--chromium/ui/views/controls/prefix_selector.cc16
-rw-r--r--chromium/ui/views/controls/prefix_selector.h16
-rw-r--r--chromium/ui/views/controls/scroll_view.cc16
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc14
-rw-r--r--chromium/ui/views/controls/separator.cc11
-rw-r--r--chromium/ui/views/controls/separator_unittest.cc56
-rw-r--r--chromium/ui/views/controls/styled_label.cc10
-rw-r--r--chromium/ui/views/controls/styled_label.h14
-rw-r--r--chromium/ui/views/controls/styled_label_unittest.cc97
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc11
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc25
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc33
-rw-r--r--chromium/ui/views/controls/webview/web_contents_set_background_color.cc2
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.cc19
-rw-r--r--chromium/ui/views/corewm/tooltip_aura.h6
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_unittest.cc130
-rw-r--r--chromium/ui/views/event_monitor.h8
-rw-r--r--chromium/ui/views/event_monitor_aura.cc25
-rw-r--r--chromium/ui/views/event_monitor_aura.h11
-rw-r--r--chromium/ui/views/event_monitor_mac.h3
-rw-r--r--chromium/ui/views/event_monitor_mac.mm20
-rw-r--r--chromium/ui/views/event_monitor_unittest.cc20
-rw-r--r--chromium/ui/views/examples/bubble_example.cc6
-rw-r--r--chromium/ui/views/examples/bubble_example.h1
-rw-r--r--chromium/ui/views/examples/button_sticker_sheet.cc8
-rw-r--r--chromium/ui/views/examples/dialog_example.cc2
-rw-r--r--chromium/ui/views/features.gni6
-rw-r--r--chromium/ui/views/focus/focus_manager.h3
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc2
-rw-r--r--chromium/ui/views/focus/focus_search.cc2
-rw-r--r--chromium/ui/views/focus/widget_focus_manager.h3
-rw-r--r--chromium/ui/views/layout/box_layout.cc9
-rw-r--r--chromium/ui/views/layout/box_layout.h7
-rw-r--r--chromium/ui/views/layout/box_layout_unittest.cc17
-rw-r--r--chromium/ui/views/layout/layout_provider.cc5
-rw-r--r--chromium/ui/views/layout/layout_provider.h3
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.h5
-rw-r--r--chromium/ui/views/mouse_watcher.cc13
-rw-r--r--chromium/ui/views/mouse_watcher.h7
-rw-r--r--chromium/ui/views/mus/BUILD.gn24
-rw-r--r--chromium/ui/views/mus/DEPS2
-rw-r--r--chromium/ui/views/mus/aura_init.cc20
-rw-r--r--chromium/ui/views/mus/aura_init.h16
-rw-r--r--chromium/ui/views/mus/ax_remote_host.cc106
-rw-r--r--chromium/ui/views/mus/ax_remote_host.h13
-rw-r--r--chromium/ui/views/mus/ax_remote_host_unittest.cc135
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.cc10
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.h5
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus_unittest.cc20
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.cc126
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.h15
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc55
-rw-r--r--chromium/ui/views/mus/drag_interactive_uitest.cc31
-rw-r--r--chromium/ui/views/mus/mus_client.cc108
-rw-r--r--chromium/ui/views/mus/mus_client.h49
-rw-r--r--chromium/ui/views/mus/mus_client_test_api.h3
-rw-r--r--chromium/ui/views/mus/mus_views_delegate.cc3
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router.cc19
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router.h10
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc47
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.cc2
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc9
-rw-r--r--chromium/ui/views/mus/screen_mus.cc48
-rw-r--r--chromium/ui/views/mus/screen_mus.h31
-rw-r--r--chromium/ui/views/mus/screen_mus_unittest.cc86
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc6
-rw-r--r--chromium/ui/views/mus/window_manager_constants_converters.cc24
-rw-r--r--chromium/ui/views/mus/window_manager_constants_converters.h6
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_bottom.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_bottom_left.pngbin160 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_bottom_right.pngbin165 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_left.pngbin78 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_pointer_bottom.pngbin223 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_pointer_left.pngbin192 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_pointer_right.pngbin192 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_pointer_top.pngbin139 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_right.pngbin75 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_top.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_top_left.pngbin133 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/bubble_top_right.pngbin133 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/close.pngbin159 -> 159 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/close_hover.pngbin326 -> 298 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/close_pressed.pngbin210 -> 205 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom.pngbin106 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.pngbin574 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.pngbin543 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_left.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_right.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_left.pngbin412 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_right.pngbin487 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom.pngbin77 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.pngbin131 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.pngbin131 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_left.pngbin73 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_right.pngbin72 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_left.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_right.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.pngbin472 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.pngbin437 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.pngbin455 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.pngbin375 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.pngbin186 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.pngbin132 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.pngbin140 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.pngbin121 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/maximize_hover.pngbin155 -> 129 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/maximize_pressed.pngbin163 -> 130 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/restore_hover.pngbin173 -> 144 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/restore_pressed.pngbin173 -> 144 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_bottom.pngbin95 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_bottom_left.pngbin265 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_bottom_right.pngbin257 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_left.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_pointer_bottom.pngbin380 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_pointer_left.pngbin317 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_pointer_right.pngbin322 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_pointer_top.pngbin199 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_right.pngbin84 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_top.pngbin81 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_top_left.pngbin204 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/bubble_top_right.pngbin203 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom.pngbin116 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.pngbin1194 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.pngbin1207 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_left.pngbin105 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_right.pngbin102 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top.pngbin111 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_left.pngbin986 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_right.pngbin1111 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom.pngbin88 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.pngbin206 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.pngbin200 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_left.pngbin83 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_right.pngbin83 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top.pngbin76 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_left.pngbin150 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_right.pngbin153 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.pngbin1136 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.pngbin954 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.pngbin1006 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.pngbin880 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.pngbin454 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.pngbin359 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.pngbin361 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.pngbin244 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/views_resources.grd36
-rw-r--r--chromium/ui/views/selection_controller.cc15
-rw-r--r--chromium/ui/views/selection_controller.h3
-rw-r--r--chromium/ui/views/selection_controller_unittest.cc189
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc52
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_runner_views.cc2
-rw-r--r--chromium/ui/views/vector_icons/ic_close.icon15
-rw-r--r--chromium/ui/views/vector_icons/menu_drop_arrow.icon9
-rw-r--r--chromium/ui/views/view.cc4
-rw-r--r--chromium/ui/views/view.h7
-rw-r--r--chromium/ui/views/view_properties.cc8
-rw-r--r--chromium/ui/views/view_properties.h4
-rw-r--r--chromium/ui/views/view_targeter_unittest.cc3
-rw-r--r--chromium/ui/views/views_test_suite.cc4
-rw-r--r--chromium/ui/views/widget/ax_native_widget_mac_unittest.mm7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc4
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc8
-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.cc45
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc9
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host.h20
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc41
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc86
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc26
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc143
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h28
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_event_filter.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc2
-rw-r--r--chromium/ui/views/widget/drop_helper.cc14
-rw-r--r--chromium/ui/views/widget/native_widget.h5
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc87
-rw-r--r--chromium/ui/views/widget/native_widget_aura.h11
-rw-r--r--chromium/ui/views/widget/native_widget_aura_unittest.cc8
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h26
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm393
-rw-r--r--chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm2
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm26
-rw-r--r--chromium/ui/views/widget/native_widget_private.h16
-rw-r--r--chromium/ui/views/widget/root_view_unittest.cc4
-rw-r--r--chromium/ui/views/widget/widget.cc47
-rw-r--r--chromium/ui/views/widget/widget.h10
-rw-r--r--chromium/ui/views/widget/widget_delegate.cc10
-rw-r--r--chromium/ui/views/widget/widget_delegate.h2
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc4
-rw-r--r--chromium/ui/views/widget/widget_observer.h5
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc64
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc168
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h18
-rw-r--r--chromium/ui/views/win/hwnd_message_handler_delegate.h9
-rw-r--r--chromium/ui/views/win/pen_event_processor.cc6
-rw-r--r--chromium/ui/views/win/pen_event_processor.h3
-rw-r--r--chromium/ui/views/win/windows_session_change_observer.cc5
-rw-r--r--chromium/ui/views/window/custom_frame_view.cc6
-rw-r--r--chromium/ui/views/window/dialog_delegate.h2
-rw-r--r--chromium/ui/views/window/dialog_delegate_unittest.cc34
-rw-r--r--chromium/ui/views/window/hit_test_utils.cc38
-rw-r--r--chromium/ui/views/window/hit_test_utils.h29
-rw-r--r--chromium/ui/views/window/hit_test_utils_unittest.cc66
285 files changed, 5170 insertions, 3914 deletions
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index 961f2b06534..3265121c103 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -27,6 +27,7 @@ aggregate_vector_icons("views_vector_icons") {
"info.icon",
"launch.icon",
"menu_check.icon",
+ "menu_drop_arrow.icon",
"menu_radio_empty.icon",
"menu_radio_selected.icon",
"new_incognito_window.icon",
@@ -78,23 +79,13 @@ jumbo_component("views") {
"background.h",
"border.h",
"bubble/bubble_border.h",
- "bubble/bubble_dialog_delegate.h",
+ "bubble/bubble_dialog_delegate_view.h",
"bubble/bubble_frame_view.h",
"bubble/info_bubble.h",
"bubble/tooltip_icon.h",
"button_drag_utils.h",
- "cocoa/bridged_content_view.h",
"cocoa/bridged_native_widget.h",
- "cocoa/bridged_native_widget_owner.h",
- "cocoa/cocoa_mouse_capture.h",
- "cocoa/cocoa_mouse_capture_delegate.h",
- "cocoa/cocoa_window_move_loop.h",
- "cocoa/drag_drop_client_mac.h",
"cocoa/native_widget_mac_nswindow.h",
- "cocoa/tooltip_manager_mac.h",
- "cocoa/views_nswindow_delegate.h",
- "cocoa/views_scrollbar_bridge.h",
- "cocoa/widget_owner_nswindow_adapter.h",
"cocoa/window_touch_bar_delegate.h",
"color_chooser/color_chooser_listener.h",
"color_chooser/color_chooser_view.h",
@@ -121,6 +112,7 @@ jumbo_component("views") {
"controls/link.h",
"controls/link_listener.h",
"controls/menu/menu_closure_animation_mac.h",
+ "controls/menu/menu_cocoa_watcher_mac.h",
"controls/menu/menu_config.h",
"controls/menu/menu_controller.h",
"controls/menu/menu_controller_delegate.h",
@@ -253,12 +245,13 @@ jumbo_component("views") {
"window/dialog_observer.h",
"window/frame_background.h",
"window/frame_buttons.h",
+ "window/hit_test_utils.h",
"window/native_frame_view.h",
"window/non_client_view.h",
"window/window_button_order_provider.h",
+ "window/window_resize_utils.h",
"window/window_resources.h",
"window/window_shape.h",
- "window/window_resize_utils.h",
"word_lookup_client.h",
]
@@ -283,22 +276,13 @@ jumbo_component("views") {
"background.cc",
"border.cc",
"bubble/bubble_border.cc",
- "bubble/bubble_dialog_delegate.cc",
+ "bubble/bubble_dialog_delegate_view.cc",
"bubble/bubble_frame_view.cc",
"bubble/info_bubble.cc",
"bubble/tooltip_icon.cc",
"button_drag_utils.cc",
- "cocoa/bridged_content_view.mm",
- "cocoa/bridged_content_view_touch_bar.mm",
"cocoa/bridged_native_widget.mm",
- "cocoa/cocoa_mouse_capture.mm",
- "cocoa/cocoa_window_move_loop.mm",
- "cocoa/drag_drop_client_mac.mm",
"cocoa/native_widget_mac_nswindow.mm",
- "cocoa/tooltip_manager_mac.mm",
- "cocoa/views_nswindow_delegate.mm",
- "cocoa/views_scrollbar_bridge.mm",
- "cocoa/widget_owner_nswindow_adapter.mm",
"color_chooser/color_chooser_view.cc",
"controls/animated_icon_view.cc",
"controls/button/blue_button.cc",
@@ -320,6 +304,7 @@ jumbo_component("views") {
"controls/link.cc",
"controls/menu/display_change_listener_mac.cc",
"controls/menu/menu_closure_animation_mac.mm",
+ "controls/menu/menu_cocoa_watcher_mac.mm",
"controls/menu/menu_config.cc",
"controls/menu/menu_config_chromeos.cc",
"controls/menu/menu_config_linux.cc",
@@ -435,6 +420,7 @@ jumbo_component("views") {
"window/dialog_client_view.cc",
"window/dialog_delegate.cc",
"window/frame_background.cc",
+ "window/hit_test_utils.cc",
"window/native_frame_view.cc",
"window/non_client_view.cc",
"window/window_button_order_provider.cc",
@@ -442,14 +428,37 @@ jumbo_component("views") {
"window/window_shape.cc",
]
- # Internal sources. If a header in this list is used by another target under
- # //ui/views:* the header can be listed again in that target's sources. See
- # http://crbug/com/732993 for a possible build system feature to avoid the
- # repetition. TODO(tapted): Move more headers from public into this list with
- # the implementation file.
+ # Other targets in this file (e.g. tests) get access to the internal headers.
+ friend = [ ":*" ]
+
+ # Internal sources. TODO(https://crbug.com/871123): Move more headers from
+ # public into this list, along with the implementation file.
sources += [
+ "cocoa/bridged_content_view.h",
+ "cocoa/bridged_content_view.mm",
+ "cocoa/bridged_content_view_touch_bar.mm",
+ "cocoa/bridged_native_widget_host.h",
+ "cocoa/bridged_native_widget_host_impl.h",
+ "cocoa/bridged_native_widget_host_impl.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/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",
"controls/button/label_button_label.cc",
"controls/button/label_button_label.h",
+ "controls/menu/menu_pre_target_handler.h",
]
sources += get_target_outputs(":views_vector_icons")
@@ -468,7 +477,7 @@ jumbo_component("views") {
"//base:i18n",
"//base/third_party/dynamic_annotations",
"//cc/paint",
- "//services/ui/public/interfaces",
+ "//services/ws/public/mojom",
"//skia",
"//third_party/icu",
"//ui/accessibility",
@@ -497,6 +506,7 @@ jumbo_component("views") {
"//ui/gfx/animation",
"//ui/gfx/geometry",
"//ui/views/resources",
+ "//ui/views_bridge_mac:mojo",
]
if (use_x11) {
@@ -583,7 +593,6 @@ jumbo_component("views") {
"accessibility/ax_widget_obj_wrapper.h",
"accessibility/ax_window_obj_wrapper.h",
"bubble/tray_bubble_view.h",
- "controls/menu/menu_pre_target_handler.h",
"controls/native/native_view_host_aura.h",
"corewm/cursor_height_provider_win.h",
"corewm/tooltip.h",
@@ -617,7 +626,8 @@ jumbo_component("views") {
"accessibility/ax_window_obj_wrapper.cc",
"bubble/tray_bubble_view.cc",
"controls/menu/display_change_listener_aura.cc",
- "controls/menu/menu_pre_target_handler.cc",
+ "controls/menu/menu_pre_target_handler_aura.cc",
+ "controls/menu/menu_pre_target_handler_aura.h",
"controls/native/native_view_host_aura.cc",
"corewm/cursor_height_provider_win.cc",
"corewm/tooltip_aura.cc",
@@ -645,7 +655,7 @@ jumbo_component("views") {
"widget/window_reorderer.cc",
]
deps += [
- "//services/ui/public/interfaces",
+ "//services/ws/public/mojom",
"//ui/aura",
"//ui/platform_window",
"//ui/touch_selection",
@@ -705,18 +715,21 @@ jumbo_component("views") {
"widget/desktop_aura/window_event_filter.cc",
"widget/desktop_aura/window_event_filter.h",
]
- if (!use_x11) {
- public +=
- [ "widget/desktop_aura/desktop_window_tree_host_platform.h" ]
- sources +=
- [ "widget/desktop_aura/desktop_window_tree_host_platform.cc" ]
- }
+ }
+ if ((is_linux && !use_x11) || is_fuchsia) {
+ public += [ "widget/desktop_aura/desktop_window_tree_host_platform.h" ]
+ sources +=
+ [ "widget/desktop_aura/desktop_window_tree_host_platform.cc" ]
}
}
}
if (is_mac) {
sources -= [ "controls/views_text_services_context_menu.cc" ]
+ sources += [
+ "controls/menu/menu_pre_target_handler_mac.h",
+ "controls/menu/menu_pre_target_handler_mac.mm",
+ ]
deps += [
"//components/crash/core/common",
"//ui/accelerated_widget_mac",
@@ -917,16 +930,6 @@ jumbo_static_library("test_support") {
source_set("views_unittests_sources") {
testonly = true
- # Headers used in tests that appear in :views private sources list. Permits
- # this target to act as a "friend" of :views. The build system doesn't
- # currently have a way to represent this. See http://crbug.com/732993.
- public = [
- "controls/button/label_button_label.h",
- ]
- if (has_native_accessibility) {
- public += [ "accessibility/view_ax_platform_node_delegate.h" ]
- }
-
sources = [
"accessible_pane_view_unittest.cc",
"animation/bounds_animator_unittest.cc",
@@ -939,7 +942,7 @@ source_set("views_unittests_sources") {
"animation/square_ink_drop_ripple_unittest.cc",
"border_unittest.cc",
"bubble/bubble_border_unittest.cc",
- "bubble/bubble_dialog_delegate_unittest.cc",
+ "bubble/bubble_dialog_delegate_view_unittest.cc",
"bubble/bubble_frame_view_unittest.cc",
"cocoa/bridged_native_widget_unittest.mm",
"cocoa/cocoa_mouse_capture_unittest.mm",
@@ -971,6 +974,7 @@ source_set("views_unittests_sources") {
"controls/resize_area_unittest.cc",
"controls/scroll_view_unittest.cc",
"controls/scrollbar/scrollbar_unittest.cc",
+ "controls/separator_unittest.cc",
"controls/slider_unittest.cc",
"controls/styled_label_unittest.cc",
"controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm",
@@ -989,6 +993,7 @@ source_set("views_unittests_sources") {
"layout/grid_layout_unittest.cc",
"paint_info_unittest.cc",
"rect_based_targeting_utils_unittest.cc",
+ "selection_controller_unittest.cc",
"test/widget_test_unittest.cc",
"view_model_unittest.cc",
"view_model_utils_unittest.cc",
@@ -1004,6 +1009,7 @@ source_set("views_unittests_sources") {
"window/custom_frame_view_unittest.cc",
"window/dialog_client_view_unittest.cc",
"window/dialog_delegate_unittest.cc",
+ "window/hit_test_utils_unittest.cc",
"window/non_client_view_unittest.cc",
"window/window_resize_utils_unittest.cc",
]
@@ -1013,7 +1019,7 @@ source_set("views_unittests_sources") {
# Make all deps in this target public so both views_unittests and
# views_mus_unittests will get them.
public_deps = [
- ":test_support",
+ ":test_support_internal",
":views",
"//base",
"//base:i18n",
@@ -1021,7 +1027,7 @@ source_set("views_unittests_sources") {
"//cc",
"//cc/paint",
"//components/vector_icons",
- "//services/ui/public/interfaces",
+ "//services/ws/public/mojom",
"//skia",
"//testing/gtest",
"//third_party/icu",
@@ -1049,8 +1055,6 @@ source_set("views_unittests_sources") {
]
if (is_win) {
- public += [ "accessibility/view_ax_platform_node_delegate_win.h" ]
-
public_deps += [
"//build/win:default_exe_manifest",
"//third_party/iaccessible2",
@@ -1090,8 +1094,10 @@ source_set("views_unittests_sources") {
"accessibility/ax_aura_obj_cache_unittest.cc",
"accessibility/ax_tree_source_views_unittest.cc",
"controls/native/native_view_host_aura_unittest.cc",
+ "corewm/tooltip_controller_unittest.cc",
"touchui/touch_selection_menu_runner_views_unittest.cc",
"view_unittest_aura.cc",
+ "widget/window_reorderer_unittest.cc",
]
public_deps += [
"//ui/aura",
@@ -1121,16 +1127,10 @@ test("views_unittests") {
if (use_aura) {
sources += [
- # These tests currently use AuraTestBase, but then try to use views
- # objects. Thus, when they are run in views_mus_unittests, they test the
- # local aura path instead of the remote mus path, so pull them
- # out. crbug.com/710939.
- #
- # Some of the tests need drag-drop support. crbug.com/614037
- "corewm/tooltip_controller_unittest.cc",
+ # These tests are expecting a hierarchy as created by classic ash. They
+ # are only useful for views_unittests, and not in views_mus_unittests.
"touchui/touch_selection_controller_impl_unittest.cc",
"widget/native_widget_aura_unittest.cc",
- "widget/window_reorderer_unittest.cc",
]
if (is_mac) {
@@ -1153,11 +1153,17 @@ test("views_unittests") {
}
}
+ if (is_linux && !is_chromeos && !use_x11) {
+ sources +=
+ [ "widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc" ]
+ }
+
if (!is_chromeos) {
sources += [ "widget/desktop_widget_unittest.cc" ]
}
deps = [
+ ":test_support",
":views_unittests_sources",
"//mojo/core/embedder",
]
diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS
index 39d2ec74e37..f591ea6f71c 100644
--- a/chromium/ui/views/DEPS
+++ b/chromium/ui/views/DEPS
@@ -2,7 +2,7 @@ include_rules = [
"+cc/paint",
"+components/crash/core/common/crash_key.h",
"+components/vector_icons",
- "+services/ui/public/interfaces",
+ "+services/ws/public/mojom",
"+skia/ext",
"+third_party/iaccessible2",
"+third_party/skia",
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index e7bbe189e43..b8ea4c3c754 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -157,9 +157,16 @@ void AXWindowObjWrapper::OnWindowPropertyChanged(aura::Window* window,
void AXWindowObjWrapper::OnWindowVisibilityChanged(aura::Window* window,
bool visible) {
- AXAuraObjCache::GetInstance()->FireEvent(
- AXAuraObjCache::GetInstance()->GetOrCreate(window_),
- ax::mojom::Event::kStateChanged);
+ AXAuraObjCache::GetInstance()->FireEvent(this,
+ ax::mojom::Event::kStateChanged);
+}
+
+void AXWindowObjWrapper::OnWindowTransformed(aura::Window* window,
+ ui::PropertyChangeReason reason) {
+ if (window != window_)
+ return;
+
+ FireLocationChanges(window_);
}
} // 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 44f3f64eb3c..e996fa3a124 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -50,6 +50,8 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
const void* key,
intptr_t old) override;
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
+ void OnWindowTransformed(aura::Window* window,
+ ui::PropertyChangeReason reason) override;
private:
aura::Window* window_;
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 8a702690827..09711e4e6f0 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -111,6 +111,10 @@ TEST_F(ViewAXPlatformNodeDelegateTest, BoundsShouldMatch) {
}
TEST_F(ViewAXPlatformNodeDelegateTest, LabelIsChildOfButton) {
+ // Disable focus rings for this test: they introduce extra children that can
+ // be either before or after the label, which complicates correctness testing.
+ button_->SetInstallFocusRingOnFocus(false);
+
// |button_| is focusable, so |label_| (as its child) should be ignored.
EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, button_->focus_behavior());
EXPECT_EQ(1, button_accessibility()->GetChildCount());
diff --git a/chromium/ui/views/animation/bounds_animator.h b/chromium/ui/views/animation/bounds_animator.h
index c0a6501fc0d..e72714fefb3 100644
--- a/chromium/ui/views/animation/bounds_animator.h
+++ b/chromium/ui/views/animation/bounds_animator.h
@@ -161,7 +161,7 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
// Parent of all views being animated.
View* parent_;
- base::ObserverList<BoundsAnimatorObserver> observers_;
+ base::ObserverList<BoundsAnimatorObserver>::Unchecked observers_;
// All animations we create up with the same container.
scoped_refptr<gfx::AnimationContainer> container_;
diff --git a/chromium/ui/views/animation/ink_drop.h b/chromium/ui/views/animation/ink_drop.h
index 00de74cc3e3..735f0f9a06b 100644
--- a/chromium/ui/views/animation/ink_drop.h
+++ b/chromium/ui/views/animation/ink_drop.h
@@ -81,7 +81,7 @@ class VIEWS_EXPORT InkDrop {
void NotifyInkDropRippleAnimationEnded(InkDropState state);
private:
- base::ObserverList<InkDropObserver> observers_;
+ base::ObserverList<InkDropObserver>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(InkDrop);
};
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index b746bb4c231..9fc042cd02f 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -27,42 +27,13 @@
namespace views {
-namespace internal {
-
-BorderImages::BorderImages(const int border_image_ids[],
- const int arrow_image_ids[],
- int border_interior_thickness,
- int arrow_interior_thickness,
- int corner_radius)
- : border_thickness(border_interior_thickness),
- border_interior_thickness(border_interior_thickness),
- arrow_thickness(arrow_interior_thickness),
- arrow_interior_thickness(arrow_interior_thickness),
- arrow_width(2 * arrow_interior_thickness),
- corner_radius(corner_radius) {
- if (!border_image_ids)
- return;
-
- border_painter = Painter::CreateImageGridPainter(border_image_ids);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- border_thickness = rb.GetImageSkiaNamed(border_image_ids[0])->width();
-
- if (arrow_image_ids[0] != 0) {
- left_arrow = *rb.GetImageSkiaNamed(arrow_image_ids[0]);
- top_arrow = *rb.GetImageSkiaNamed(arrow_image_ids[1]);
- right_arrow = *rb.GetImageSkiaNamed(arrow_image_ids[2]);
- bottom_arrow = *rb.GetImageSkiaNamed(arrow_image_ids[3]);
- arrow_width = top_arrow.width();
- arrow_thickness = top_arrow.height();
- }
-}
-
-BorderImages::~BorderImages() {}
-
-} // namespace internal
-
namespace {
+// GetShadowValues and GetBorderAndShadowFlags cache their results. The shadow
+// values depend on both the shadow elevation and color, so we create a tuple to
+// key the cache.
+typedef std::tuple<int, SkColor> ShadowCacheKey;
+
// The border corner radius for material design bubble borders.
constexpr int kMaterialDesignCornerRadius = 2;
@@ -87,82 +58,6 @@ 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[] = {
- IDR_BUBBLE_TL, IDR_BUBBLE_T, IDR_BUBBLE_TR,
- IDR_BUBBLE_L, 0, IDR_BUBBLE_R,
- IDR_BUBBLE_BL, IDR_BUBBLE_B, IDR_BUBBLE_BR };
-const int kNoShadowArrows[] = {
- IDR_BUBBLE_L_ARROW, IDR_BUBBLE_T_ARROW,
- IDR_BUBBLE_R_ARROW, IDR_BUBBLE_B_ARROW, };
-
-const int kBigShadowImages[] = {
- IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT,
- 0,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM,
- IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT };
-const int kBigShadowArrows[] = {
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT,
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP,
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT,
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM };
-
-const int kSmallShadowImages[] = {
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT,
- 0,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM,
- IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT };
-const int kSmallShadowArrows[] = {
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT,
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP,
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT,
- IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM };
-
-using internal::BorderImages;
-
-// Returns the cached BorderImages for the given |shadow| type.
-BorderImages* GetBorderImages(BubbleBorder::Shadow shadow) {
- // Keep a cache of bubble border image-set painters, arrows, and metrics.
- static BorderImages* kBorderImages[BubbleBorder::SHADOW_COUNT] = { NULL };
-
- CHECK_LT(shadow, BubbleBorder::SHADOW_COUNT);
- struct BorderImages*& set = kBorderImages[shadow];
- if (set)
- return set;
-
- switch (shadow) {
- case BubbleBorder::NO_SHADOW:
- case BubbleBorder::NO_SHADOW_OPAQUE_BORDER:
- set = new BorderImages(kNoShadowImages, kNoShadowArrows, 6, 7, 4);
- break;
- case BubbleBorder::BIG_SHADOW:
- set = new BorderImages(kBigShadowImages, kBigShadowArrows, 23, 9, 2);
- break;
- case BubbleBorder::SMALL_SHADOW:
- set = new BorderImages(kSmallShadowImages, kSmallShadowArrows, 5, 6, 2);
- break;
- case BubbleBorder::NO_ASSETS:
- set = new BorderImages(nullptr, nullptr, 17, 8, 2);
- break;
- case BubbleBorder::SHADOW_COUNT:
- NOTREACHED();
- break;
- }
-
- return set;
-}
-
} // namespace
const int BubbleBorder::kStroke = 1;
@@ -170,14 +65,10 @@ const int BubbleBorder::kStroke = 1;
BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
: arrow_(arrow),
arrow_offset_(0),
- arrow_paint_type_(PAINT_NORMAL),
- alignment_(ALIGN_ARROW_TO_MID_ANCHOR),
shadow_(shadow),
- images_(nullptr),
background_color_(color),
use_theme_background_color_(false) {
DCHECK(shadow_ < SHADOW_COUNT);
- Init();
}
BubbleBorder::~BubbleBorder() {}
@@ -197,23 +88,14 @@ gfx::Insets BubbleBorder::GetBorderAndShadowInsets(
void BubbleBorder::SetCornerRadius(int corner_radius) {
corner_radius_ = corner_radius;
- Init();
-}
-
-void BubbleBorder::set_paint_arrow(ArrowPaintType value) {
- if (UseMaterialDesign())
- 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 (UseMaterialDesign() &&
- (arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER ||
- arrow_ == TOP_CENTER || arrow_ == LEFT_CENTER ||
- arrow_ == RIGHT_CENTER)) {
+ if (arrow_ == TOP_RIGHT || arrow_ == TOP_LEFT || arrow_ == BOTTOM_CENTER ||
+ arrow_ == TOP_CENTER || arrow_ == LEFT_CENTER || arrow_ == RIGHT_CENTER) {
gfx::Rect contents_bounds(contents_size);
// Apply the border part of the inset before calculating coordinates because
// the border should align with the anchor's border. For the purposes of
@@ -258,44 +140,26 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
int w = anchor_rect.width();
int h = anchor_rect.height();
const gfx::Size size(GetSizeForContentsSize(contents_size));
- const int arrow_offset = GetArrowOffset(size);
const int stroke_width = shadow_ == NO_ASSETS ? 0 : kStroke;
- // |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 = UseMaterialDesign()
- ? 0
- : images_->arrow_interior_thickness + stroke_width -
- 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.
- if (arrow_paint_type_ == PAINT_TRANSPARENT)
- arrow_shift += images_->arrow_interior_thickness;
- const bool mid_anchor = alignment_ == ALIGN_ARROW_TO_MID_ANCHOR;
// Calculate the bubble coordinates based on the border and arrow settings.
if (is_arrow_on_horizontal(arrow_)) {
if (is_arrow_on_left(arrow_)) {
- x += mid_anchor ? w / 2 - arrow_offset
- : stroke_width - GetBorderThickness();
+ x += stroke_width;
} else if (is_arrow_at_center(arrow_)) {
- x += w / 2 - arrow_offset;
+ x += w / 2;
} else {
- x += mid_anchor ? w / 2 + arrow_offset - size.width()
- : w - size.width() + GetBorderThickness() - stroke_width;
+ x += w - size.width() - stroke_width;
}
- y += is_arrow_on_top(arrow_) ? h + arrow_shift
- : -arrow_shift - size.height();
+ y += is_arrow_on_top(arrow_) ? h : -size.height();
} else if (has_arrow(arrow_)) {
- x += is_arrow_on_left(arrow_) ? w + arrow_shift
- : -arrow_shift - size.width();
+ x += is_arrow_on_left(arrow_) ? w : -size.width();
if (is_arrow_on_top(arrow_)) {
- y += mid_anchor ? h / 2 - arrow_offset
- : stroke_width - GetBorderThickness();
+ y += stroke_width;
} else if (is_arrow_at_center(arrow_)) {
- y += h / 2 - arrow_offset;
+ y += h / 2;
} else {
- y += mid_anchor ? h / 2 + arrow_offset - size.height()
- : h - size.height() + GetBorderThickness() - stroke_width;
+ y += h - size.height() - stroke_width;
}
} else {
x += (w - size.width()) / 2;
@@ -305,107 +169,28 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
return gfx::Rect(x, y, size.width(), size.height());
}
-int BubbleBorder::GetBorderThickness() const {
- // TODO(estade): this shouldn't be called in MD.
- return UseMaterialDesign()
- ? 0
- : images_->border_thickness - images_->border_interior_thickness;
-}
-
int BubbleBorder::GetBorderCornerRadius() const {
- if (UseMaterialDesign())
- return corner_radius_.value_or(kMaterialDesignCornerRadius);
- return images_->corner_radius;
-}
-
-int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const {
- if (UseMaterialDesign())
- 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)
- return edge_length / 2;
-
- // Calculate the minimum offset to not overlap arrow and corner images.
- const int min = images_->border_thickness + (images_->arrow_width / 2);
- // Ensure the returned value will not cause image overlap, if possible.
- return std::max(min, std::min(arrow_offset_, edge_length - min));
-}
-
-bool BubbleBorder::GetArrowPath(const gfx::Rect& view_bounds,
- gfx::Path* path) const {
- if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL)
- return false;
-
- GetArrowPathFromArrowBounds(GetArrowRect(view_bounds), path);
- return true;
-}
-
-void BubbleBorder::SetBorderInteriorThickness(int border_interior_thickness) {
- // TODO(estade): remove this function.
- DCHECK(!UseMaterialDesign());
- images_->border_interior_thickness = border_interior_thickness;
- if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL)
- images_->border_thickness = border_interior_thickness;
-}
-
-void BubbleBorder::Init() {
- if (UseMaterialDesign()) {
- // Harmony bubbles don't use arrows.
- alignment_ = ALIGN_EDGE_TO_ANCHOR_EDGE;
- arrow_paint_type_ = PAINT_NONE;
- } else {
- images_ = GetBorderImages(shadow_);
- }
+ return corner_radius_.value_or(kMaterialDesignCornerRadius);
}
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
- if (UseMaterialDesign())
- return PaintMd(view, canvas);
-
- gfx::Rect bounds(view.GetContentsBounds());
- bounds.Inset(-GetBorderThickness(), -GetBorderThickness());
- const gfx::Rect arrow_bounds = GetArrowRect(view.GetLocalBounds());
- if (arrow_bounds.IsEmpty()) {
- if (images_->border_painter)
- Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds);
- return;
- }
- if (!images_->border_painter) {
- DrawArrow(canvas, arrow_bounds);
- return;
- }
+ if (shadow_ == NO_ASSETS)
+ return PaintNoAssets(view, canvas);
- // Clip the arrow bounds out to avoid painting the overlapping edge area.
- canvas->Save();
- canvas->ClipRect(arrow_bounds, SkClipOp::kDifference);
- Painter::PaintPainterAt(canvas, images_->border_painter.get(), bounds);
- canvas->Restore();
+ gfx::ScopedCanvas scoped(canvas);
+
+ SkRRect r_rect = GetClientRect(view);
+ canvas->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference,
+ true /*doAntiAlias*/);
- DrawArrow(canvas, arrow_bounds);
+ DrawBorderAndShadow(std::move(r_rect), &cc::PaintCanvas::drawRRect, canvas,
+ md_shadow_elevation_, md_shadow_color_);
}
gfx::Insets BubbleBorder::GetInsets() const {
- if (UseMaterialDesign()) {
- return (shadow_ == NO_ASSETS)
- ? gfx::Insets()
- : GetBorderAndShadowInsets(md_shadow_elevation_);
- }
-
- // 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_))
- return gfx::Insets(inset);
-
- int first_inset = inset;
- int second_inset = std::max(inset, images_->arrow_thickness);
- if (is_arrow_on_horizontal(arrow_) ?
- is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_))
- std::swap(first_inset, second_inset);
- return is_arrow_on_horizontal(arrow_) ?
- gfx::Insets(first_inset, inset, second_inset, inset) :
- gfx::Insets(inset, first_inset, inset, second_inset);
+ return (shadow_ == NO_ASSETS)
+ ? gfx::Insets()
+ : GetBorderAndShadowInsets(md_shadow_elevation_);
}
gfx::Size BubbleBorder::GetMinimumSize() const {
@@ -414,22 +199,26 @@ gfx::Size BubbleBorder::GetMinimumSize() const {
// static
const gfx::ShadowValues& BubbleBorder::GetShadowValues(
- base::Optional<int> elevation) {
- // The shadows are always the same for any elevation, so construct them once
- // and cache.
- static base::NoDestructor<std::map<int, gfx::ShadowValues>> shadow_map;
- if (shadow_map->find(elevation.value_or(-1)) != shadow_map->end())
- return shadow_map->find(elevation.value_or(-1))->second;
+ base::Optional<int> elevation,
+ SkColor color) {
+ // The shadows are always the same for any elevation and color combination, so
+ // construct them once and cache.
+ static base::NoDestructor<std::map<ShadowCacheKey, gfx::ShadowValues>>
+ shadow_map;
+ ShadowCacheKey key(elevation.value_or(-1), color);
+
+ if (shadow_map->find(key) != shadow_map->end())
+ return shadow_map->find(key)->second;
gfx::ShadowValues shadows;
if (elevation.has_value()) {
DCHECK(elevation.value() >= 0);
- shadows = LayoutProvider::Get()->MakeShadowValues(elevation.value());
+ shadows = LayoutProvider::Get()->MakeShadowValues(elevation.value(), color);
} else {
constexpr int kSmallShadowVerticalOffset = 2;
constexpr int kSmallShadowBlur = 4;
- constexpr SkColor kSmallShadowColor = SkColorSetA(SK_ColorBLACK, 0x33);
- constexpr SkColor kLargeShadowColor = SkColorSetA(SK_ColorBLACK, 0x1A);
+ SkColor kSmallShadowColor = SkColorSetA(color, 0x33);
+ SkColor kLargeShadowColor = SkColorSetA(color, 0x1A);
// 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.
@@ -441,30 +230,31 @@ const gfx::ShadowValues& BubbleBorder::GetShadowValues(
});
}
- shadow_map->insert(
- std::pair<int, gfx::ShadowValues>(elevation.value_or(-1), shadows));
- return shadow_map->find(elevation.value_or(-1))->second;
+ shadow_map->insert({key, shadows});
+ return shadow_map->find(key)->second;
}
// static
const cc::PaintFlags& BubbleBorder::GetBorderAndShadowFlags(
- base::Optional<int> elevation) {
- // The flags are always the same for any elevation, so construct them once and
- // cache.
- static base::NoDestructor<std::map<int, cc::PaintFlags>> flag_map;
+ base::Optional<int> elevation,
+ SkColor color) {
+ // The flags are always the same for any elevation and color combination, so
+ // construct them once and cache.
+ static base::NoDestructor<std::map<ShadowCacheKey, cc::PaintFlags>> flag_map;
+ ShadowCacheKey key(elevation.value_or(-1), color);
- if (flag_map->find(elevation.value_or(-1)) != flag_map->end())
- return flag_map->find(elevation.value_or(-1))->second;
+ if (flag_map->find(key) != flag_map->end())
+ return flag_map->find(key)->second;
cc::PaintFlags flags;
constexpr SkColor kBorderColor = SkColorSetA(SK_ColorBLACK, 0x26);
flags.setColor(kBorderColor);
flags.setAntiAlias(true);
- flags.setLooper(gfx::CreateShadowDrawLooper(GetShadowValues(elevation)));
- flag_map->insert(
- std::pair<int, cc::PaintFlags>(elevation.value_or(-1), flags));
+ flags.setLooper(
+ gfx::CreateShadowDrawLooper(GetShadowValues(elevation, color)));
- return flag_map->find(elevation.value_or(-1))->second;
+ flag_map->insert({key, flags});
+ return flag_map->find(key)->second;
}
gfx::Size BubbleBorder::GetSizeForContentsSize(
@@ -473,116 +263,9 @@ gfx::Size BubbleBorder::GetSizeForContentsSize(
gfx::Size size(contents_size);
const gfx::Insets insets = GetInsets();
size.Enlarge(insets.width(), insets.height());
- if (UseMaterialDesign())
- return size;
-
- // Ensure the bubble is large enough to not overlap border and arrow images.
- const int min = 2 * images_->border_thickness;
- // Only take arrow image sizes into account when the bubble tip is shown.
- if (arrow_paint_type_ != PAINT_NORMAL || !has_arrow(arrow_)) {
- size.SetToMax(gfx::Size(min, min));
- return size;
- }
- const int min_with_arrow_width = min + images_->arrow_width;
- const int min_with_arrow_thickness = images_->border_thickness +
- std::max(images_->arrow_thickness + images_->border_interior_thickness,
- images_->border_thickness);
- if (is_arrow_on_horizontal(arrow_))
- size.SetToMax(gfx::Size(min_with_arrow_width, min_with_arrow_thickness));
- else
- size.SetToMax(gfx::Size(min_with_arrow_thickness, min_with_arrow_width));
return size;
}
-gfx::ImageSkia* BubbleBorder::GetArrowImage() const {
- if (!has_arrow(arrow_))
- return NULL;
- if (is_arrow_on_horizontal(arrow_)) {
- return is_arrow_on_top(arrow_) ?
- &images_->top_arrow : &images_->bottom_arrow;
- }
- return is_arrow_on_left(arrow_) ?
- &images_->left_arrow : &images_->right_arrow;
-}
-
-gfx::Rect BubbleBorder::GetArrowRect(const gfx::Rect& bounds) const {
- if (!has_arrow(arrow_) || arrow_paint_type_ != PAINT_NORMAL)
- return gfx::Rect();
-
- gfx::Point origin;
- int offset = GetArrowOffset(bounds.size());
- const int half_length = images_->arrow_width / 2;
- const gfx::Insets insets = GetInsets();
-
- if (is_arrow_on_horizontal(arrow_)) {
- origin.set_x(is_arrow_on_left(arrow_) || is_arrow_at_center(arrow_) ?
- offset : bounds.width() - offset);
- origin.Offset(-half_length, 0);
- if (is_arrow_on_top(arrow_))
- origin.set_y(insets.top() - images_->arrow_thickness);
- else
- origin.set_y(bounds.height() - insets.bottom());
- } else {
- origin.set_y(is_arrow_on_top(arrow_) || is_arrow_at_center(arrow_) ?
- offset : bounds.height() - offset);
- origin.Offset(0, -half_length);
- if (is_arrow_on_left(arrow_))
- origin.set_x(insets.left() - images_->arrow_thickness);
- else
- origin.set_x(bounds.width() - insets.right());
- }
-
- if (shadow_ != NO_ASSETS)
- return gfx::Rect(origin, GetArrowImage()->size());
-
- // With no assets, return the size enclosing the path filled in DrawArrow().
- DCHECK_EQ(2 * images_->arrow_interior_thickness, images_->arrow_width);
- int width = images_->arrow_width;
- int height = images_->arrow_interior_thickness;
- if (!is_arrow_on_horizontal(arrow_))
- std::swap(width, height);
- return gfx::Rect(origin, gfx::Size(width, height));
-}
-
-void BubbleBorder::GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
- SkPath* path) const {
- DCHECK(!UseMaterialDesign());
- const bool horizontal = is_arrow_on_horizontal(arrow_);
- const int thickness = images_->arrow_interior_thickness;
- float tip_x = horizontal ? arrow_bounds.CenterPoint().x() :
- is_arrow_on_left(arrow_) ? arrow_bounds.right() - thickness :
- arrow_bounds.x() + thickness;
- float tip_y = !horizontal ? arrow_bounds.CenterPoint().y() + 0.5f :
- is_arrow_on_top(arrow_) ? arrow_bounds.bottom() - thickness :
- arrow_bounds.y() + thickness;
- const bool positive_offset = horizontal ?
- is_arrow_on_top(arrow_) : is_arrow_on_left(arrow_);
- const int offset_to_next_vertex = positive_offset ?
- images_->arrow_interior_thickness : -images_->arrow_interior_thickness;
-
- path->incReserve(4);
- path->moveTo(SkDoubleToScalar(tip_x), SkDoubleToScalar(tip_y));
- path->lineTo(SkDoubleToScalar(tip_x + offset_to_next_vertex),
- SkDoubleToScalar(tip_y + offset_to_next_vertex));
- const int multiplier = horizontal ? 1 : -1;
- path->lineTo(SkDoubleToScalar(tip_x - multiplier * offset_to_next_vertex),
- SkDoubleToScalar(tip_y + multiplier * offset_to_next_vertex));
- path->close();
-}
-
-void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
- const gfx::Rect& arrow_bounds) const {
- DCHECK(!UseMaterialDesign());
- canvas->DrawImageInt(*GetArrowImage(), arrow_bounds.x(), arrow_bounds.y());
- SkPath path;
- GetArrowPathFromArrowBounds(arrow_bounds, &path);
- cc::PaintFlags flags;
- flags.setStyle(cc::PaintFlags::kFill_Style);
- flags.setColor(background_color_);
-
- canvas->DrawPath(path, flags);
-}
-
SkRRect BubbleBorder::GetClientRect(const View& view) const {
gfx::RectF bounds(view.GetLocalBounds());
bounds.Inset(GetInsets());
@@ -590,20 +273,6 @@ SkRRect BubbleBorder::GetClientRect(const View& view) const {
GetBorderCornerRadius(), GetBorderCornerRadius());
}
-void BubbleBorder::PaintMd(const View& view, gfx::Canvas* canvas) {
- if (shadow_ == NO_ASSETS)
- return PaintNoAssets(view, canvas);
-
- gfx::ScopedCanvas scoped(canvas);
-
- SkRRect r_rect = GetClientRect(view);
- canvas->sk_canvas()->clipRRect(r_rect, SkClipOp::kDifference,
- true /*doAntiAlias*/);
-
- DrawBorderAndShadow(std::move(r_rect), &cc::PaintCanvas::drawRRect, canvas,
- md_shadow_elevation_);
-}
-
void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) {
gfx::ScopedCanvas scoped(canvas);
canvas->sk_canvas()->clipRRect(GetClientRect(view), SkClipOp::kDifference,
@@ -611,15 +280,6 @@ void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) {
canvas->sk_canvas()->drawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
}
-internal::BorderImages* BubbleBorder::GetImagesForTest() const {
- return images_;
-}
-
-bool BubbleBorder::UseMaterialDesign() const {
- return ui::MaterialDesignController::IsSecondaryUiMaterial() ||
- corner_radius_.has_value();
-}
-
void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
canvas->DrawColor(border_->background_color());
diff --git a/chromium/ui/views/bubble/bubble_border.h b/chromium/ui/views/bubble/bubble_border.h
index 778d93070d8..d4a6e2a28a7 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -12,58 +12,19 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/shadow_value.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
-class SkPath;
class SkRRect;
namespace gfx {
-class Path;
class Rect;
}
namespace views {
-class Painter;
-
-namespace internal {
-
-// A helper that combines each border image-set painter with arrows and metrics.
-struct BorderImages {
- BorderImages(const int border_image_ids[],
- const int arrow_image_ids[],
- int border_interior_thickness,
- int arrow_interior_thickness,
- int corner_radius);
- virtual ~BorderImages();
-
- std::unique_ptr<Painter> border_painter;
- gfx::ImageSkia left_arrow;
- gfx::ImageSkia top_arrow;
- gfx::ImageSkia right_arrow;
- gfx::ImageSkia bottom_arrow;
-
- // The thickness of border and arrow images and their interior areas.
- // Thickness is the width of left/right and the height of top/bottom images.
- // The interior is measured without including stroke or shadow pixels. The tip
- // of the arrow is |arrow_interior_thickness| from the border and the base is
- // always twice that; drawn in the background color.
- int border_thickness;
- int border_interior_thickness;
- int arrow_thickness;
- int arrow_interior_thickness;
-
- // Width of an arrow (on the horizontal), including any shadows. Defaults to
- // the width of the |top_arrow| asset.
- int arrow_width;
-
- // The corner radius of the bubble's rounded-rect interior area.
- int corner_radius;
-};
-
-} // namespace internal
// Renders a border, with optional arrow, and a custom dropshadow.
// This can be used to produce floating "bubble" objects with rounded corners.
@@ -115,26 +76,6 @@ class VIEWS_EXPORT BubbleBorder : public Border {
#else
DIALOG_SHADOW = SMALL_SHADOW,
#endif
-
- };
-
- // The position of the bubble in relation to the anchor.
- enum BubbleAlignment {
- // The tip of the arrow points to the middle of the anchor.
- ALIGN_ARROW_TO_MID_ANCHOR,
- // The edge nearest to the arrow is lined up with the edge of the anchor.
- ALIGN_EDGE_TO_ANCHOR_EDGE,
- };
-
- // 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,
- // Leave space for the arrow, but do not paint it.
- PAINT_TRANSPARENT,
- // Neither paint nor leave space for the arrow.
- PAINT_NONE,
};
// Specific to MD bubbles: size of shadow blur (outside the bubble) and
@@ -187,7 +128,8 @@ class VIEWS_EXPORT BubbleBorder : public Border {
T rect,
void (cc::PaintCanvas::*draw)(const T&, const cc::PaintFlags&),
gfx::Canvas* canvas,
- base::Optional<int> shadow_elevation = base::nullopt) {
+ base::Optional<int> shadow_elevation = base::nullopt,
+ SkColor shadow_base_color = SK_ColorBLACK) {
// Borders with custom shadow elevations do not draw the 1px border.
if (!shadow_elevation.has_value()) {
// Provide a 1 px border outside the bounds.
@@ -197,8 +139,8 @@ class VIEWS_EXPORT BubbleBorder : public Border {
rect.outset(one_pixel, one_pixel);
}
- (canvas->sk_canvas()->*draw)(rect,
- GetBorderAndShadowFlags(shadow_elevation));
+ (canvas->sk_canvas()->*draw)(
+ rect, GetBorderAndShadowFlags(shadow_elevation, shadow_base_color));
}
// Set the corner radius, enables Material Design.
@@ -208,10 +150,6 @@ class VIEWS_EXPORT BubbleBorder : public Border {
void set_arrow(Arrow arrow) { arrow_ = arrow; }
Arrow arrow() const { return arrow_; }
- // Get or set the bubble alignment.
- void set_alignment(BubbleAlignment alignment) { alignment_ = alignment; }
- BubbleAlignment alignment() const { return alignment_; }
-
// Get the shadow type.
Shadow shadow() const { return shadow_; }
@@ -233,42 +171,25 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// location to place the arrow |offset| pixels from the perpendicular edge.
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);
-
// Sets the shadow elevation for MD shadows. A null |shadow_elevation| will
// yield the default BubbleBorder MD shadow.
void set_md_shadow_elevation(int shadow_elevation) {
- DCHECK(UseMaterialDesign()) << "Setting a non-default MD shadow elevation "
- "requires that the BubbleBorder is using MD";
md_shadow_elevation_ = shadow_elevation;
}
+ // Sets the shadow color for MD shadows. Defaults to SK_ColorBLACK.
+ void set_md_shadow_color(SkColor shadow_color) {
+ md_shadow_color_ = shadow_color;
+ }
+
// Get the desired widget bounds (in screen coordinates) given the anchor rect
// and bubble content size; calculated from shadow and arrow image dimensions.
virtual gfx::Rect GetBounds(const gfx::Rect& anchor_rect,
const gfx::Size& contents_size) const;
- // Get the border exterior thickness, including stroke and shadow, in pixels.
- int GetBorderThickness() const;
-
// Returns the corner radius of the current image set.
int GetBorderCornerRadius() const;
- // Gets the arrow offset to use.
- int GetArrowOffset(const gfx::Size& border_size) const;
-
- // Retreives the arrow path given |view_bounds|. |view_bounds| should be local
- // bounds of the view.
- // Returns false if |path| is unchanged, which is the case when there is no
- // painted arrow.
- // 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;
@@ -284,55 +205,41 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// bubbles. A null |shadow_elevation| will yield the default BubbleBorder MD
// ShadowValues.
static const gfx::ShadowValues& GetShadowValues(
- base::Optional<int> shadow_elevation = base::nullopt);
+ base::Optional<int> shadow_elevation = base::nullopt,
+ SkColor shadow_base_color = SK_ColorBLACK);
// Returns the paint flags to use for painting the border and shadow based on
// |shadow_elevation|. This is only used for MD bubbles. A null
// |shadow_elevation| will yield the default BubbleBorder MD PaintFlags.
static const cc::PaintFlags& GetBorderAndShadowFlags(
- base::Optional<int> shadow_elevation = base::nullopt);
+ base::Optional<int> shadow_elevation = base::nullopt,
+ SkColor shadow_base_color = SK_ColorBLACK);
// The border and arrow stroke size used in image assets, in pixels.
static const int kStroke;
- // Initializes the MD or non-MD BubbleBorder.
- void Init();
-
gfx::Size GetSizeForContentsSize(const gfx::Size& contents_size) const;
- gfx::ImageSkia* GetArrowImage() const;
- gfx::Rect GetArrowRect(const gfx::Rect& bounds) const;
- void GetArrowPathFromArrowBounds(const gfx::Rect& arrow_bounds,
- SkPath* path) const;
- void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const;
// Returns the region within |view| representing the client area. This can be
// set as a canvas clip to ensure any fill or shadow from the border does not
// draw over the contents of the bubble.
SkRRect GetClientRect(const View& view) const;
- // Paints an MD border. Ignores |shadow_|.
- void PaintMd(const View& view, gfx::Canvas* canvas);
-
// Paint for the NO_ASSETS shadow type. This just paints transparent pixels
// to make the window shape based on insets and GetBorderCornerRadius().
void PaintNoAssets(const View& view, gfx::Canvas* canvas);
- internal::BorderImages* GetImagesForTest() const;
-
- // Whether to use material design.
- bool UseMaterialDesign() const;
-
Arrow arrow_;
int arrow_offset_;
// Corner radius for the bubble border. If supplied the border will use
// material design.
base::Optional<int> corner_radius_;
- // Elevation for the MD shadow. Requires material design.
- base::Optional<SkColor> md_shadow_elevation_;
- ArrowPaintType arrow_paint_type_;
- BubbleAlignment alignment_;
+
Shadow shadow_;
- internal::BorderImages* images_;
+ // Elevation for the MD shadow.
+ base::Optional<int> md_shadow_elevation_;
+ // Color for the MD shadow.
+ SkColor md_shadow_color_ = SK_ColorBLACK;
SkColor background_color_;
bool use_theme_background_color_;
diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc
index 87ca9bc7786..e1420089ab5 100644
--- a/chromium/ui/views/bubble/bubble_border_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_border_unittest.cc
@@ -16,13 +16,6 @@
#include "ui/views/test/views_test_base.h"
namespace views {
-namespace {
-
-bool UseMd() {
- return ui::MaterialDesignController::IsSecondaryUiMaterial();
-}
-
-} // namespace
typedef views::ViewsTestBase BubbleBorderTest;
@@ -223,7 +216,6 @@ TEST_F(BubbleBorderTest, GetSizeForContentsSizeTest) {
BubbleBorder::NO_SHADOW,
SK_ColorWHITE);
- const views::internal::BorderImages* kImages = border.GetImagesForTest();
const gfx::Insets kInsets = border.GetInsets();
// kSmallSize is smaller than the minimum allowable size and does not
@@ -233,106 +225,68 @@ TEST_F(BubbleBorderTest, GetSizeForContentsSizeTest) {
// the resulting size.
const gfx::Size kMediumSize = gfx::Size(50, 60);
- const gfx::Size kSmallHorizArrow(
- UseMd() ? kSmallSize.width() + kInsets.width()
- : 2 * kImages->border_thickness + kImages->arrow_width,
- UseMd() ? kSmallSize.height() + kInsets.height()
- : kImages->border_thickness + kImages->arrow_thickness +
- kImages->border_interior_thickness);
-
- const gfx::Size kSmallVertArrow(
- UseMd() ? kSmallHorizArrow.width() : kSmallHorizArrow.height(),
- UseMd() ? kSmallHorizArrow.height() : kSmallHorizArrow.width());
-
- const gfx::Size kSmallNoArrow(
- UseMd() ? kSmallHorizArrow.width() : 2 * kImages->border_thickness,
- UseMd() ? kSmallHorizArrow.height() : 2 * kImages->border_thickness);
-
- const gfx::Size kMediumHorizArrow(
- UseMd() ? kMediumSize.width() + kInsets.width()
- : kMediumSize.width() + 2 * border.GetBorderThickness(),
- UseMd() ? kMediumSize.height() + kInsets.height()
- : kMediumSize.height() + border.GetBorderThickness() +
- kImages->arrow_thickness);
-
- const gfx::Size kMediumVertArrow(
- UseMd() ? kMediumHorizArrow.width()
- : kMediumSize.width() + border.GetBorderThickness() +
- kImages->arrow_thickness,
- UseMd() ? kMediumHorizArrow.height()
- : kMediumSize.height() + 2 * border.GetBorderThickness());
-
- const gfx::Size kMediumNoArrow(
- UseMd() ? kMediumHorizArrow.width()
- : kMediumSize.width() + 2 * border.GetBorderThickness(),
- UseMd() ? kMediumHorizArrow.height()
- : kMediumSize.height() + 2 * border.GetBorderThickness());
+ const gfx::Size kSmallHorizArrow(kSmallSize.width() + kInsets.width(),
+ kSmallSize.height() + kInsets.height());
+
+ const gfx::Size kSmallVertArrow(kSmallHorizArrow.width(),
+ kSmallHorizArrow.height());
+
+ const gfx::Size kSmallNoArrow(kSmallHorizArrow.width(),
+ kSmallHorizArrow.height());
+
+ const gfx::Size kMediumHorizArrow(kMediumSize.width() + kInsets.width(),
+ kMediumSize.height() + kInsets.height());
+
+ const gfx::Size kMediumVertArrow(kMediumHorizArrow.width(),
+ kMediumHorizArrow.height());
+
+ const gfx::Size kMediumNoArrow(kMediumHorizArrow.width(),
+ kMediumHorizArrow.height());
struct TestCase {
BubbleBorder::Arrow arrow;
gfx::Size content;
- gfx::Size expected_with_arrow;
gfx::Size expected_without_arrow;
};
TestCase cases[] = {
- // Content size: kSmallSize
- { BubbleBorder::TOP_LEFT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
- { BubbleBorder::TOP_CENTER, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
- { BubbleBorder::TOP_RIGHT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
- { BubbleBorder::BOTTOM_LEFT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
- { BubbleBorder::BOTTOM_CENTER, kSmallSize, kSmallHorizArrow,
- kSmallNoArrow },
- { BubbleBorder::BOTTOM_RIGHT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
- { BubbleBorder::LEFT_TOP, kSmallSize, kSmallVertArrow, kSmallNoArrow },
- { BubbleBorder::LEFT_CENTER, kSmallSize, kSmallVertArrow, kSmallNoArrow },
- { BubbleBorder::LEFT_BOTTOM, kSmallSize, kSmallVertArrow, kSmallNoArrow },
- { BubbleBorder::RIGHT_TOP, kSmallSize, kSmallVertArrow, kSmallNoArrow },
- { BubbleBorder::RIGHT_CENTER, kSmallSize, kSmallVertArrow, kSmallNoArrow },
- { BubbleBorder::RIGHT_BOTTOM, kSmallSize, kSmallVertArrow, kSmallNoArrow },
- { BubbleBorder::NONE, kSmallSize, kSmallNoArrow, kSmallNoArrow },
- { BubbleBorder::FLOAT, kSmallSize, kSmallNoArrow, kSmallNoArrow },
-
- // Content size: kMediumSize
- { BubbleBorder::TOP_LEFT, kMediumSize, kMediumHorizArrow, kMediumNoArrow },
- { BubbleBorder::TOP_CENTER, kMediumSize, kMediumHorizArrow,
- kMediumNoArrow },
- { BubbleBorder::TOP_RIGHT, kMediumSize, kMediumHorizArrow, kMediumNoArrow },
- { BubbleBorder::BOTTOM_LEFT, kMediumSize, kMediumHorizArrow,
- kMediumNoArrow },
- { BubbleBorder::BOTTOM_CENTER, kMediumSize, kMediumHorizArrow,
- kMediumNoArrow },
- { BubbleBorder::BOTTOM_RIGHT, kMediumSize, kMediumHorizArrow,
- kMediumNoArrow },
- { BubbleBorder::LEFT_TOP, kMediumSize, kMediumVertArrow, kMediumNoArrow },
- { BubbleBorder::LEFT_CENTER, kMediumSize, kMediumVertArrow,
- kMediumNoArrow },
- { BubbleBorder::LEFT_BOTTOM, kMediumSize, kMediumVertArrow,
- kMediumNoArrow },
- { BubbleBorder::RIGHT_TOP, kMediumSize, kMediumVertArrow, kMediumNoArrow },
- { BubbleBorder::RIGHT_CENTER, kMediumSize, kMediumVertArrow,
- kMediumNoArrow },
- { BubbleBorder::RIGHT_BOTTOM, kMediumSize, kMediumVertArrow,
- kMediumNoArrow },
- { BubbleBorder::NONE, kMediumSize, kMediumNoArrow, kMediumNoArrow },
- { BubbleBorder::FLOAT, kMediumSize, kMediumNoArrow, kMediumNoArrow }
- };
+ // Content size: kSmallSize
+ {BubbleBorder::TOP_LEFT, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::TOP_CENTER, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::TOP_RIGHT, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::BOTTOM_LEFT, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::BOTTOM_CENTER, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::BOTTOM_RIGHT, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::LEFT_TOP, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::LEFT_CENTER, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::LEFT_BOTTOM, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::RIGHT_TOP, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::RIGHT_CENTER, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::RIGHT_BOTTOM, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::NONE, kSmallSize, kSmallNoArrow},
+ {BubbleBorder::FLOAT, kSmallSize, kSmallNoArrow},
+
+ // Content size: kMediumSize
+ {BubbleBorder::TOP_LEFT, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::TOP_CENTER, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::TOP_RIGHT, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::BOTTOM_LEFT, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::BOTTOM_CENTER, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::BOTTOM_RIGHT, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::LEFT_TOP, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::LEFT_CENTER, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::LEFT_BOTTOM, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::RIGHT_TOP, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::RIGHT_CENTER, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::RIGHT_BOTTOM, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::NONE, kMediumSize, kMediumNoArrow},
+ {BubbleBorder::FLOAT, kMediumSize, kMediumNoArrow}};
for (size_t i = 0; i < arraysize(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("i=%d arrow=%d",
static_cast<int>(i), cases[i].arrow));
border.set_arrow(cases[i].arrow);
-
- border.set_paint_arrow(BubbleBorder::PAINT_NORMAL);
- EXPECT_EQ(cases[i].expected_with_arrow,
- border.GetSizeForContentsSize(cases[i].content));
-
- border.set_paint_arrow(BubbleBorder::PAINT_TRANSPARENT);
- EXPECT_EQ(cases[i].expected_without_arrow,
- border.GetSizeForContentsSize(cases[i].content));
-
- border.set_paint_arrow(BubbleBorder::PAINT_NONE);
EXPECT_EQ(cases[i].expected_without_arrow,
border.GetSizeForContentsSize(cases[i].content));
}
@@ -348,195 +302,67 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
const gfx::Size kContentSize(500, 600);
const gfx::Insets kInsets = border.GetInsets();
- const views::internal::BorderImages* kImages = border.GetImagesForTest();
-
border.set_arrow(BubbleBorder::TOP_LEFT);
- const gfx::Size kTotalSizeWithHorizArrow =
- border.GetSizeForContentsSize(kContentSize);
+ const gfx::Size kTotalSize = border.GetSizeForContentsSize(kContentSize);
border.set_arrow(BubbleBorder::RIGHT_BOTTOM);
- const gfx::Size kTotalSizeWithVertArrow =
- border.GetSizeForContentsSize(kContentSize);
+ EXPECT_EQ(kTotalSize, border.GetSizeForContentsSize(kContentSize));
border.set_arrow(BubbleBorder::NONE);
- const gfx::Size kTotalSizeWithNoArrow =
- border.GetSizeForContentsSize(kContentSize);
-
- const int kBorderThickness = border.GetBorderThickness();
-
- const int kArrowOffsetForHorizCenter = kTotalSizeWithHorizArrow.width() / 2;
- const int kArrowOffsetForVertCenter = kTotalSizeWithVertArrow.height() / 2;
- const int kArrowOffsetForNotCenter =
- UseMd() ? 0 : kImages->border_thickness + (kImages->arrow_width / 2);
+ EXPECT_EQ(kTotalSize, border.GetSizeForContentsSize(kContentSize));
const int kStrokeWidth =
shadow == BubbleBorder::NO_ASSETS ? 0 : BubbleBorder::kStroke;
- const int kArrowThickness = UseMd() ? 0 : kImages->arrow_interior_thickness;
- const int kArrowShift =
- UseMd() ? 0 : kArrowThickness + kStrokeWidth - kImages->arrow_thickness;
- const int kHeightDifference =
- kTotalSizeWithHorizArrow.height() - kTotalSizeWithNoArrow.height();
- const int kWidthDifference =
- kTotalSizeWithVertArrow.width() - kTotalSizeWithNoArrow.width();
- EXPECT_EQ(kHeightDifference, kWidthDifference);
-
- // The arrow only makes a difference in height if it is longer than the
- // shadow.
- const int kExpectedHeightDifference =
- UseMd() ? 0
- : std::max(kImages->arrow_thickness +
- kImages->border_interior_thickness,
- kImages->border_thickness) -
- std::max(kImages->border_interior_thickness,
- kImages->border_thickness);
- EXPECT_EQ(kExpectedHeightDifference, kHeightDifference)
- << "Size with arrow: " << kTotalSizeWithHorizArrow.ToString()
- << " vs. size without arrow: " << kTotalSizeWithNoArrow.ToString();
-
- const int kTopHorizArrowY =
- UseMd() ? kAnchor.bottom() + kStrokeWidth - kInsets.top()
- : kAnchor.bottom() + kArrowShift;
- const int kBottomHorizArrowY =
- UseMd() ? kAnchor.y() - kTotalSizeWithHorizArrow.height()
- : kAnchor.y() - kArrowShift - kTotalSizeWithHorizArrow.height();
- const int kLeftVertArrowX = kAnchor.x() + kAnchor.width() + kArrowShift;
- const int kRightVertArrowX =
- UseMd() ? kAnchor.x() - kTotalSizeWithHorizArrow.width()
- : kAnchor.x() - kArrowShift - kTotalSizeWithVertArrow.width();
+ const int kTopHorizArrowY = kAnchor.bottom() + kStrokeWidth - kInsets.top();
+ const int kBottomHorizArrowY = kAnchor.y() - kTotalSize.height();
+ const int kLeftVertArrowX = kAnchor.x() + kAnchor.width();
+ const int kRightVertArrowX = kAnchor.x() - kTotalSize.width();
struct TestCase {
BubbleBorder::Arrow arrow;
- BubbleBorder::BubbleAlignment alignment;
int expected_x;
int expected_y;
};
TestCase cases[] = {
// Horizontal arrow tests.
- {BubbleBorder::TOP_LEFT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- UseMd() ? kAnchor.x() + kStrokeWidth - kInsets.left()
- : kAnchor.CenterPoint().x() - kArrowOffsetForNotCenter,
+ {BubbleBorder::TOP_LEFT, kAnchor.x() + kStrokeWidth - kInsets.left(),
kTopHorizArrowY},
- {BubbleBorder::TOP_LEFT, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
- UseMd() ? kAnchor.x() + kStrokeWidth - kInsets.left()
- : kAnchor.x() + kStrokeWidth - kBorderThickness,
- kTopHorizArrowY},
- {BubbleBorder::TOP_CENTER, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- kAnchor.CenterPoint().x() - kArrowOffsetForHorizCenter,
- kTopHorizArrowY},
- {BubbleBorder::BOTTOM_RIGHT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- UseMd() ? kAnchor.CenterPoint().x() - kTotalSizeWithHorizArrow.width()
- : kAnchor.CenterPoint().x() + kArrowOffsetForNotCenter -
- kTotalSizeWithHorizArrow.width(),
- kBottomHorizArrowY},
- {BubbleBorder::BOTTOM_RIGHT, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
- kAnchor.x() + kAnchor.width() - kTotalSizeWithHorizArrow.width() +
- kBorderThickness - kStrokeWidth,
+ {BubbleBorder::TOP_CENTER,
+ kAnchor.CenterPoint().x() - (kTotalSize.width() / 2), kTopHorizArrowY},
+ {BubbleBorder::BOTTOM_RIGHT,
+ kAnchor.x() + kAnchor.width() - kTotalSize.width() - kStrokeWidth,
kBottomHorizArrowY},
// Vertical arrow tests.
- {BubbleBorder::LEFT_TOP, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- kLeftVertArrowX, kAnchor.CenterPoint().y() - kArrowOffsetForNotCenter},
- {BubbleBorder::LEFT_TOP, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
- kLeftVertArrowX, kAnchor.y() + kStrokeWidth - kBorderThickness},
- {BubbleBorder::LEFT_CENTER, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- kLeftVertArrowX - (UseMd() ? kInsets.right() - kStrokeWidth : 0),
- kAnchor.CenterPoint().y() - kArrowOffsetForVertCenter +
- (UseMd() ? 2 * kStrokeWidth : 0)},
- {BubbleBorder::RIGHT_BOTTOM, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- kRightVertArrowX,
- kAnchor.CenterPoint().y() + kArrowOffsetForNotCenter -
- kTotalSizeWithVertArrow.height()},
- {BubbleBorder::RIGHT_BOTTOM, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
- kRightVertArrowX,
- kAnchor.y() + kAnchor.height() - kTotalSizeWithVertArrow.height() +
- kBorderThickness - kStrokeWidth},
+ {BubbleBorder::LEFT_TOP, kLeftVertArrowX, kAnchor.y() + kStrokeWidth},
+ {BubbleBorder::LEFT_CENTER,
+ kLeftVertArrowX - (kInsets.right() - kStrokeWidth),
+ kAnchor.CenterPoint().y() - (kTotalSize.height() / 2) +
+ (2 * kStrokeWidth)},
+ {BubbleBorder::RIGHT_BOTTOM, kRightVertArrowX,
+ kAnchor.y() + kAnchor.height() - kTotalSize.height() - kStrokeWidth},
// No arrow tests.
- {BubbleBorder::NONE, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- kAnchor.x() + (kAnchor.width() - kTotalSizeWithNoArrow.width()) / 2,
+ {BubbleBorder::NONE,
+ kAnchor.x() + (kAnchor.width() - kTotalSize.width()) / 2,
kAnchor.y() + kAnchor.height()},
- {BubbleBorder::FLOAT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
- kAnchor.x() + (kAnchor.width() - kTotalSizeWithNoArrow.width()) / 2,
- kAnchor.y() + (kAnchor.height() - kTotalSizeWithNoArrow.height()) / 2},
+ {BubbleBorder::FLOAT,
+ kAnchor.x() + (kAnchor.width() - kTotalSize.width()) / 2,
+ kAnchor.y() + (kAnchor.height() - kTotalSize.height()) / 2},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- SCOPED_TRACE(base::StringPrintf("i=%d arrow=%d alignment=%d",
- static_cast<int>(i), cases[i].arrow,
- cases[i].alignment));
+ SCOPED_TRACE(base::StringPrintf("shadow=%d i=%d arrow=%d",
+ static_cast<int>(shadow),
+ static_cast<int>(i), cases[i].arrow));
const BubbleBorder::Arrow arrow = cases[i].arrow;
border.set_arrow(arrow);
- border.set_alignment(cases[i].alignment);
-
- border.set_paint_arrow(BubbleBorder::PAINT_NORMAL);
gfx::Point origin = border.GetBounds(kAnchor, kContentSize).origin();
- int expected_x = cases[i].expected_x;
- int expected_y = cases[i].expected_y;
- EXPECT_EQ(expected_x, origin.x());
- EXPECT_EQ(expected_y, origin.y());
-
- border.set_paint_arrow(BubbleBorder::PAINT_TRANSPARENT);
- origin = border.GetBounds(kAnchor, kContentSize).origin();
- if (border.is_arrow_on_horizontal(arrow)) {
- expected_y += BubbleBorder::is_arrow_on_top(arrow)
- ? kArrowThickness
- : (-kArrowThickness + kHeightDifference);
- } else if (BubbleBorder::has_arrow(arrow)) {
- expected_x += BubbleBorder::is_arrow_on_left(arrow)
- ? kArrowThickness
- : (-kArrowThickness + kWidthDifference);
- }
- EXPECT_EQ(expected_x, origin.x());
- EXPECT_EQ(expected_y, origin.y());
-
- border.set_paint_arrow(BubbleBorder::PAINT_NONE);
- origin = border.GetBounds(kAnchor, kContentSize).origin();
- expected_x = cases[i].expected_x;
- expected_y = cases[i].expected_y;
- if (border.is_arrow_on_horizontal(arrow) &&
- !BubbleBorder::is_arrow_on_top(arrow)) {
- expected_y += kHeightDifference;
- } else if (BubbleBorder::has_arrow(arrow) &&
- !border.is_arrow_on_horizontal(arrow) &&
- !BubbleBorder::is_arrow_on_left(arrow)) {
- expected_x += kWidthDifference;
- }
- EXPECT_EQ(expected_x, origin.x());
- EXPECT_EQ(expected_y, origin.y());
+ EXPECT_EQ(cases[i].expected_x, origin.x());
+ EXPECT_EQ(cases[i].expected_y, origin.y());
}
-}
-}
-
-// Ensure all the shadow types pass some size validation and paint sanely.
-TEST_F(BubbleBorderTest, ShadowTypes) {
- if (UseMd())
- return; // This test doesn't mean anything in MD mode.
- const gfx::Rect rect(0, 0, 320, 200);
- View paint_view;
- paint_view.SetBoundsRect(rect);
-
- for (int i = 0; i < BubbleBorder::SHADOW_COUNT; ++i) {
- BubbleBorder::Shadow shadow = static_cast<BubbleBorder::Shadow>(i);
- SCOPED_TRACE(testing::Message() << "BubbleBorder::Shadow: " << shadow);
- gfx::Canvas canvas(gfx::Size(640, 480), 1.0f, false);
- BubbleBorder border(BubbleBorder::TOP_LEFT, shadow, SK_ColorWHITE);
- internal::BorderImages* border_images = border.GetImagesForTest();
-
- // Arrow assets should always be at least as big as the drawn arrow.
- EXPECT_GE(border_images->arrow_thickness,
- border_images->arrow_interior_thickness);
- EXPECT_GE(border_images->arrow_width,
- 2 * border_images->arrow_interior_thickness);
-
- // Border assets should always be at least as thick as the hittable border.
- EXPECT_GE(border_images->border_thickness,
- border_images->border_interior_thickness);
-
- // For a TOP_LEFT arrow, the x-offset always matches the border thickness.
- EXPECT_EQ(border.GetArrowRect(rect).x(), border_images->border_thickness);
- border.Paint(paint_view, &canvas);
}
}
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
index 0bfe54962a2..84d9ade9513 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
@@ -202,11 +202,24 @@ View* BubbleDialogDelegateView::GetAnchorView() const {
return anchor_view_tracker_->view();
}
+void BubbleDialogDelegateView::set_arrow(BubbleBorder::Arrow arrow) {
+ if (arrow_ == arrow)
+ return;
+ arrow_ = arrow;
+
+ // If set_arrow() is called before CreateWidget(), there's no need to update
+ // the BubbleFrameView.
+ if (GetBubbleFrameView()) {
+ GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
+ SizeToContents();
+ }
+}
+
gfx::Rect BubbleDialogDelegateView::GetAnchorRect() const {
if (!GetAnchorView())
return anchor_rect_;
- anchor_rect_ = GetAnchorView()->GetBoundsInScreen();
+ anchor_rect_ = GetAnchorView()->GetAnchorBoundsInScreen();
anchor_rect_.Inset(anchor_view_insets_);
return anchor_rect_;
}
@@ -220,23 +233,6 @@ void BubbleDialogDelegateView::UseCompactMargins() {
set_margins(gfx::Insets(kCompactMargin));
}
-void BubbleDialogDelegateView::SetAlignment(
- BubbleBorder::BubbleAlignment alignment) {
- GetBubbleFrameView()->bubble_border()->set_alignment(alignment);
- SizeToContents();
-}
-
-void BubbleDialogDelegateView::SetArrowPaintType(
- BubbleBorder::ArrowPaintType paint_type) {
- GetBubbleFrameView()->bubble_border()->set_paint_arrow(paint_type);
- SizeToContents();
-}
-
-void BubbleDialogDelegateView::SetBorderInteriorThickness(int thickness) {
- GetBubbleFrameView()->bubble_border()->SetBorderInteriorThickness(thickness);
- SizeToContents();
-}
-
void BubbleDialogDelegateView::OnAnchorBoundsChanged() {
SizeToContents();
}
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate.h b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
index 216578e0961..51a95a0ab17 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_H_
-#define UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_H_
+#ifndef UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_VIEW_H_
+#define UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_VIEW_H_
#include <memory>
@@ -72,7 +72,7 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
const gfx::Rect& anchor_rect() const { return anchor_rect_; }
BubbleBorder::Arrow arrow() const { return arrow_; }
- void set_arrow(BubbleBorder::Arrow arrow) { arrow_ = arrow; }
+ void set_arrow(BubbleBorder::Arrow arrow);
void set_mirror_arrow_in_rtl(bool mirror) { mirror_arrow_in_rtl_ = mirror; }
@@ -89,6 +89,8 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
title_margins_ = title_margins;
}
+ // TODO(pbos): Remove by overriding Views::GetAnchorBoundsInScreen() instead.
+ // See https://crbug.com/869928.
const gfx::Insets& anchor_view_insets() const { return anchor_view_insets_; }
void set_anchor_view_insets(const gfx::Insets& i) { anchor_view_insets_ = i; }
@@ -111,16 +113,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// Sets the content margins to a default picked for smaller bubbles.
void UseCompactMargins();
- // Sets the bubble alignment relative to the anchor. This may only be called
- // after calling CreateBubble.
- void SetAlignment(BubbleBorder::BubbleAlignment alignment);
-
- // 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.
@@ -244,4 +236,4 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
} // namespace views
-#endif // UI_VIEWS_BUBBLE_BUBBLE_DELEGATE2_H_
+#endif // UI_VIEWS_BUBBLE_BUBBLE_DIALOG_DELEGATE_VIEW_H_
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
index 6b0e5d89b70..5de626a2bd4 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include <stddef.h>
@@ -86,10 +86,10 @@ class TestBubbleDialogDelegateView : public BubbleDialogDelegateView {
DISALLOW_COPY_AND_ASSIGN(TestBubbleDialogDelegateView);
};
-class BubbleDialogDelegateTest : public ViewsTestBase {
+class BubbleDialogDelegateViewTest : public ViewsTestBase {
public:
- BubbleDialogDelegateTest() {}
- ~BubbleDialogDelegateTest() override {}
+ BubbleDialogDelegateViewTest() {}
+ ~BubbleDialogDelegateViewTest() override {}
// Creates and shows a test widget that owns its native widget.
Widget* CreateTestWidget() {
@@ -102,12 +102,12 @@ class BubbleDialogDelegateTest : public ViewsTestBase {
}
private:
- DISALLOW_COPY_AND_ASSIGN(BubbleDialogDelegateTest);
+ DISALLOW_COPY_AND_ASSIGN(BubbleDialogDelegateViewTest);
};
} // namespace
-TEST_F(BubbleDialogDelegateTest, CreateDelegate) {
+TEST_F(BubbleDialogDelegateViewTest, CreateDelegate) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -127,7 +127,7 @@ TEST_F(BubbleDialogDelegateTest, CreateDelegate) {
EXPECT_TRUE(bubble_observer.widget_closed());
}
-TEST_F(BubbleDialogDelegateTest, MirrorArrowInRtl) {
+TEST_F(BubbleDialogDelegateViewTest, MirrorArrowInRtl) {
std::string default_locale = base::i18n::GetConfiguredLocale();
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
for (bool rtl : {false, true}) {
@@ -146,7 +146,7 @@ TEST_F(BubbleDialogDelegateTest, MirrorArrowInRtl) {
base::i18n::SetICUDefaultLocale(default_locale);
}
-TEST_F(BubbleDialogDelegateTest, CloseAnchorWidget) {
+TEST_F(BubbleDialogDelegateViewTest, CloseAnchorWidget) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -177,7 +177,7 @@ TEST_F(BubbleDialogDelegateTest, CloseAnchorWidget) {
// This test checks that the bubble delegate is capable to handle an early
// destruction of the used anchor view. (Animations and delayed closure of the
// bubble will call upon the anchor view to get its location).
-TEST_F(BubbleDialogDelegateTest, CloseAnchorViewTest) {
+TEST_F(BubbleDialogDelegateViewTest, CloseAnchorViewTest) {
// Create an anchor widget and add a view to be used as an anchor view.
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
std::unique_ptr<View> anchor_view(new View());
@@ -211,7 +211,7 @@ TEST_F(BubbleDialogDelegateTest, CloseAnchorViewTest) {
}
// Testing that a move of the anchor view will lead to new bubble locations.
-TEST_F(BubbleDialogDelegateTest, TestAnchorRectMovesWithViewTest) {
+TEST_F(BubbleDialogDelegateViewTest, TestAnchorRectMovesWithViewTest) {
// Create an anchor widget and add a view to be used as anchor view.
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
@@ -226,7 +226,7 @@ TEST_F(BubbleDialogDelegateTest, TestAnchorRectMovesWithViewTest) {
EXPECT_NE(view_rect.ToString(), view_rect_2.ToString());
}
-TEST_F(BubbleDialogDelegateTest, ResetAnchorWidget) {
+TEST_F(BubbleDialogDelegateViewTest, ResetAnchorWidget) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -267,7 +267,7 @@ TEST_F(BubbleDialogDelegateTest, ResetAnchorWidget) {
EXPECT_TRUE(bubble_observer.widget_closed());
}
-TEST_F(BubbleDialogDelegateTest, InitiallyFocusedView) {
+TEST_F(BubbleDialogDelegateViewTest, InitiallyFocusedView) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -279,29 +279,28 @@ TEST_F(BubbleDialogDelegateTest, InitiallyFocusedView) {
bubble_widget->CloseNow();
}
-TEST_F(BubbleDialogDelegateTest, NonClientHitTest) {
+TEST_F(BubbleDialogDelegateViewTest, NonClientHitTest) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
BubbleDialogDelegateView::CreateBubble(bubble_delegate);
BubbleFrameView* frame = bubble_delegate->GetBubbleFrameView();
- const int border = frame->bubble_border()->GetBorderThickness();
struct {
const int point;
const int hit;
} cases[] = {
- {border, HTNOWHERE}, {border + 60, HTCLIENT}, {1000, HTNOWHERE},
+ {0, HTNOWHERE}, {60, HTCLIENT}, {1000, HTNOWHERE},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
- << " with border: " << border << ", at point " << cases[i].point;
+ << " at point " << cases[i].point;
}
}
-TEST_F(BubbleDialogDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) {
+TEST_F(BubbleDialogDelegateViewTest, VisibleWhenAnchorWidgetBoundsChanged) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -318,7 +317,7 @@ TEST_F(BubbleDialogDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) {
// Test that setting WidgetDelegate::set_can_activate() to false makes the
// widget created via BubbleDialogDelegateView::CreateBubble() not activatable.
-TEST_F(BubbleDialogDelegateTest, NotActivatable) {
+TEST_F(BubbleDialogDelegateViewTest, NotActivatable) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -329,7 +328,7 @@ TEST_F(BubbleDialogDelegateTest, NotActivatable) {
EXPECT_FALSE(bubble_widget->CanActivate());
}
-TEST_F(BubbleDialogDelegateTest, CloseMethods) {
+TEST_F(BubbleDialogDelegateViewTest, CloseMethods) {
{
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
@@ -373,7 +372,7 @@ TEST_F(BubbleDialogDelegateTest, CloseMethods) {
}
}
-TEST_F(BubbleDialogDelegateTest, CustomTitle) {
+TEST_F(BubbleDialogDelegateViewTest, CustomTitle) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -447,7 +446,7 @@ TEST_F(BubbleDialogDelegateTest, CustomTitle) {
// Ensure the BubbleFrameView correctly resizes when the title is provided by a
// StyledLabel.
-TEST_F(BubbleDialogDelegateTest, StyledLabelTitle) {
+TEST_F(BubbleDialogDelegateViewTest, StyledLabelTitle) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
@@ -478,7 +477,7 @@ TEST_F(BubbleDialogDelegateTest, StyledLabelTitle) {
bubble_widget->GetWindowBoundsInScreen().height());
}
-TEST_F(BubbleDialogDelegateTest, VisibleAnchorChanges) {
+TEST_F(BubbleDialogDelegateViewTest, VisibleAnchorChanges) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(nullptr);
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index 50fce2ddc25..f43e505afb4 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -12,7 +12,6 @@
#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_recorder.h"
#include "ui/display/display.h"
@@ -25,7 +24,7 @@
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/bubble/bubble_border.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/image_view.h"
@@ -127,21 +126,8 @@ std::unique_ptr<Label> BubbleFrameView::CreateDefaultTitleLabel(
// static
Button* BubbleFrameView::CreateCloseButton(ButtonListener* listener) {
ImageButton* close_button = nullptr;
- if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- close_button = CreateVectorImageButton(listener);
- SetImageFromVectorIcon(close_button, vector_icons::kCloseRoundedIcon);
- } else {
- ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
- close_button = new ImageButton(listener);
- close_button->SetImage(Button::STATE_NORMAL,
- *rb->GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
- close_button->SetImage(
- Button::STATE_HOVERED,
- *rb->GetImageNamed(IDR_CLOSE_DIALOG_H).ToImageSkia());
- close_button->SetImage(
- Button::STATE_PRESSED,
- *rb->GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
- }
+ close_button = CreateVectorImageButton(listener);
+ SetImageFromVectorIcon(close_button, vector_icons::kCloseRoundedIcon);
close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
close_button->SizeToPreferredSize();
@@ -249,9 +235,6 @@ void BubbleFrameView::GetWindowMask(const gfx::Size& size,
rect.fBottom += SkIntToScalar(kBottomBorderShadowSize);
window_mask->addRect(rect);
}
- gfx::Path arrow_path;
- if (bubble_border_->GetArrowPath(gfx::Rect(size), &arrow_path))
- window_mask->addPath(arrow_path, 0, 0);
}
void BubbleFrameView::ResetWindowControls() {
@@ -272,6 +255,7 @@ void BubbleFrameView::UpdateWindowTitle() {
!delegate->GetWindowTitle().empty());
default_title_->SetText(delegate->GetWindowTitle());
} // custom_title_'s updates are handled by its creator.
+ Layout();
}
void BubbleFrameView::SizeConstraintsChanged() {}
@@ -574,8 +558,7 @@ void BubbleFrameView::OffsetArrowIfOffScreen(const gfx::Rect& anchor_rect,
// |offscreen_adjust|, e.g. positive |offscreen_adjust| means bubble
// window needs to be moved to the right and that means we need to move arrow
// to the left, and that means negative offset.
- bubble_border_->set_arrow_offset(
- bubble_border_->GetArrowOffset(window_bounds.size()) - offscreen_adjust);
+ bubble_border_->set_arrow_offset(-offscreen_adjust);
if (offscreen_adjust)
SchedulePaint();
}
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index 8dedcaf8203..eef3fda7a3e 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -116,7 +116,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, RemoveFootnoteView);
FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, LayoutWithIcon);
FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, CloseReasons);
- FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateTest, CloseMethods);
+ FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateViewTest, CloseMethods);
// Mirrors the bubble's arrow location on the |vertical| or horizontal axis,
// if the generated window bounds don't fit in the monitor bounds.
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index bd891dc540b..0a060d2fbf5 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -9,13 +9,12 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/text_utils.h"
#include "ui/views/bubble/bubble_border.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/test/test_layout_provider.h"
#include "ui/views/test/test_views.h"
@@ -29,10 +28,6 @@ typedef ViewsTestBase BubbleFrameViewTest;
namespace {
-bool UseMd() {
- return ui::MaterialDesignController::IsSecondaryUiMaterial();
-}
-
const BubbleBorder::Arrow kArrow = BubbleBorder::TOP_LEFT;
const SkColor kColor = SK_ColorRED;
const int kMargin = 6;
@@ -50,7 +45,8 @@ const int kExpectedAdditionalHeight = 12;
class TestBubbleFrameViewWidgetDelegate : public WidgetDelegate {
public:
- TestBubbleFrameViewWidgetDelegate(Widget* widget) : widget_(widget) {}
+ explicit TestBubbleFrameViewWidgetDelegate(Widget* widget)
+ : widget_(widget) {}
~TestBubbleFrameViewWidgetDelegate() override {}
@@ -77,35 +73,31 @@ class TestBubbleFrameViewWidgetDelegate : public WidgetDelegate {
}
private:
- Widget* widget_;
+ Widget* const widget_;
View* contents_view_ = nullptr; // Owned by |widget_|.
bool should_show_close_ = false;
};
class TestBubbleFrameView : public BubbleFrameView {
public:
- TestBubbleFrameView(ViewsTestBase* test_base)
+ explicit TestBubbleFrameView(ViewsTestBase* test_base)
: BubbleFrameView(gfx::Insets(), gfx::Insets(kMargin)),
- test_base_(test_base),
available_bounds_(gfx::Rect(0, 0, 1000, 1000)) {
- SetBubbleBorder(std::unique_ptr<BubbleBorder>(
- new BubbleBorder(kArrow, BubbleBorder::NO_SHADOW, kColor)));
+ SetBubbleBorder(std::make_unique<BubbleBorder>(
+ kArrow, BubbleBorder::NO_SHADOW, kColor));
+ widget_ = std::make_unique<Widget>();
+ widget_delegate_ =
+ std::make_unique<TestBubbleFrameViewWidgetDelegate>(widget_.get());
+ Widget::InitParams params =
+ test_base->CreateParams(Widget::InitParams::TYPE_BUBBLE);
+ params.delegate = widget_delegate_.get();
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ widget_->Init(params);
}
~TestBubbleFrameView() override {}
// View overrides:
const Widget* GetWidget() const override {
- if (!widget_) {
- widget_.reset(new Widget);
- widget_delegate_.reset(
- new TestBubbleFrameViewWidgetDelegate(widget_.get()));
- Widget::InitParams params =
- test_base_->CreateParams(Widget::InitParams::TYPE_BUBBLE);
- params.delegate = widget_delegate_.get();
- params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- widget_->Init(params);
- }
-
return widget_.get();
}
@@ -119,13 +111,10 @@ class TestBubbleFrameView : public BubbleFrameView {
}
private:
- ViewsTestBase* test_base_;
-
- gfx::Rect available_bounds_;
+ const gfx::Rect available_bounds_;
- // Widget returned by GetWidget(). Only created if GetWidget() is called.
- mutable std::unique_ptr<TestBubbleFrameViewWidgetDelegate> widget_delegate_;
- mutable std::unique_ptr<Widget> widget_;
+ std::unique_ptr<TestBubbleFrameViewWidgetDelegate> widget_delegate_;
+ std::unique_ptr<Widget> widget_;
DISALLOW_COPY_AND_ASSIGN(TestBubbleFrameView);
};
@@ -159,9 +148,6 @@ TEST_F(BubbleFrameViewTest, RemoveFootnoteView) {
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());
@@ -368,7 +354,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
gfx::Rect window_bounds;
// Bubbles have a thicker shadow on the bottom in MD.
// Match definition of kLargeShadowVerticalOffset in bubble_border.cc.
- const int kLargeShadowVerticalOffset = UseMd() ? 2 : 0;
+ constexpr int kLargeShadowVerticalOffset = 2;
// Some of these tests may go away once --secondary-ui-md becomes the
// default. Under Material Design mode, the BubbleBorder doesn't support all
@@ -376,16 +362,6 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
// added for MD mode.
// Test that the bubble displays normally when it fits.
- if (!UseMd()) { // TOP_CENTER isn't supported by the bubble_border() in MD.
- frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(500, 100, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525);
- }
-
frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
window_bounds = frame.GetUpdatedWindowBounds(
gfx::Rect(500, 900, 50, 50), // |anchor_rect|
@@ -413,19 +389,6 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
425 + kLargeShadowVerticalOffset);
// Test bubble not fitting left screen edge.
- if (!UseMd()) { // TOP_CENTER isn't supported by the bubble_border() in MD.
- frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(100, 100, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.x(), 0);
- EXPECT_EQ(window_bounds.x() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 125);
- }
-
frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
window_bounds = frame.GetUpdatedWindowBounds(
gfx::Rect(100, 900, 50, 50), // |anchor_rect|
@@ -433,26 +396,8 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
true); // |adjust_if_offscreen|
EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow());
EXPECT_EQ(window_bounds.x(), 0);
- if (!UseMd()) { // There is no arrow offset in MD mode.
- EXPECT_EQ(window_bounds.x() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 125);
- }
// Test bubble not fitting right screen edge.
- if (!UseMd()) { // TOP_CENTER isn't supported by the bubble_border() in MD.
- frame.bubble_border()->set_arrow(BubbleBorder::TOP_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(900, 100, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.right(), 1000);
- EXPECT_EQ(window_bounds.x() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 925);
- }
-
frame.bubble_border()->set_arrow(BubbleBorder::BOTTOM_CENTER);
window_bounds = frame.GetUpdatedWindowBounds(
gfx::Rect(900, 900, 50, 50), // |anchor_rect|
@@ -460,60 +405,6 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) {
true); // |adjust_if_offscreen|
EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, frame.bubble_border()->arrow());
EXPECT_EQ(window_bounds.right(), 1000);
- if (!UseMd()) { // There is no arrow offset in MD mode.
- EXPECT_EQ(window_bounds.x() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 925);
- }
-
- // Test bubble not fitting top screen edge.
- if (!UseMd()) { // Moving the bubble by setting the arrow offset doesn't work
- // in MD mode since there is no arrow displayed.
- frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(100, 100, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.y(), 0);
- EXPECT_EQ(window_bounds.y() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 125);
-
- frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(900, 100, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.y(), 0);
- EXPECT_EQ(window_bounds.y() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 125);
-
- // Test bubble not fitting bottom screen edge.
- frame.bubble_border()->set_arrow(BubbleBorder::LEFT_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(100, 900, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.bottom(), 1000);
- EXPECT_EQ(window_bounds.y() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 925);
-
- frame.bubble_border()->set_arrow(BubbleBorder::RIGHT_CENTER);
- window_bounds = frame.GetUpdatedWindowBounds(
- gfx::Rect(900, 900, 50, 50), // |anchor_rect|
- gfx::Size(500, 500), // |client_size|
- true); // |adjust_if_offscreen|
- EXPECT_EQ(BubbleBorder::RIGHT_CENTER, frame.bubble_border()->arrow());
- EXPECT_EQ(window_bounds.bottom(), 1000);
- EXPECT_EQ(window_bounds.y() +
- frame.bubble_border()->GetArrowOffset(window_bounds.size()),
- 925);
- }
}
TEST_F(BubbleFrameViewTest, GetPreferredSize) {
diff --git a/chromium/ui/views/bubble/info_bubble.h b/chromium/ui/views/bubble/info_bubble.h
index 1c0e5074bff..c1f092d10d1 100644
--- a/chromium/ui/views/bubble/info_bubble.h
+++ b/chromium/ui/views/bubble/info_bubble.h
@@ -8,7 +8,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/strings/string16.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
namespace views {
diff --git a/chromium/ui/views/bubble/tooltip_icon.cc b/chromium/ui/views/bubble/tooltip_icon.cc
index 2b88baf6279..8e1969cd449 100644
--- a/chromium/ui/views/bubble/tooltip_icon.cc
+++ b/chromium/ui/views/bubble/tooltip_icon.cc
@@ -61,7 +61,7 @@ void TooltipIcon::GetAccessibleNodeData(ui::AXNodeData* node_data) {
void TooltipIcon::MouseMovedOutOfHost() {
if (IsMouseHovered()) {
- mouse_watcher_->Start();
+ mouse_watcher_->Start(GetWidget()->GetNativeWindow());
return;
}
@@ -96,7 +96,7 @@ void TooltipIcon::ShowBubble() {
View* frame = bubble_->GetWidget()->non_client_view()->frame_view();
mouse_watcher_ = std::make_unique<MouseWatcher>(
std::make_unique<MouseWatcherViewHost>(frame, gfx::Insets()), this);
- mouse_watcher_->Start();
+ mouse_watcher_->Start(GetWidget()->GetNativeWindow());
}
}
diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc
index 397b49e9b04..9e2994cfefd 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.cc
+++ b/chromium/ui/views/bubble/tray_bubble_view.cc
@@ -221,8 +221,6 @@ TrayBubbleView::TrayBubbleView(const InitParams& init_params)
DCHECK(params_.parent_window);
DCHECK(anchor_widget()); // Computed by BubbleDialogDelegateView().
bubble_border_->set_use_theme_background_color(!init_params.bg_color);
- bubble_border_->set_alignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
- bubble_border_->set_paint_arrow(BubbleBorder::PAINT_NONE);
if (init_params.corner_radius)
bubble_border_->SetCornerRadius(init_params.corner_radius.value());
set_parent_window(params_.parent_window);
@@ -421,7 +419,7 @@ void TrayBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
// cannot see a lag.
mouse_watcher_->set_notify_on_exit_time(
base::TimeDelta::FromMilliseconds(kFrameTimeInMS));
- mouse_watcher_->Start();
+ mouse_watcher_->Start(GetWidget()->GetNativeWindow());
}
}
diff --git a/chromium/ui/views/bubble/tray_bubble_view.h b/chromium/ui/views/bubble/tray_bubble_view.h
index 346641e9ad5..5ef449781bc 100644
--- a/chromium/ui/views/bubble/tray_bubble_view.h
+++ b/chromium/ui/views/bubble/tray_bubble_view.h
@@ -12,7 +12,7 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/events/event.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/mouse_watcher.h"
#include "ui/views/views_export.h"
diff --git a/chromium/ui/views/cocoa/DEPS b/chromium/ui/views/cocoa/DEPS
index 3209b5ac9d8..fcaeee7d596 100644
--- a/chromium/ui/views/cocoa/DEPS
+++ b/chromium/ui/views/cocoa/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+components/viz/common",
"+ui/accelerated_widget_mac",
+ "+ui/views_bridge_mac",
]
diff --git a/chromium/ui/views/cocoa/bridged_content_view.h b/chromium/ui/views/cocoa/bridged_content_view.h
index a5a9b690ef2..a6daf562123 100644
--- a/chromium/ui/views/cocoa/bridged_content_view.h
+++ b/chromium/ui/views/cocoa/bridged_content_view.h
@@ -10,32 +10,36 @@
#include "base/strings/string16.h"
#import "ui/base/cocoa/tool_tip_base_view.h"
#import "ui/base/cocoa/tracking_area.h"
+#include "ui/views/views_export.h"
namespace ui {
class TextInputClient;
}
namespace views {
-class View;
+class BridgedNativeWidget;
}
// The NSView that sits as the root contentView of the NSWindow, whilst it has
// a views::RootView present. Bridges requests from Cocoa to the hosted
// views::View.
+VIEWS_EXPORT
@interface BridgedContentView : ToolTipBaseView<NSTextInputClient,
NSUserInterfaceValidations,
NSDraggingSource> {
@private
- // Weak. The hosted RootView, owned by hostedView_->GetWidget().
- views::View* hostedView_;
+ // Weak, reset by clearView.
+ views::BridgedNativeWidget* bridge_;
// Weak. If non-null the TextInputClient of the currently focused View in the
// hierarchy rooted at |hostedView_|. Owned by the focused View.
+ // TODO(ccameron): Remove this member.
ui::TextInputClient* textInputClient_;
// The TextInputClient about to be set. Requests for a new -inputContext will
// use this, but while the input is changing, |self| still needs to service
// IME requests using the old |textInputClient_|.
+ // TODO(ccameron): Remove this member.
ui::TextInputClient* pendingTextInputClient_;
// A tracking area installed to enable mouseMoved events.
@@ -51,12 +55,12 @@ class View;
base::string16 lastTooltipText_;
}
-@property(readonly, nonatomic) views::View* hostedView;
+@property(readonly, nonatomic) views::BridgedNativeWidget* bridge;
@property(assign, nonatomic) ui::TextInputClient* textInputClient;
@property(assign, nonatomic) BOOL drawMenuBackgroundForBlur;
// Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
-- (id)initWithView:(views::View*)viewToHost;
+- (id)initWithBridge:(views::BridgedNativeWidget*)bridge bounds:(gfx::Rect)rect;
// Clear the hosted view. For example, if it is about to be destroyed.
- (void)clearView;
diff --git a/chromium/ui/views/cocoa/bridged_content_view.mm b/chromium/ui/views/cocoa/bridged_content_view.mm
index d6c0b74b395..9ffa0c183b3 100644
--- a/chromium/ui/views/cocoa/bridged_content_view.mm
+++ b/chromium/ui/views/cocoa/bridged_content_view.mm
@@ -14,7 +14,6 @@
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data_provider_mac.h"
-#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/ime/text_input_client.h"
@@ -32,16 +31,12 @@
#import "ui/gfx/path_mac.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views/cocoa/bridged_native_widget_host.h"
#import "ui/views/cocoa/drag_drop_client_mac.h"
#include "ui/views/controls/label.h"
-#include "ui/views/controls/menu/menu_config.h"
-#include "ui/views/controls/menu/menu_controller.h"
#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;
namespace {
@@ -67,14 +62,6 @@ gfx::Point MovePointToWindow(const NSPoint& point,
NSHeight(content_rect) - point_in_window.y);
}
-// Dispatch |event| to |menu_controller| and return true if |event| is
-// swallowed.
-bool DispatchEventToMenu(MenuController* menu_controller, ui::KeyEvent* event) {
- return menu_controller &&
- menu_controller->OnWillDispatchKeyEvent(event) ==
- ui::POST_DISPATCH_NONE;
-}
-
// Returns true if |client| has RTL text.
bool IsTextRTL(const ui::TextInputClient* client) {
return client && client->GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
@@ -84,7 +71,8 @@ bool IsTextRTL(const ui::TextInputClient* client) {
// otherwise be ignored by a ui::TextInputClient when inserted.
bool IsImeTriggerEvent(NSEvent* event) {
ui::KeyboardCode key = ui::KeyboardCodeFromNSEvent(event);
- return key == ui::VKEY_RETURN || key == ui::VKEY_TAB;
+ return key == ui::VKEY_RETURN || key == ui::VKEY_TAB ||
+ key == ui::VKEY_ESCAPE;
}
// Returns the boundary rectangle for composition characters in the
@@ -218,9 +206,16 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@interface BridgedContentView ()
-// Returns the active menu controller corresponding to |hostedView_|,
-// nil otherwise.
-- (MenuController*)activeMenuController;
+// Dispatch |event| to |bridge_|'s host.
+- (void)dispatchKeyEvent:(ui::KeyEvent*)event;
+
+// Returns true if active menu controller corresponds to this widget. Note that
+// this will synchronously call into the browser process.
+- (BOOL)hasActiveMenuController;
+
+// Dispatch |event| to |menu_controller| and return true if |event| is
+// swallowed.
+- (BOOL)dispatchKeyEventToMenuController:(ui::KeyEvent*)event;
// Passes |event| to the InputMethod for dispatch.
- (void)handleKeyEvent:(ui::KeyEvent*)event;
@@ -273,19 +268,18 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@implementation BridgedContentView
-@synthesize hostedView = hostedView_;
+@synthesize bridge = bridge_;
@synthesize textInputClient = textInputClient_;
@synthesize drawMenuBackgroundForBlur = drawMenuBackgroundForBlur_;
-- (id)initWithView:(views::View*)viewToHost {
- DCHECK(viewToHost);
- gfx::Rect bounds = viewToHost->bounds();
+- (id)initWithBridge:(views::BridgedNativeWidget*)bridge
+ bounds:(gfx::Rect)bounds {
// To keep things simple, assume the origin is (0, 0) until there exists a use
// case for something other than that.
DCHECK(bounds.origin().IsOrigin());
NSRect initialFrame = NSMakeRect(0, 0, bounds.width(), bounds.height());
if ((self = [super initWithFrame:initialFrame])) {
- hostedView_ = viewToHost;
+ bridge_ = bridge;
// Apple's documentation says that NSTrackingActiveAlways is incompatible
// with NSTrackingCursorUpdate, so use NSTrackingActiveInActiveApp.
@@ -326,7 +320,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (void)clearView {
[self setTextInputClient:nullptr];
- hostedView_ = nullptr;
+ bridge_ = nullptr;
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
[cursorTrackingArea_.get() clearOwner];
[self removeTrackingArea:cursorTrackingArea_.get()];
@@ -391,20 +385,22 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
}
-// If |point| is classified as HTCAPTION (draggable background), return nil so
+// If |point| is classified as a draggable background (HTCAPTION), return nil so
// that it can lead to a window drag or double-click in the title bar. Dragging
// could be optimized by telling the window server which regions should be
// instantly draggable without asking (tracked at https://crbug.com/830962).
- (NSView*)hitTest:(NSPoint)point {
gfx::Point flippedPoint(point.x, NSHeight(self.superview.bounds) - point.y);
- int component = hostedView_->GetWidget()->GetNonClientComponent(flippedPoint);
- if (component == HTCAPTION)
+ bool isDraggableBackground = false;
+ bridge_->host()->GetIsDraggableBackgroundAt(flippedPoint,
+ &isDraggableBackground);
+ if (isDraggableBackground)
return nil;
return [super hitTest:point];
}
- (void)processCapturedMouseEvent:(NSEvent*)theEvent {
- if (!hostedView_)
+ if (!bridge_)
return;
NSWindow* source = [theEvent window];
@@ -430,26 +426,19 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (isScrollEvent) {
ui::ScrollEvent event(theEvent);
event.set_location(event_location);
- hostedView_->GetWidget()->OnScrollEvent(&event);
+ bridge_->host()->OnScrollEvent(event);
} else {
ui::MouseEvent event(theEvent);
event.set_location(event_location);
- hostedView_->GetWidget()->OnMouseEvent(&event);
+ bridge_->host()->OnMouseEvent(event);
}
}
- (void)updateTooltipIfRequiredAt:(const gfx::Point&)locationInContent {
- DCHECK(hostedView_);
+ DCHECK(bridge_);
base::string16 newTooltipText;
- views::View* view = hostedView_->GetTooltipHandlerForPoint(locationInContent);
- if (view) {
- gfx::Point viewPoint = locationInContent;
- views::View::ConvertPointToScreen(hostedView_, &viewPoint);
- views::View::ConvertPointFromScreen(view, &viewPoint);
- if (!view->GetTooltipText(viewPoint, &newTooltipText))
- DCHECK(newTooltipText.empty());
- }
+ bridge_->host()->GetTooltipTextAt(locationInContent, &newTooltipText);
if (newTooltipText != lastTooltipText_) {
std::swap(newTooltipText, lastTooltipText_);
[self setToolTipAtMousePoint:base::SysUTF16ToNSString(lastTooltipText_)];
@@ -457,34 +446,46 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)updateFullKeyboardAccess {
- if (!hostedView_)
+ if (!bridge_)
return;
-
- views::FocusManager* focusManager =
- hostedView_->GetWidget()->GetFocusManager();
- if (focusManager)
- focusManager->SetKeyboardAccessible([NSApp isFullKeyboardAccessEnabled]);
+ bridge_->host()->SetKeyboardAccessible([NSApp isFullKeyboardAccessEnabled]);
}
// BridgedContentView private implementation.
-- (MenuController*)activeMenuController {
- MenuController* menuController = MenuController::GetActiveInstance();
- return menuController && menuController->owner() == hostedView_->GetWidget()
- ? menuController
- : nullptr;
+- (void)dispatchKeyEvent:(ui::KeyEvent*)event {
+ bool eventHandled = false;
+ if (bridge_)
+ bridge_->host()->DispatchKeyEvent(*event, &eventHandled);
+ if (eventHandled)
+ event->SetHandled();
}
-- (void)handleKeyEvent:(ui::KeyEvent*)event {
- if (!hostedView_)
- return;
+- (BOOL)hasActiveMenuController {
+ bool hasMenuController = false;
+ if (bridge_)
+ bridge_->host()->GetHasMenuController(&hasMenuController);
+ return hasMenuController;
+}
+
+- (BOOL)dispatchKeyEventToMenuController:(ui::KeyEvent*)event {
+ bool eventSwallowed = false;
+ bool eventHandled = false;
+ if (bridge_) {
+ bridge_->host()->DispatchKeyEventToMenuController(*event, &eventSwallowed,
+ &eventHandled);
+ }
+ if (eventHandled)
+ event->SetHandled();
+ return eventSwallowed;
+}
+- (void)handleKeyEvent:(ui::KeyEvent*)event {
DCHECK(event);
- if (DispatchEventToMenu([self activeMenuController], event))
+ if ([self dispatchKeyEventToMenuController:event])
return;
- ignore_result(
- hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(event));
+ [self dispatchKeyEvent:event];
}
- (BOOL)handleUnhandledKeyDownAsKeyEvent {
@@ -501,7 +502,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
keyCode:(ui::KeyboardCode)keyCode
domCode:(ui::DomCode)domCode
eventFlags:(int)eventFlags {
- if (!hostedView_)
+ if (!bridge_)
return;
// Always propagate the shift modifier if present. Shift doesn't always alter
@@ -513,7 +514,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// Generate a synthetic event with the keycode toolkit-views expects.
ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, eventFlags);
- if (DispatchEventToMenu([self activeMenuController], &event))
+ if ([self dispatchKeyEventToMenuController:&event])
return;
// If there's an active TextInputClient, schedule the editing command to be
@@ -521,8 +522,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (textInputClient_ && textInputClient_->IsTextEditCommandEnabled(command))
textInputClient_->SetTextEditCommandForNextKeyEvent(command);
- ignore_result(
- hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(&event));
+ [self dispatchKeyEvent:&event];
}
- (void)adjustUiEventLocation:(ui::LocatedEvent*)event
@@ -540,7 +540,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)insertTextInternal:(id)text {
- if (!hostedView_)
+ if (!bridge_)
return;
if ([text isKindOfClass:[NSAttributedString class]])
@@ -591,7 +591,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if (isFinalInsertForKeyEvent && ![self hasMarkedText]) {
ui::KeyEvent charEvent([text characterAtIndex:0],
ui::KeyboardCodeFromNSEvent(keyDownEvent_),
- ui::EF_NONE);
+ ui::DomCodeFromNSEvent(keyDownEvent_), ui::EF_NONE);
[self handleKeyEvent:&charEvent];
hasUnhandledKeyDownEvent_ = NO;
if (charEvent.handled())
@@ -599,7 +599,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
// Forward the |text| to |textInputClient_| if no menu is active.
- if (textInputClient_ && ![self activeMenuController]) {
+ if (textInputClient_ && ![self hasActiveMenuController]) {
// If a single character is inserted by keyDown's call to
// interpretKeyEvents: then use InsertChar() to allow editing events to be
// merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible
@@ -614,8 +614,9 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// |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));
+ textInputClient_->InsertChar(
+ ui::KeyEvent([text characterAtIndex:0], ui::VKEY_UNKNOWN,
+ ui::DomCode::NONE, ui::EF_NONE));
// Leave character events that may have triggered IME confirmation for
// inline IME (e.g. Korean) as "unhandled". There will be no more
// -insertText: messages, but we are unable to handle these via
@@ -632,9 +633,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (views::DragDropClientMac*)dragDropClient {
- views::BridgedNativeWidget* bridge =
- views::NativeWidgetMac::GetBridgeForNativeWindow([self window]);
- return bridge ? bridge->drag_drop_client() : nullptr;
+ return bridge_ ? bridge_->drag_drop_client() : nullptr;
}
- (void)undo:(id)sender {
@@ -689,7 +688,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// Translates the location of |theEvent| to toolkit-views coordinates and passes
// the event to NativeWidgetMac for handling.
- (void)mouseEvent:(NSEvent*)theEvent {
- if (!hostedView_)
+ if (!bridge_)
return;
DCHECK([theEvent type] != NSScrollWheel);
@@ -699,8 +698,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// Aura updates tooltips with the help of aura::Window::AddPreTargetHandler().
// Mac hooks in here.
[self updateTooltipIfRequiredAt:event.location()];
-
- hostedView_->GetWidget()->OnMouseEvent(&event);
+ bridge_->host()->OnMouseEvent(event);
}
- (void)forceTouchEvent:(NSEvent*)theEvent {
@@ -720,15 +718,15 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
if ([[self window] firstResponder] != self)
return NO;
BOOL result = [super becomeFirstResponder];
- if (result && hostedView_)
- hostedView_->GetWidget()->GetFocusManager()->RestoreFocusedView();
+ if (result && bridge_)
+ bridge_->host()->SetIsFirstResponder(true);
return result;
}
- (BOOL)resignFirstResponder {
BOOL result = [super resignFirstResponder];
- if (result && hostedView_)
- hostedView_->GetWidget()->GetFocusManager()->StoreFocusedView(true);
+ if (result && bridge_)
+ bridge_->host()->SetIsFirstResponder(false);
return result;
}
@@ -747,22 +745,25 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// window containing it, since AppKit requires a titlebar to give frameless
// windows correct shadows and rounded corners.
NSWindow* window = [self window];
- if (window && [window contentView] == self)
+ if (window && [window contentView] == self) {
newSize = [window contentRectForFrameRect:[window frame]].size;
+ // Ensure that the window geometry be updated on the host side before the
+ // view size is updated.
+ // TODO(ccameron): Consider updating the view size and window size and
+ // position together in UpdateWindowGeometry.
+ // https://crbug.com/875776, https://crbug.com/875731
+ if (bridge_)
+ bridge_->UpdateWindowGeometry();
+ }
[super setFrameSize:newSize];
- if (!hostedView_)
- return;
- hostedView_->SetSize(gfx::Size(newSize.width, newSize.height));
+ if (bridge_)
+ bridge_->host()->SetViewSize(gfx::Size(newSize.width, newSize.height));
}
- (BOOL)isOpaque {
- if (!hostedView_)
- return NO;
-
- ui::Layer* layer = hostedView_->GetWidget()->GetLayer();
- return layer && layer->fills_bounds_opaquely();
+ return bridge_ ? !bridge_->is_translucent_window() : NO;
}
// To maximize consistency with the Cocoa browser (mac_views_browser=0), accept
@@ -803,7 +804,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// If a menu is active, and -[NSView interpretKeyEvents:] asks for the
// input context, return nil. This ensures the action message is sent to
// the view, rather than any NSTextInputClient a subview has installed.
- if ([self activeMenuController])
+ if ([self hasActiveMenuController])
return nil;
// When not in an editable mode, or while entering passwords
@@ -834,11 +835,24 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)keyDown:(NSEvent*)theEvent {
+ BOOL hadMarkedTextAtKeyDown = [self hasMarkedText];
+
// Convert the event into an action message, according to OSX key mappings.
keyDownEvent_ = theEvent;
hasUnhandledKeyDownEvent_ = YES;
[self interpretKeyEvents:@[ theEvent ]];
+ // When there is marked text, -[NSView interpretKeyEvents:] may handle the
+ // event by dismissing the IME window in a way that neither unmarks text, nor
+ // updates any composition. That is, no signal is given either to the
+ // NSTextInputClient or the NSTextInputContext that the IME changed state.
+ // However, we must ensure this key down is not processed as an accelerator.
+ // TODO(tapted): Investigate removing the IsImeTriggerEvent() check - it's
+ // probably not required, but helps tests that expect some events to always
+ // get processed (i.e. TextfieldTest.TextInputClientTest).
+ if (hadMarkedTextAtKeyDown && IsImeTriggerEvent(theEvent))
+ hasUnhandledKeyDownEvent_ = NO;
+
// If |keyDownEvent_| wasn't cleared during -interpretKeyEvents:, it wasn't
// handled. Give Widget accelerators a chance to handle it.
[self handleUnhandledKeyDownAsKeyEvent];
@@ -857,7 +871,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)scrollWheel:(NSEvent*)theEvent {
- if (!hostedView_)
+ if (!bridge_)
return;
ui::ScrollEvent event(theEvent);
@@ -866,14 +880,13 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
// Aura updates tooltips with the help of aura::Window::AddPreTargetHandler().
// Mac hooks in here.
[self updateTooltipIfRequiredAt:event.location()];
-
- hostedView_->GetWidget()->OnScrollEvent(&event);
+ bridge_->host()->OnScrollEvent(event);
}
// Called when we get a three-finger swipe, and they're enabled in System
// Preferences.
- (void)swipeWithEvent:(NSEvent*)event {
- if (!hostedView_)
+ if (!bridge_)
return;
// themblsha: In my testing all three-finger swipes send only a single event
@@ -894,35 +907,24 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
ui::GestureEvent gestureEvent(location.x(), location.y(),
ui::EventFlagsFromNative(event),
ui::EventTimeFromNative(event), swipeDetails);
-
- hostedView_->GetWidget()->OnGestureEvent(&gestureEvent);
+ bridge_->host()->OnGestureEvent(gestureEvent);
}
- (void)quickLookWithEvent:(NSEvent*)theEvent {
- if (!hostedView_)
+ if (!bridge_)
return;
const gfx::Point locationInContent =
gfx::ToFlooredPoint(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);
+ bool foundWord = false;
gfx::DecoratedText decoratedWord;
gfx::Point baselinePoint;
- if (!wordLookupClient->GetWordLookupDataAtPoint(
- locationInTarget, &decoratedWord, &baselinePoint)) {
+ bridge_->host()->GetWordAt(locationInContent, &foundWord, &decoratedWord,
+ &baselinePoint);
+ if (!foundWord)
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:
@@ -1387,6 +1389,12 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (NSAttributedString*)
attributedSubstringForProposedRange:(NSRange)range
actualRange:(NSRangePointer)actualRange {
+ // On TouchBar Macs, the IME subsystem sometimes sends an invalid range with a
+ // non-zero length. This will cause a DCHECK in gfx::Range, so repair it here.
+ // See https://crbug.com/888782.
+ if (range.location == NSNotFound)
+ range.length = 0;
+
gfx::Range actual_range;
base::string16 substring = AttributedSubstringForRangeHelper(
textInputClient_, gfx::Range(range), &actual_range);
@@ -1442,7 +1450,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (void)insertText:(id)text replacementRange:(NSRange)replacementRange {
- if (!hostedView_ || !textInputClient_)
+ if (!bridge_ || !textInputClient_)
return;
textInputClient_->DeleteRange(gfx::Range(replacementRange));
@@ -1524,11 +1532,9 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
command != ui::TextEditCommand::SELECT_ALL)
return NO;
- views::FocusManager* focus_manager =
- hostedView_->GetWidget()->GetFocusManager();
- return focus_manager && focus_manager->GetFocusedView() &&
- focus_manager->GetFocusedView()->GetClassName() ==
- views::Label::kViewClassName;
+ bool is_textual = false;
+ bridge_->host()->GetIsFocusedViewTextual(&is_textual);
+ return is_textual;
}
// NSDraggingSource protocol implementation.
@@ -1550,20 +1556,22 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (id)accessibilityAttributeValue:(NSString*)attribute {
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- return @[ hostedView_->GetNativeViewAccessible() ];
+ return @[ bridge_->host()->GetNativeViewAccessible() ];
}
return [super accessibilityAttributeValue:attribute];
}
- (id)accessibilityHitTest:(NSPoint)point {
- return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point];
+ return
+ [bridge_->host()->GetNativeViewAccessible() accessibilityHitTest:point];
}
- (id)accessibilityFocusedUIElement {
- if (!hostedView_)
+ if (!bridge_)
return nil;
- return [hostedView_->GetNativeViewAccessible() accessibilityFocusedUIElement];
+ return [bridge_->host()->GetNativeViewAccessible()
+ accessibilityFocusedUIElement];
}
@end
diff --git a/chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm b/chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm
index 1497d8d63d8..6f1d18d11c4 100644
--- a/chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm
+++ b/chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm
@@ -7,11 +7,9 @@
#import "base/mac/sdk_forward_declarations.h"
#include "base/strings/sys_string_conversions.h"
#import "ui/base/cocoa/touch_bar_forward_declarations.h"
-#include "ui/base/models/dialog_model.h"
#import "ui/views/cocoa/bridged_content_view.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/window/dialog_client_view.h"
-#include "ui/views/window/dialog_delegate.h"
+#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views/cocoa/bridged_native_widget_host.h"
namespace {
@@ -29,21 +27,9 @@ NSString* const kTouchBarCancelId = @"com.google.chrome-CANCEL";
@implementation BridgedContentView (TouchBarAdditions)
- (void)touchBarButtonAction:(id)sender {
- if (!hostedView_)
- return;
-
- views::DialogDelegate* dialog =
- hostedView_->GetWidget()->widget_delegate()->AsDialogDelegate();
- DCHECK(dialog);
- views::DialogClientView* client = dialog->GetDialogClientView();
-
- if ([sender tag] == ui::DIALOG_BUTTON_OK) {
- client->AcceptWindow();
- return;
- }
-
- DCHECK_EQ([sender tag], ui::DIALOG_BUTTON_CANCEL);
- client->CancelWindow();
+ ui::DialogButton type = static_cast<ui::DialogButton>([sender tag]);
+ if (bridge_)
+ bridge_->host()->DoDialogButtonAction(type);
}
// NSTouchBarDelegate protocol implementation.
@@ -51,7 +37,7 @@ NSString* const kTouchBarCancelId = @"com.google.chrome-CANCEL";
- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
API_AVAILABLE(macos(10.12.2)) {
- if (!hostedView_)
+ if (!bridge_)
return nil;
if ([identifier isEqualToString:kTouchBarDialogButtonsGroupId]) {
@@ -76,19 +62,22 @@ NSString* const kTouchBarCancelId = @"com.google.chrome-CANCEL";
else
return nil;
- ui::DialogModel* model =
- hostedView_->GetWidget()->widget_delegate()->AsDialogDelegate();
- if (!model || !(model->GetDialogButtons() & type))
+ bool buttonExists = false;
+ base::string16 buttonLabel;
+ bool isButtonEnabled = false;
+ bool isButtonDefault = false;
+ bridge_->host()->GetDialogButtonInfo(type, &buttonExists, &buttonLabel,
+ &isButtonEnabled, &isButtonDefault);
+ if (!buttonExists)
return nil;
base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
- NSString* title = base::SysUTF16ToNSString(model->GetDialogButtonLabel(type));
NSButton* button =
- [NSButton buttonWithTitle:title
+ [NSButton buttonWithTitle:base::SysUTF16ToNSString(buttonLabel)
target:self
action:@selector(touchBarButtonAction:)];
- if (type == model->GetDefaultDialogButton()) {
+ if (isButtonDefault) {
// NSAlert uses a private NSButton subclass (_NSTouchBarGroupButton) with
// more bells and whistles. It doesn't use -setBezelColor: directly, but
// this gives an appearance matching the default _NSTouchBarGroupButton.
@@ -97,7 +86,7 @@ NSString* const kTouchBarCancelId = @"com.google.chrome-CANCEL";
blue:0.843
alpha:1.0]];
}
- [button setEnabled:model->IsDialogButtonEnabled(type)];
+ [button setEnabled:isButtonEnabled];
[button setTag:type];
[item setView:button];
return item.autorelease();
@@ -106,12 +95,12 @@ NSString* const kTouchBarCancelId = @"com.google.chrome-CANCEL";
// NSTouchBarProvider protocol implementation (via NSResponder category).
- (NSTouchBar*)makeTouchBar {
- if (!hostedView_)
+ if (!bridge_)
return nil;
- ui::DialogModel* model =
- hostedView_->GetWidget()->widget_delegate()->AsDialogDelegate();
- if (!model || !model->GetDialogButtons())
+ bool buttonsExist = false;
+ bridge_->host()->GetDoDialogButtonsExist(&buttonsExist);
+ if (!buttonsExist)
return nil;
base::scoped_nsobject<NSTouchBar> bar(
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h
index 674a9b78228..6d2d12e6455 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget.h
+++ b/chromium/ui/views/cocoa/bridged_native_widget.h
@@ -13,32 +13,28 @@
#import "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#import "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/accelerated_widget_mac/ca_transaction_observer.h"
#include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
-#include "ui/base/ime/input_method_delegate.h"
-#include "ui/compositor/layer_owner.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/display/display_observer.h"
#import "ui/views/cocoa/bridged_native_widget_owner.h"
#import "ui/views/cocoa/cocoa_mouse_capture_delegate.h"
#import "ui/views/focus/focus_manager.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
-#include "ui/views/window/dialog_observer.h"
+#include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
@class BridgedContentView;
@class ModalShowAnimationWithLayer;
+@class NativeWidgetMacNSWindow;
@class ViewsNSWindowDelegate;
-namespace ui {
-class InputMethod;
-class RecyclableCompositorMac;
-}
-
namespace views {
namespace test {
class BridgedNativeWidgetTestApi;
}
+class BridgedNativeWidgetHost;
class CocoaMouseCapture;
class CocoaWindowMoveLoop;
class DragDropClientMac;
@@ -49,46 +45,40 @@ class View;
// DesktopNativeWidgetMac. Serves as a helper class to bridge requests from the
// NativeWidgetMac to the Cocoa window. Behaves a bit like an aura::Window.
class VIEWS_EXPORT BridgedNativeWidget
- : public ui::CATransactionCoordinator::PreCommitObserver,
- public ui::LayerDelegate,
- public ui::LayerOwner,
- public ui::internal::InputMethodDelegate,
+ : public views_bridge_mac::mojom::BridgedNativeWidget,
+ public display::DisplayObserver,
+ public ui::CATransactionCoordinator::PreCommitObserver,
public CocoaMouseCaptureDelegate,
- public FocusChangeListener,
- public ui::AcceleratedWidgetMacNSView,
- public BridgedNativeWidgetOwner,
- public DialogObserver {
+ public BridgedNativeWidgetOwner {
public:
// Contains NativeViewHost->gfx::NativeView associations.
using AssociatedViews = std::map<const views::View*, NSView*>;
- // Ways of changing the visibility of the bridged NSWindow.
- enum WindowVisibilityState {
- HIDE_WINDOW, // Hides with -[NSWindow orderOut:].
- SHOW_AND_ACTIVATE_WINDOW, // Shows with -[NSWindow makeKeyAndOrderFront:].
- SHOW_INACTIVE, // Shows with -[NSWindow orderWindow:..]. Orders
- // the window above its parent if it has one.
- };
-
// Return the size that |window| will take for the given client area |size|,
// based on its current style mask.
static gfx::Size GetWindowSizeForClientSize(NSWindow* window,
const gfx::Size& size);
- // Creates one side of the bridge. |parent| must not be NULL.
- explicit BridgedNativeWidget(NativeWidgetMac* parent);
+ // Creates one side of the bridge. |host| and |parent| must not be NULL.
+ BridgedNativeWidget(BridgedNativeWidgetHost* host, NativeWidgetMac* parent);
~BridgedNativeWidget() override;
- // Initialize the bridge, "retains" ownership of |window|.
- void Init(base::scoped_nsobject<NSWindow> window,
- const Widget::InitParams& params);
+ // Initialize the NSWindow by taking ownership of the specified object.
+ // TODO(ccameron): When a BridgedNativeWidget is allocated across a process
+ // boundary, it will not be possible to explicitly set an NSWindow in this
+ // way.
+ void SetWindow(base::scoped_nsobject<NativeWidgetMacNSWindow> window);
- // Invoked at the end of Widget::Init().
- void OnWidgetInitDone();
+ // Create the drag drop client for this widget.
+ // TODO(ccameron): This function takes a views::View (and is not rolled into
+ // CreateContentView) because drag-drop has not been routed through |host_|
+ // yet.
+ void CreateDragDropClient(views::View* view);
- // Sets or clears the focus manager to use for tracking focused views.
- // This does NOT take ownership of |focus_manager|.
- void SetFocusManager(FocusManager* focus_manager);
+ // Set the parent NSView for the widget.
+ // TODO(ccameron): Like SetWindow, this will need to pass a handle instead of
+ // an NSView across processes.
+ void SetParent(NSView* parent);
// Changes the bounds of the window and the hosted layer if present. The
// origin is a location in screen coordinates except for "child" windows,
@@ -98,20 +88,6 @@ class VIEWS_EXPORT BridgedNativeWidget
// views::GetAuraWindowTypeForWidgetType does not consider a "popup" type.
void SetBounds(const gfx::Rect& new_bounds);
- // Set or clears the views::View bridged by the content view. This does NOT
- // take ownership of |view|.
- void SetRootView(views::View* view);
-
- // Sets the desired visibility of the window and updates the visibility of
- // descendant windows where necessary.
- void SetVisibilityState(WindowVisibilityState new_state);
-
- // Acquiring mouse capture first steals capture from any existing
- // CocoaMouseCaptureDelegate, then captures all mouse events until released.
- void AcquireCapture();
- void ReleaseCapture();
- bool HasCapture();
-
// Start moving the window, pinned to the mouse cursor, and monitor events.
// Return MOVE_LOOP_SUCCESSFUL on mouse up or MOVE_LOOP_CANCELED on premature
// termination via EndMoveLoop() or when window is destroyed during the drag.
@@ -162,23 +138,10 @@ class VIEWS_EXPORT BridgedNativeWidget
// Called by the NSWindowDelegate when the window becomes or resigns key.
void OnWindowKeyStatusChangedTo(bool is_key);
- // Called by NativeWidgetMac when the window size constraints change.
- void OnSizeConstraintsChanged();
-
// Called by the window show animation when it completes and wants to destroy
// itself.
void OnShowAnimationComplete();
- // See widget.h for documentation.
- ui::InputMethod* GetInputMethod();
-
- // The restored bounds will be derived from the current NSWindow frame unless
- // fullscreen or transitioning between fullscreen states.
- gfx::Rect GetRestoredBounds() const;
-
- // Creates a ui::Compositor which becomes responsible for drawing the window.
- void CreateLayer(ui::LayerType layer_type, bool translucent);
-
// Updates |associated_views_| on NativeViewHost::Attach()/Detach().
void SetAssociationForView(const views::View* view, NSView* native_view);
void ClearAssociationForView(const views::View* view);
@@ -187,11 +150,13 @@ class VIEWS_EXPORT BridgedNativeWidget
NativeWidgetMac* native_widget_mac() { return native_widget_mac_; }
BridgedContentView* ns_view() { return bridged_view_; }
- NSWindow* ns_window() { return window_; }
+ BridgedNativeWidgetHost* host() { return host_; }
+ NSWindow* ns_window();
TooltipManager* tooltip_manager() { return tooltip_manager_.get(); }
DragDropClientMac* drag_drop_client() { return drag_drop_client_.get(); }
+ bool is_translucent_window() const { return is_translucent_window_; }
// The parent widget specified in Widget::InitParams::parent. If non-null, the
// parent will close children before the parent closes, and children will be
@@ -227,12 +192,52 @@ class VIEWS_EXPORT BridgedNativeWidget
bool ShouldRunCustomAnimationFor(
Widget::VisibilityTransition transition) const;
- // ui::CATransactionCoordinator::PreCommitObserver implementation
+ // display::DisplayObserver:
+ void OnDisplayMetricsChanged(const display::Display& display,
+ uint32_t metrics) override;
+
+ // ui::CATransactionCoordinator::PreCommitObserver:
bool ShouldWaitInPreCommit() override;
base::TimeDelta PreCommitTimeout() override;
- // Overridden from ui::internal::InputMethodDelegate:
- ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override;
+ // views_bridge_mac::mojom::BridgedNativeWidget:
+ void InitWindow(views_bridge_mac::mojom::BridgedNativeWidgetInitParamsPtr
+ params) override;
+ void InitCompositorView() override;
+ void CreateContentView(const gfx::Rect& bounds) override;
+ void DestroyContentView() override;
+ void CloseWindow() override;
+ void CloseWindowNow() override;
+ void SetInitialBounds(const gfx::Rect& new_bounds,
+ const gfx::Size& minimum_content_size,
+ const gfx::Vector2d& parent_offset) override;
+ void SetBounds(const gfx::Rect& new_bounds,
+ const gfx::Size& minimum_content_size) override;
+ void SetVisibilityState(
+ views_bridge_mac::mojom::WindowVisibilityState new_state) override;
+ void SetVisibleOnAllSpaces(bool always_visible) override;
+ void SetFullscreen(bool fullscreen) override;
+ void SetMiniaturized(bool miniaturized) override;
+ void SetSizeConstraints(const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ bool is_resizable,
+ bool is_maximizable) override;
+ void SetOpacity(float opacity) override;
+ void SetContentAspectRatio(const gfx::SizeF& aspect_ratio) override;
+ void SetCALayerParams(const gfx::CALayerParams& ca_layer_params) override;
+ void SetWindowTitle(const base::string16& title) override;
+ void MakeFirstResponder() override;
+ void ClearTouchBar() override;
+ void AcquireCapture() override;
+ void ReleaseCapture() override;
+
+ // TODO(ccameron): This method exists temporarily as we move all direct access
+ // of TextInputClient out of BridgedContentView.
+ void SetTextInputClient(ui::TextInputClient* text_input_client);
+
+ // Compute the window and content size, and forward them to |host_|. This will
+ // update widget and compositor size.
+ void UpdateWindowGeometry();
private:
friend class test::BridgedNativeWidgetTestApi;
@@ -243,32 +248,24 @@ class VIEWS_EXPORT BridgedNativeWidget
// Notify descendants of a visibility change.
void NotifyVisibilityChangeDown();
- // Essentially NativeWidgetMac::GetClientAreaBoundsInScreen().size(), but no
- // coordinate transformations are required from AppKit coordinates.
- gfx::Size GetClientAreaSize() const;
-
- // Creates an owned ui::Compositor. For consistency, these functions reflect
- // those in aura::WindowTreeHost.
- void CreateCompositor();
- void InitCompositor();
- void DestroyCompositor();
-
// Installs the NSView for hosting the composited layer.
void AddCompositorSuperview();
- // Size the layer to match the client area bounds, taking into account display
- // scale factor.
- void UpdateLayerProperties();
+ // Query the display properties of the monitor that |window_| is on, and
+ // forward them to |host_|.
+ void UpdateWindowDisplay();
- // Immediately return if there is a composited frame matching |size_in_dip|.
- // Otherwise, asks ui::WindowResizeHelperMac to run tasks until a matching
- // frame is ready, or a timeout occurs.
- void MaybeWaitForFrame(const gfx::Size& size_in_dip);
+ // Return true if the delegate's modal type is window-modal. These display as
+ // a native window "sheet", and have a different lifetime to regular windows.
+ bool IsWindowModalSheet() const;
// Show the window using -[NSApp beginSheet:..], modal for the parent window.
void ShowAsModalSheet();
- // Overridden from CocoaMouseCaptureDelegate:
+ // Returns true if capture exists and is currently active.
+ bool HasCapture();
+
+ // CocoaMouseCaptureDelegate:
void PostCapturedEvent(NSEvent* event) override;
void OnMouseCaptureLost() override;
NSWindow* GetWindow() const override;
@@ -277,85 +274,64 @@ class VIEWS_EXPORT BridgedNativeWidget
// Creates and attaches a new instance if not found.
NSMutableDictionary* GetWindowProperties() const;
- // Overridden from FocusChangeListener:
- void OnWillChangeFocus(View* focused_before,
- View* focused_now) override;
- void OnDidChangeFocus(View* focused_before,
- View* focused_now) override;
-
- // Overridden from ui::LayerDelegate:
- void OnPaintLayer(const ui::PaintContext& context) override;
- void OnDeviceScaleFactorChanged(float old_device_scale_factor,
- float new_device_scale_factor) override;
-
- // Overridden from ui::AcceleratedWidgetMac:
- void AcceleratedWidgetCALayerParamsUpdated() override;
-
- // Overridden from BridgedNativeWidgetOwner:
+ // BridgedNativeWidgetOwner:
NSWindow* GetNSWindow() override;
gfx::Vector2d GetChildWindowOffset() const override;
bool IsVisibleParent() const override;
void RemoveChildWindow(BridgedNativeWidget* child) override;
- // DialogObserver:
- void OnDialogModelChanged() override;
-
- // Set |layer()| to be visible or not visible based on |window_visible_|. If
- // the layer is not visible, then lock the compositor, so we don't draw any
- // new frames.
- void UpdateLayerVisibility();
-
- views::NativeWidgetMac* native_widget_mac_; // Weak. Owns this.
- base::scoped_nsobject<NSWindow> window_;
+ BridgedNativeWidgetHost* const host_; // Weak. Owns this.
+ NativeWidgetMac* const native_widget_mac_; // Weak. Owns |host_|.
+ base::scoped_nsobject<NativeWidgetMacNSWindow> window_;
base::scoped_nsobject<ViewsNSWindowDelegate> window_delegate_;
base::scoped_nsobject<BridgedContentView> bridged_view_;
base::scoped_nsobject<ModalShowAnimationWithLayer> show_animation_;
- std::unique_ptr<ui::InputMethod> input_method_;
std::unique_ptr<CocoaMouseCapture> mouse_capture_;
std::unique_ptr<CocoaWindowMoveLoop> window_move_loop_;
std::unique_ptr<TooltipManager> tooltip_manager_;
std::unique_ptr<DragDropClientMac> drag_drop_client_;
- FocusManager* focus_manager_; // Weak. Owned by our Widget.
- Widget::InitParams::Type widget_type_;
+ ui::ModalType modal_type_ = ui::MODAL_TYPE_NONE;
+ bool is_translucent_window_ = false;
- BridgedNativeWidgetOwner* parent_; // Weak. If non-null, owns this.
+ BridgedNativeWidgetOwner* parent_ = nullptr; // Weak. If non-null, owns this.
std::vector<BridgedNativeWidget*> child_windows_;
+ // The size of the content area of the window most recently sent to |host_|
+ // (and its compositor).
+ gfx::Size content_dip_size_;
+
+ // The size of the frame most recently *received from* the compositor. Note
+ // that during resize (and showing new windows), this will lag behind
+ // |content_dip_size_|, which is the frame size most recently *sent to* the
+ // compositor.
+ gfx::Size compositor_frame_dip_size_;
base::scoped_nsobject<NSView> compositor_superview_;
std::unique_ptr<ui::DisplayCALayerTree> display_ca_layer_tree_;
- std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
// Tracks the bounds when the window last started entering fullscreen. Used to
// provide an answer for GetRestoredBounds(), but not ever sent to Cocoa (it
// has its own copy, but doesn't provide access to it).
gfx::Rect bounds_before_fullscreen_;
- // Tracks the origin of the window (from the top-left of the screen) when it
- // was last reported to toolkit-views. Needed to trigger move notifications
- // associated with a window resize since AppKit won't send move notifications
- // when the top-left point of the window moves vertically. The origin of the
- // window in AppKit coordinates is not actually changing in this case.
- gfx::Point last_window_frame_origin_;
-
// The transition types to animate when not relying on native NSWindow
// animation behaviors. Bitmask of Widget::VisibilityTransition.
int transitions_to_animate_ = Widget::ANIMATE_BOTH;
// Whether this window wants to be fullscreen. If a fullscreen animation is in
// progress then it might not be actually fullscreen.
- bool target_fullscreen_state_;
+ bool target_fullscreen_state_ = false;
// Whether this window is in a fullscreen transition, and the fullscreen state
// can not currently be changed.
- bool in_fullscreen_transition_;
+ bool in_fullscreen_transition_ = false;
// Stores the value last read from -[NSWindow isVisible], to detect visibility
// changes.
- bool window_visible_;
+ bool window_visible_ = false;
// If true, the window is either visible, or wants to be visible but is
// currently hidden due to having a hidden parent.
- bool wants_to_be_visible_;
+ bool wants_to_be_visible_ = false;
// If true, then ignore interactions with CATransactionCoordinator until the
// first frame arrives.
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm
index 69c5f1f44d7..abdbcc45fab 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget.mm
@@ -14,48 +14,69 @@
#include "base/mac/mac_util.h"
#import "base/mac/sdk_forward_declarations.h"
#include "base/single_thread_task_runner.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/surfaces/local_surface_id.h"
-#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+#include "base/strings/sys_string_conversions.h"
#import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
#include "ui/base/hit_test.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_factory.h"
#include "ui/base/layout.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/compositor/recyclable_compositor_mac.h"
+#include "ui/display/screen.h"
#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/bridged_native_widget_host.h"
#import "ui/views/cocoa/cocoa_mouse_capture.h"
#import "ui/views/cocoa/cocoa_window_move_loop.h"
#import "ui/views/cocoa/drag_drop_client_mac.h"
+#import "ui/views/cocoa/native_widget_mac_nswindow.h"
#include "ui/views/cocoa/tooltip_manager_mac.h"
#import "ui/views/cocoa/views_nswindow_delegate.h"
#import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
-#include "ui/views/view.h"
-#include "ui/views/views_delegate.h"
#include "ui/views/widget/native_widget_mac.h"
#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_aura_utils.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/window/dialog_delegate.h"
-extern "C" {
+using views_bridge_mac::mojom::WindowVisibilityState;
-typedef int32_t CGSConnection;
-CGSConnection _CGSDefaultConnection();
-CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection,
- NSInteger windowNumber,
- int radius);
-
-}
namespace {
constexpr auto kUIPaintTimeout = base::TimeDelta::FromSeconds(5);
} // namespace
+// Self-owning animation delegate that starts a hide animation, then calls
+// -[NSWindow close] when the animation ends, releasing itself.
+@interface ViewsNSWindowCloseAnimator : NSObject<NSAnimationDelegate> {
+ @private
+ base::scoped_nsobject<NSWindow> window_;
+ base::scoped_nsobject<NSAnimation> animation_;
+}
++ (void)closeWindowWithAnimation:(NSWindow*)window;
+@end
+
+@implementation ViewsNSWindowCloseAnimator
+
+- (id)initWithWindow:(NSWindow*)window {
+ if ((self = [super init])) {
+ window_.reset([window retain]);
+ animation_.reset(
+ [[ConstrainedWindowAnimationHide alloc] initWithWindow:window]);
+ [animation_ setDelegate:self];
+ [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
+ [animation_ startAnimation];
+ }
+ return self;
+}
+
++ (void)closeWindowWithAnimation:(NSWindow*)window {
+ [[ViewsNSWindowCloseAnimator alloc] initWithWindow:window];
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ [window_ close];
+ [animation_ setDelegate:nil];
+ [self release];
+}
+@end
+
// The NSView that hosts the composited CALayer drawing the UI. It fills the
// window but is not hittable so that accessibility hit tests always go to the
// BridgedContentView.
@@ -131,22 +152,6 @@ using NSViewComparatorValue = __kindof NSView*;
int kWindowPropertiesKey;
-float GetDeviceScaleFactorFromView(NSView* view) {
- return ui::GetScaleFactorForNativeView(view);
-}
-
-// Returns true if bounds passed to window in SetBounds should be treated as
-// though they are in screen coordinates.
-bool PositionWindowInScreenCoordinates(views::Widget* widget,
- views::Widget::InitParams::Type type) {
- // Replicate the logic in desktop_aura/desktop_screen_position_client.cc.
- if (views::GetAuraWindowTypeForWidgetType(type) ==
- aura::client::WINDOW_TYPE_POPUP)
- return true;
-
- return widget && widget->is_top_level();
-}
-
// Returns true if the content_view is reparented.
bool PositionWindowInNativeViewParent(NSView* content_view) {
return [[content_view window] contentView] != content_view;
@@ -231,15 +236,9 @@ gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize(
return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
}
-BridgedNativeWidget::BridgedNativeWidget(NativeWidgetMac* parent)
- : native_widget_mac_(parent),
- focus_manager_(nullptr),
- widget_type_(Widget::InitParams::TYPE_WINDOW), // Updated in Init().
- parent_(nullptr),
- target_fullscreen_state_(false),
- in_fullscreen_transition_(false),
- window_visible_(false),
- wants_to_be_visible_(false) {
+BridgedNativeWidget::BridgedNativeWidget(BridgedNativeWidgetHost* host,
+ NativeWidgetMac* parent)
+ : host_(host), native_widget_mac_(parent) {
DCHECK(parent);
window_delegate_.reset(
[[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
@@ -255,18 +254,54 @@ BridgedNativeWidget::~BridgedNativeWidget() {
ui::CATransactionCoordinator::Get().RemovePreCommitObserver(this);
RemoveOrDestroyChildren();
DCHECK(child_windows_.empty());
- SetFocusManager(nullptr);
- SetRootView(nullptr);
- DestroyCompositor();
+ DestroyContentView();
}
-void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
- const Widget::InitParams& params) {
- widget_type_ = params.type;
-
+void BridgedNativeWidget::SetWindow(
+ base::scoped_nsobject<NativeWidgetMacNSWindow> window) {
DCHECK(!window_);
- window_.swap(window);
+ window_ = std::move(window);
+ [window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
[window_ setDelegate:window_delegate_];
+}
+
+void BridgedNativeWidget::SetParent(NSView* new_parent) {
+ BridgedNativeWidget* bridged_native_widget_parent =
+ NativeWidgetMac::GetBridgeForNativeWindow([new_parent window]);
+ // Remove from the old parent.
+ if (parent_) {
+ parent_->RemoveChildWindow(this);
+ parent_ = nullptr;
+ }
+
+ if (!new_parent)
+ return;
+
+ // Disallow creating child windows of views not currently in an NSWindow.
+ CHECK([new_parent window]);
+
+ // If the parent is another BridgedNativeWidget, just add to the collection
+ // of child windows it owns and manages. Otherwise, create an adapter to
+ // anchor the child widget and observe when the parent NSWindow is closed.
+ if (bridged_native_widget_parent) {
+ parent_ = bridged_native_widget_parent;
+ bridged_native_widget_parent->child_windows_.push_back(this);
+ } else {
+ parent_ = new WidgetOwnerNSWindowAdapter(this, new_parent);
+ }
+
+ // Widget::ShowInactive() could result in a Space switch when the widget has a
+ // parent, and we're calling -orderWindow:relativeTo:. Use Transient
+ // collection behaviour to prevent that.
+ // https://crbug.com/697829
+ [window_ setCollectionBehavior:[window_ collectionBehavior] |
+ NSWindowCollectionBehaviorTransient];
+}
+
+void BridgedNativeWidget::InitWindow(
+ views_bridge_mac::mojom::BridgedNativeWidgetInitParamsPtr params) {
+ modal_type_ = params->modal_type;
+ is_translucent_window_ = params->is_translucent;
// Register for application hide notifications so that visibility can be
// properly tracked. This is not done in the delegate so that the lifetime is
@@ -291,64 +326,27 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
DCHECK(![window_ isVisible]);
DCHECK_EQ(0u, [window_ styleMask] & NSFullScreenWindowMask);
- if (params.parent) {
- // Disallow creating child windows of views not currently in an NSWindow.
- CHECK([params.parent window]);
- BridgedNativeWidget* bridged_native_widget_parent =
- NativeWidgetMac::GetBridgeForNativeWindow([params.parent window]);
- // If the parent is another BridgedNativeWidget, just add to the collection
- // of child windows it owns and manages. Otherwise, create an adapter to
- // anchor the child widget and observe when the parent NSWindow is closed.
- if (bridged_native_widget_parent) {
- parent_ = bridged_native_widget_parent;
- bridged_native_widget_parent->child_windows_.push_back(this);
- } else {
- parent_ = new WidgetOwnerNSWindowAdapter(this, params.parent);
- }
- // crbug.com/697829: Widget::ShowInactive() could result in a Space switch
- // when the widget has a parent, and we're calling -orderWindow:relativeTo:.
- // Use Transient collection behaviour to prevent that.
- [window_ setCollectionBehavior:[window_ collectionBehavior] |
- NSWindowCollectionBehaviorTransient];
- }
-
// Include "regular" windows without the standard frame in the window cycle.
// These use NSBorderlessWindowMask so do not get it by default.
- if (widget_type_ == Widget::InitParams::TYPE_WINDOW &&
- params.remove_standard_frame) {
+ if (params->force_into_collection_cycle) {
[window_
setCollectionBehavior:[window_ collectionBehavior] |
NSWindowCollectionBehaviorParticipatesInCycle];
}
- // OSX likes to put shadows on most things. However, frameless windows (with
- // styleMask = NSBorderlessWindowMask) default to no shadow. So change that.
- // SHADOW_TYPE_DROP is used for Menus, which get the same shadow style on Mac.
- switch (params.shadow_type) {
- case Widget::InitParams::SHADOW_TYPE_NONE:
- [window_ setHasShadow:NO];
- break;
- case Widget::InitParams::SHADOW_TYPE_DEFAULT:
- // Controls should get views shadows instead of native shadows.
- [window_ setHasShadow:params.type != Widget::InitParams::TYPE_CONTROL];
- break;
- case Widget::InitParams::SHADOW_TYPE_DROP:
- [window_ setHasShadow:YES];
- break;
- } // No default case, to pick up new types.
-
- // Set a meaningful initial bounds. Note that except for frameless widgets
- // with no WidgetDelegate, the bounds will be set again by Widget after
- // initializing the non-client view. In the former case, if bounds were not
- // set at all, the creator of the Widget is expected to call SetBounds()
- // before calling Widget::Show() to avoid a kWindowSizeDeterminedLater-sized
- // (i.e. 1x1) window appearing.
- if (!params.bounds.IsEmpty()) {
- SetBounds(params.bounds);
- } else {
+ [window_ setHasShadow:params->has_window_server_shadow];
+ tooltip_manager_.reset(new TooltipManagerMac(this));
+}
+
+void BridgedNativeWidget::SetInitialBounds(
+ const gfx::Rect& new_bounds,
+ const gfx::Size& minimum_content_size,
+ const gfx::Vector2d& bounds_offset_for_parent) {
+ gfx::Rect adjusted_bounds = new_bounds;
+ if (new_bounds.IsEmpty()) {
// If a position is set, but no size, complain. Otherwise, a 1x1 window
// would appear there, which might be unexpected.
- DCHECK(params.bounds.origin().IsOrigin())
+ DCHECK(new_bounds.origin().IsOrigin())
<< "Zero-sized windows not supported on Mac.";
// Otherwise, bounds is all zeroes. Cocoa will currently have the window at
@@ -357,63 +355,28 @@ void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window,
// Read back the current frame: it will be a 1x1 context rect but the frame
// size also depends on the window style.
NSRect frame_rect = [window_ frame];
- SetBounds(gfx::Rect(gfx::Point(),
- gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect))));
+ adjusted_bounds = gfx::Rect(
+ gfx::Point(), gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)));
}
-
- // Widgets for UI controls (usually layered above web contents) start visible.
- if (params.type == Widget::InitParams::TYPE_CONTROL)
- SetVisibilityState(SHOW_INACTIVE);
-
- // Tooltip Widgets shouldn't have their own tooltip manager, but tooltips are
- // native on Mac, so nothing should ever want one in Widget form.
- DCHECK_NE(params.type, Widget::InitParams::TYPE_TOOLTIP);
- tooltip_manager_.reset(new TooltipManagerMac(this));
-}
-
-void BridgedNativeWidget::OnWidgetInitDone() {
- DialogDelegate* dialog =
- native_widget_mac_->GetWidget()->widget_delegate()->AsDialogDelegate();
- if (dialog)
- dialog->AddObserver(this);
-}
-
-void BridgedNativeWidget::SetFocusManager(FocusManager* focus_manager) {
- if (focus_manager_ == focus_manager)
- return;
-
- if (focus_manager_) {
- // Only the destructor can replace the focus manager (and it passes null).
- DCHECK(![window_ delegate]);
- DCHECK(!focus_manager);
- if (View* old_focus = focus_manager_->GetFocusedView())
- OnDidChangeFocus(old_focus, nullptr);
- focus_manager_->RemoveFocusChangeListener(this);
- focus_manager_ = nullptr;
- return;
- }
-
- focus_manager_ = focus_manager;
- focus_manager_->AddFocusChangeListener(this);
- if (View* new_focus = focus_manager_->GetFocusedView())
- OnDidChangeFocus(nullptr, new_focus);
+ adjusted_bounds.Offset(bounds_offset_for_parent);
+ SetBounds(adjusted_bounds, minimum_content_size);
}
-void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
- Widget* widget = native_widget_mac_->GetWidget();
+void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds,
+ const gfx::Size& minimum_content_size) {
// -[NSWindow contentMinSize] is only checked by Cocoa for user-initiated
// resizes. This is not what toolkit-views expects, so clamp. Note there is
// no check for maximum size (consistent with aura::Window::SetBounds()).
gfx::Size clamped_content_size =
GetClientSizeForWindowSize(window_, new_bounds.size());
- clamped_content_size.SetToMax(widget->GetMinimumSize());
+ clamped_content_size.SetToMax(minimum_content_size);
// A contentRect with zero width or height is a banned practice in ChromeMac,
// due to unpredictable OSX treatment.
DCHECK(!clamped_content_size.IsEmpty())
<< "Zero-sized windows not supported on Mac";
- if (!window_visible_ && native_widget_mac_->IsWindowModalSheet()) {
+ if (!window_visible_ && IsWindowModalSheet()) {
// Window-Modal dialogs (i.e. sheets) are positioned by Cocoa when shown for
// the first time. They also have no frame, so just update the content size.
[window_ setContentSize:NSMakeSize(clamped_content_size.width(),
@@ -424,9 +387,6 @@ void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
new_bounds.origin(),
GetWindowSizeForClientSize(window_, clamped_content_size));
- if (parent_ && !PositionWindowInScreenCoordinates(widget, widget_type_))
- actual_new_bounds.Offset(parent_->GetChildWindowOffset());
-
if (PositionWindowInNativeViewParent(bridged_view_))
actual_new_bounds.Offset(GetNativeViewParentOffset(bridged_view_));
@@ -435,29 +395,26 @@ void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) {
animate:NO];
}
-void BridgedNativeWidget::SetRootView(views::View* view) {
- if (view == [bridged_view_ hostedView])
+void BridgedNativeWidget::DestroyContentView() {
+ if (!bridged_view_)
return;
-
- // If this is ever false, the compositor will need to be properly torn down
- // and replaced, pointing at the new view.
- DCHECK(!view || !compositor_);
-
drag_drop_client_.reset();
[bridged_view_ clearView];
bridged_view_.reset();
- // Note that there can still be references to the old |bridged_view_|
- // floating around in Cocoa libraries at this point. However, references to
- // the old views::View will be gone, so any method calls will become no-ops.
+ [window_ setContentView:nil];
+}
- if (view) {
- bridged_view_.reset([[BridgedContentView alloc] initWithView:view]);
- drag_drop_client_.reset(new DragDropClientMac(this, view));
+void BridgedNativeWidget::CreateContentView(const gfx::Rect& bounds) {
+ DCHECK(!bridged_view_);
+ // The compositor needs to point at the new content view created here.
+ DCHECK(!compositor_superview_);
- // Objective C initializers can return nil. However, if |view| is non-NULL
- // this should be treated as an error and caught early.
- CHECK(bridged_view_);
- }
+ bridged_view_.reset(
+ [[BridgedContentView alloc] initWithBridge:this bounds:bounds]);
+
+ // Objective C initializers can return nil. However, if |view| is non-NULL
+ // this should be treated as an error and caught early.
+ CHECK(bridged_view_);
// Layer backing the content view improves resize performance, reduces memory
// use (no backing store), and clips sublayers to rounded window corners.
@@ -466,18 +423,77 @@ void BridgedNativeWidget::SetRootView(views::View* view) {
[window_ setContentView:bridged_view_];
}
+void BridgedNativeWidget::CreateDragDropClient(views::View* view) {
+ drag_drop_client_.reset(new DragDropClientMac(this, view));
+}
+
+void BridgedNativeWidget::CloseWindow() {
+ // Keep |window| on the stack so that the ObjectiveC block below can capture
+ // it and properly increment the reference count bound to the posted task.
+ NSWindow* window = ns_window();
+
+ if (IsWindowModalSheet()) {
+ // Sheets can't be closed normally. This starts the sheet closing. Once the
+ // sheet has finished animating, it will call sheetDidEnd: on the parent
+ // window's delegate. Note it still needs to be asynchronous, since code
+ // calling Widget::Close() doesn't expect things to be deleted upon return.
+ // Ensure |window| is retained by a block. Note in some cases during
+ // teardown, [window sheetParent] may be nil.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(base::RetainBlock(^{
+ [NSApp endSheet:window];
+ })));
+ return;
+ }
+
+ // For other modal types, animate the close.
+ if (ShouldRunCustomAnimationFor(Widget::ANIMATE_HIDE)) {
+ [ViewsNSWindowCloseAnimator closeWindowWithAnimation:window];
+ return;
+ }
+
+ // Destroy the content view so that it won't call back into |host_| while
+ // being torn down.
+ DestroyContentView();
+
+ // Widget::Close() ensures [Non]ClientView::CanClose() returns true, so there
+ // is no need to call the NSWindow or its delegate's -windowShouldClose:
+ // implementation in the manner of -[NSWindow performClose:]. But,
+ // like -performClose:, first remove the window from AppKit's display
+ // list to avoid crashes like http://crbug.com/156101.
+ [window orderOut:nil];
+
+ // 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::BindOnce(base::RetainBlock(^{
+ [window close];
+ })));
+}
+
+void BridgedNativeWidget::CloseWindowNow() {
+ // NSWindows must be retained until -[NSWindow close] returns.
+ auto window_retain = window_;
+
+ // If there's a bridge at this point, it means there must be a window as well.
+ DCHECK(window_);
+ [window_ close];
+ // Note: |this| will be deleted here.
+}
+
void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) {
// Ensure that:
// - A window with an invisible parent is not made visible.
// - A parent changing visibility updates child window visibility.
// * But only when changed via this function - ignore changes via the
// NSWindow API, or changes propagating out from here.
- wants_to_be_visible_ = new_state != HIDE_WINDOW;
+ wants_to_be_visible_ = new_state != WindowVisibilityState::kHideWindow;
[show_animation_ stopAnimation];
DCHECK(!show_animation_);
- if (new_state == HIDE_WINDOW) {
+ if (new_state == WindowVisibilityState::kHideWindow) {
// Calling -orderOut: on a window with an attached sheet encounters broken
// AppKit behavior. The sheet effectively becomes "lost".
// See http://crbug.com/667602. Alternatives: call -setAlphaValue:0 and
@@ -506,12 +522,12 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) {
if (parent() && !parent()->IsVisibleParent())
return;
- if (native_widget_mac_->IsWindowModalSheet()) {
+ if (IsWindowModalSheet()) {
ShowAsModalSheet();
return;
}
- if (new_state == SHOW_AND_ACTIVATE_WINDOW) {
+ if (new_state == WindowVisibilityState::kShowAndActivateWindow) {
[window_ makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
} else {
@@ -560,11 +576,13 @@ void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) {
}
void BridgedNativeWidget::AcquireCapture() {
- DCHECK(!HasCapture());
+ if (HasCapture())
+ return;
if (!window_visible_)
return; // Capture on hidden windows is disallowed.
mouse_capture_.reset(new CocoaMouseCapture(this));
+ host_->OnMouseCaptureActiveChanged(true);
// Initiating global event capture with addGlobalMonitorForEventsMatchingMask:
// will reset the mouse cursor to an arrow. Asking the window for an update
@@ -637,16 +655,13 @@ void BridgedNativeWidget::SetCursor(NSCursor* cursor) {
}
void BridgedNativeWidget::OnWindowWillClose() {
- Widget* widget = native_widget_mac_->GetWidget();
- if (DialogDelegate* dialog = widget->widget_delegate()->AsDialogDelegate())
- dialog->RemoveObserver(this);
- native_widget_mac_->WindowDestroying();
+ host_->OnWindowWillClose();
// Ensure BridgedNativeWidget does not have capture, otherwise
- // OnMouseCaptureLost() may reference a deleted |native_widget_mac_| when
- // called via ~CocoaMouseCapture() upon the destruction of |mouse_capture_|.
- // See crbug.com/622201. Also we do this before setting the delegate to nil,
- // because this may lead to callbacks to bridge which rely on a valid
+ // OnMouseCaptureLost() may reference a deleted |host_| when called via
+ // ~CocoaMouseCapture() upon the destruction of |mouse_capture_|. See
+ // https://crbug.com/622201. Also we do this before setting the delegate to
+ // nil, because this may lead to callbacks to bridge which rely on a valid
// delegate.
ReleaseCapture();
@@ -660,8 +675,8 @@ void BridgedNativeWidget::OnWindowWillClose() {
DCHECK(!show_animation_);
[window_ setDelegate:nil];
- native_widget_mac_->WindowDestroyed();
- // Note: |this| is deleted here.
+ host_->OnWindowHasClosed();
+ // Note: |this| and its host will be deleted here.
}
void BridgedNativeWidget::OnFullscreenTransitionStart(
@@ -674,12 +689,7 @@ void BridgedNativeWidget::OnFullscreenTransitionStart(
target_fullscreen_state_ = target_fullscreen_state;
in_fullscreen_transition_ = true;
- // If going into fullscreen, store an answer for GetRestoredBounds().
- if (target_fullscreen_state)
- bounds_before_fullscreen_ = gfx::ScreenRectFromNSRect([window_ frame]);
-
- // Notify that fullscreen state changed.
- native_widget_mac_->OnWindowFullscreenStateChange();
+ host_->OnWindowFullscreenTransitionStart(target_fullscreen_state);
}
void BridgedNativeWidget::OnFullscreenTransitionComplete(
@@ -687,8 +697,7 @@ void BridgedNativeWidget::OnFullscreenTransitionComplete(
in_fullscreen_transition_ = false;
if (target_fullscreen_state_ == actual_fullscreen_state) {
- // Ensure constraints are re-applied when completing a transition.
- OnSizeConstraintsChanged();
+ host_->OnWindowFullscreenTransitionComplete(actual_fullscreen_state);
return;
}
@@ -720,7 +729,7 @@ void BridgedNativeWidget::ToggleDesiredFullscreenState(bool async) {
// of relying on AppKit to do it, and not worry that OnVisibilityChanged()
// won't be called for externally triggered fullscreen requests.
if (!window_visible_)
- SetVisibilityState(SHOW_INACTIVE);
+ SetVisibilityState(WindowVisibilityState::kShowInactive);
// Enable fullscreen collection behavior because:
// 1: -[NSWindow toggleFullscreen:] would otherwise be ignored,
@@ -738,37 +747,23 @@ void BridgedNativeWidget::ToggleDesiredFullscreenState(bool async) {
withObject:nil
afterDelay:0];
} else {
+ // Suppress synchronous CA transactions during AppKit fullscreen transition
+ // since there is no need for updates during such transition.
+ // Re-layout and re-paint will be done after the transtion. See
+ // https://crbug.com/875707 for potiential problems if we don't suppress.
+ // |ca_transaction_sync_suppressed_| will be reset to false when the next
+ // frame comes in.
+ ca_transaction_sync_suppressed_ = true;
[window_ toggleFullScreen:nil];
}
}
void BridgedNativeWidget::OnSizeChanged() {
- const gfx::Rect new_bounds = native_widget_mac_->GetWindowBoundsInScreen();
- if (new_bounds.origin() != last_window_frame_origin_) {
- native_widget_mac_->GetWidget()->OnNativeWidgetMove();
- last_window_frame_origin_ = new_bounds.origin();
- }
-
- // Note we can't use new_bounds.size(), since it includes the titlebar for the
- // purposes of detecting a window move.
- gfx::Size new_size = GetClientAreaSize();
- native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(new_size);
- if (layer()) {
- UpdateLayerProperties();
- if ([window_ inLiveResize])
- MaybeWaitForFrame(new_size);
- }
+ UpdateWindowGeometry();
}
void BridgedNativeWidget::OnPositionChanged() {
- // When a window grows vertically, the AppKit origin changes, but as far as
- // tookit-views is concerned, the window hasn't moved. Suppress these.
- const gfx::Rect new_bounds = native_widget_mac_->GetWindowBoundsInScreen();
- if (new_bounds.origin() == last_window_frame_origin_)
- return;
-
- last_window_frame_origin_ = new_bounds.origin();
- native_widget_mac_->GetWidget()->OnNativeWidgetMove();
+ UpdateWindowGeometry();
}
void BridgedNativeWidget::OnVisibilityChanged() {
@@ -799,26 +794,13 @@ void BridgedNativeWidget::OnVisibilityChanged() {
[parent_->GetNSWindow() removeChildWindow:window_];
}
- // TODO(tapted): Investigate whether we want this for Mac. This is what Aura
- // does, and it is what tests expect. However, because layer drawing is
- // asynchronous (and things like deminiaturize in AppKit are not), it can
- // result in the compositor producing a blank frame during the time that the
- // layer is not visible. Avoid this by locking the compositor (preventing any
- // new frames) in UpdateLayerVisibility whenever the layer is hidden.
- if (layer()) {
- UpdateLayerVisibility();
- 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_;
- }
+ // Showing a translucent window after hiding it should trigger shadow
+ // invalidation.
+ if (window_visible && ![window_ isOpaque])
+ invalidate_shadow_on_frame_swap_ = true;
NotifyVisibilityChangeDown();
-
- native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
- window_visible_);
+ host_->OnVisibilityChanged(window_visible_);
// Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking
// for an "empty" draw, disable auto-display while hidden. For example, this
@@ -832,45 +814,28 @@ void BridgedNativeWidget::OnSystemControlTintChanged() {
}
void BridgedNativeWidget::OnBackingPropertiesChanged() {
- if (layer())
- UpdateLayerProperties();
+ UpdateWindowDisplay();
}
void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) {
- Widget* widget = native_widget_mac()->GetWidget();
- if (!widget->OnNativeWidgetActivationChanged(is_key))
- return;
- // The contentView is the BridgedContentView hosting the views::RootView. The
- // focus manager will already know if a native subview has focus.
- if ([window_ contentView] == [window_ firstResponder]) {
- if (is_key) {
- widget->OnNativeFocus();
- // Explicitly set the keyboard accessibility state on regaining key
- // window status.
- [bridged_view_ updateFullKeyboardAccess];
- widget->GetFocusManager()->RestoreFocusedView();
- } else {
- widget->OnNativeBlur();
- widget->GetFocusManager()->StoreFocusedView(true);
- }
- }
+ host_->OnWindowKeyStatusChanged(
+ is_key, [window_ contentView] == [window_ firstResponder],
+ [NSApp isFullKeyboardAccessEnabled]);
}
-void BridgedNativeWidget::OnSizeConstraintsChanged() {
+void BridgedNativeWidget::SetSizeConstraints(const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ bool is_resizable,
+ bool is_maximizable) {
// Don't modify the size constraints or fullscreen collection behavior while
// in fullscreen or during a transition. OnFullscreenTransitionComplete will
// reset these after leaving fullscreen.
if (target_fullscreen_state_ || in_fullscreen_transition_)
return;
- Widget* widget = native_widget_mac()->GetWidget();
- gfx::Size min_size = widget->GetMinimumSize();
- gfx::Size max_size = widget->GetMaximumSize();
- bool is_resizable = widget->widget_delegate()->CanResize();
bool shows_resize_controls =
is_resizable && (min_size.IsEmpty() || min_size != max_size);
- bool shows_fullscreen_controls =
- is_resizable && widget->widget_delegate()->CanMaximize();
+ bool shows_fullscreen_controls = is_resizable && is_maximizable;
gfx::ApplyNSWindowSizeConstraints(window_, min_size, max_size,
shows_resize_controls,
@@ -881,51 +846,16 @@ void BridgedNativeWidget::OnShowAnimationComplete() {
show_animation_.reset();
}
-ui::InputMethod* BridgedNativeWidget::GetInputMethod() {
- if (!input_method_) {
- input_method_ = ui::CreateInputMethod(this, gfx::kNullAcceleratedWidget);
- // For now, use always-focused mode on Mac for the input method.
- // TODO(tapted): Move this to OnWindowKeyStatusChangedTo() and balance.
- input_method_->OnFocus();
- }
- return input_method_.get();
-}
-
-gfx::Rect BridgedNativeWidget::GetRestoredBounds() const {
- if (target_fullscreen_state_ || in_fullscreen_transition_)
- return bounds_before_fullscreen_;
-
- return gfx::ScreenRectFromNSRect([window_ frame]);
-}
-
-void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type,
- bool translucent) {
- DCHECK(bridged_view_);
- DCHECK(!layer());
-
- CreateCompositor();
- DCHECK(compositor_);
-
- SetLayer(std::make_unique<ui::Layer>(layer_type));
- // Note, except for controls, this will set the layer to be hidden, since it
- // is only called during Init().
- UpdateLayerVisibility();
- layer()->set_delegate(this);
-
- InitCompositor();
-
- // Transparent window support.
- layer()->GetCompositor()->SetBackgroundColor(translucent ? SK_ColorTRANSPARENT
- : SK_ColorWHITE);
- layer()->SetFillsBoundsOpaquely(!translucent);
+void BridgedNativeWidget::InitCompositorView() {
+ AddCompositorSuperview();
- // Use the regular window background for window modal sheets. The layer() will
+ // Use the regular window background for window modal sheets. The layer will
// still paint over most of it, but the native -[NSApp beginSheet:] animation
// blocks the UI thread, so there's no way to invalidate the shadow to match
// the composited layer. This assumes the native window shape is a good match
// for the composited NonClientFrameView, which should be the case since the
// native shape is what's most appropriate for displaying sheets on Mac.
- if (translucent && !native_widget_mac_->IsWindowModalSheet()) {
+ if (is_translucent_window_ && !IsWindowModalSheet()) {
[window_ setOpaque:NO];
[window_ setBackgroundColor:[NSColor clearColor]];
@@ -939,7 +869,10 @@ void BridgedNativeWidget::CreateLayer(ui::LayerType layer_type,
DCHECK(!ca_transaction_sync_suppressed_);
}
- UpdateLayerProperties();
+ // Send the initial window geometry and screen properties. Any future changes
+ // will be forwarded.
+ UpdateWindowDisplay();
+ UpdateWindowGeometry();
}
void BridgedNativeWidget::SetAssociationForView(const views::View* view,
@@ -981,16 +914,12 @@ void BridgedNativeWidget::ReparentNativeView(NSView* native_view,
BridgedNativeWidget* parent_bridge =
NativeWidgetMac::GetBridgeForNativeWindow([new_parent window]);
if (native_view == bridged_view_.get() && parent_bridge != parent_) {
- if (parent_)
- parent_->RemoveChildWindow(this);
-
- if (parent_bridge) {
- parent_ = parent_bridge;
- parent_bridge->child_windows_.push_back(this);
- } else {
- parent_ = new WidgetOwnerNSWindowAdapter(this, new_parent);
- }
+ SetParent(new_parent);
+ // TODO(ccameron): This is likely not correct, as the window for |this|
+ // should only be added as a child window if it is visible.
+ if (!window_visible_)
+ NOTIMPLEMENTED();
[[new_parent window] addChildWindow:window_ ordered:NSWindowAbove];
}
@@ -1022,15 +951,40 @@ bool BridgedNativeWidget::ShouldRunCustomAnimationFor(
constexpr int kSupported =
Widget::ANIMATE_SHOW | Widget::ANIMATE_HIDE | Widget::ANIMATE_NONE;
DCHECK_EQ(0, transitions_to_animate_ & ~kSupported);
+ if (!(transitions_to_animate_ & transition))
+ return false;
+
+ // Custom animations are only used for tab-modals.
+ bool widget_is_modal = false;
+ host_->GetWidgetIsModal(&widget_is_modal);
+ if (!widget_is_modal)
+ return false;
+
+ // Note this also checks the native animation property. Clearing that will
+ // also disable custom animations to ensure that the views::Widget API
+ // behaves consistently.
+ if ([window_ animationBehavior] == NSWindowAnimationBehaviorNone)
+ return false;
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableModalAnimations)) {
+ return false;
+ }
+
+ return true;
+}
+
+NSWindow* BridgedNativeWidget::ns_window() {
+ return window_.get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidget, ui::CATransactionObserver
- // Custom animations are only used for tab-modals. Note this also checks the
- // native animation property. Clearing that will also disable custom
- // animations to ensure that the views::Widget API behaves consistently.
- return (transitions_to_animate_ & transition) &&
- native_widget_mac_->GetWidget()->IsModal() &&
- [window_ animationBehavior] != NSWindowAnimationBehaviorNone &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableModalAnimations);
+void BridgedNativeWidget::OnDisplayMetricsChanged(
+ const display::Display& display,
+ uint32_t metrics) {
+ UpdateWindowDisplay();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1041,9 +995,9 @@ bool BridgedNativeWidget::ShouldWaitInPreCommit() {
return false;
if (ca_transaction_sync_suppressed_)
return false;
- if (!compositor_)
+ if (!compositor_superview_)
return false;
- return !compositor_->widget()->HasFrameOfSize(GetClientAreaSize());
+ return content_dip_size_ != compositor_frame_dip_size_;
}
base::TimeDelta BridgedNativeWidget::PreCommitTimeout() {
@@ -1051,19 +1005,6 @@ base::TimeDelta BridgedNativeWidget::PreCommitTimeout() {
}
////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, internal::InputMethodDelegate:
-
-ui::EventDispatchDetails BridgedNativeWidget::DispatchKeyEventPostIME(
- ui::KeyEvent* key) {
- DCHECK(focus_manager_);
- if (!focus_manager_->OnKeyEvent(*key))
- key->StopPropagation();
- else
- native_widget_mac_->GetWidget()->OnKeyEvent(key);
- return ui::EventDispatchDetails();
-}
-
-////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidget, CocoaMouseCaptureDelegate:
void BridgedNativeWidget::PostCapturedEvent(NSEvent* event) {
@@ -1071,7 +1012,7 @@ void BridgedNativeWidget::PostCapturedEvent(NSEvent* event) {
}
void BridgedNativeWidget::OnMouseCaptureLost() {
- native_widget_mac_->GetWidget()->OnMouseCaptureLost();
+ host_->OnMouseCaptureActiveChanged(false);
}
NSWindow* BridgedNativeWidget::GetWindow() const {
@@ -1079,54 +1020,55 @@ NSWindow* BridgedNativeWidget::GetWindow() const {
}
////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, FocusChangeListener:
-
-void BridgedNativeWidget::OnWillChangeFocus(View* focused_before,
- View* focused_now) {
-}
-
-void BridgedNativeWidget::OnDidChangeFocus(View* focused_before,
- View* focused_now) {
- ui::InputMethod* input_method =
- native_widget_mac_->GetWidget()->GetInputMethod();
- if (input_method) {
- ui::TextInputClient* input_client = input_method->GetTextInputClient();
- // Sanity check: When focus moves away from the widget (i.e. |focused_now|
- // is nil), then the textInputClient will be cleared.
- DCHECK(!!focused_now || !input_client);
- [bridged_view_ setTextInputClient:input_client];
- }
+// TODO(ccameron): Update class names to:
+// BridgedNativeWidgetImpl, BridgedNativeWidget:
+
+void BridgedNativeWidget::SetVisibleOnAllSpaces(bool always_visible) {
+ gfx::SetNSWindowVisibleOnAllWorkspaces(window_, always_visible);
}
-////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, LayerDelegate:
+void BridgedNativeWidget::SetFullscreen(bool fullscreen) {
+ if (fullscreen == target_fullscreen_state_)
+ return;
+ ToggleDesiredFullscreenState();
+}
-void BridgedNativeWidget::OnPaintLayer(const ui::PaintContext& context) {
- native_widget_mac_->GetWidget()->OnNativeWidgetPaint(context);
+void BridgedNativeWidget::SetMiniaturized(bool miniaturized) {
+ if (miniaturized) {
+ // Calling performMiniaturize: will momentarily highlight the button, but
+ // AppKit will reject it if there is no miniaturize button.
+ if ([window_ styleMask] & NSMiniaturizableWindowMask)
+ [window_ performMiniaturize:nil];
+ else
+ [window_ miniaturize:nil];
+ } else {
+ [window_ deminiaturize:nil];
+ }
}
-void BridgedNativeWidget::OnDeviceScaleFactorChanged(
- float old_device_scale_factor,
- float new_device_scale_factor) {
- native_widget_mac_->GetWidget()->DeviceScaleFactorChanged(
- old_device_scale_factor, new_device_scale_factor);
+void BridgedNativeWidget::SetOpacity(float opacity) {
+ [window_ setAlphaValue:opacity];
}
-////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, AcceleratedWidgetMac:
+void BridgedNativeWidget::SetContentAspectRatio(
+ const gfx::SizeF& aspect_ratio) {
+ [window_ setContentAspectRatio:NSMakeSize(aspect_ratio.width(),
+ aspect_ratio.height())];
+}
-void BridgedNativeWidget::AcceleratedWidgetCALayerParamsUpdated() {
+void BridgedNativeWidget::SetCALayerParams(
+ const gfx::CALayerParams& ca_layer_params) {
// Ignore frames arriving "late" for an old size. A frame at the new size
// should arrive soon.
- if (!compositor_->widget()->HasFrameOfSize(GetClientAreaSize()))
+ gfx::Size frame_dip_size = gfx::ConvertSizeToDIP(ca_layer_params.scale_factor,
+ ca_layer_params.pixel_size);
+ if (content_dip_size_ != frame_dip_size)
return;
+ compositor_frame_dip_size_ = frame_dip_size;
// Update the DisplayCALayerTree with the most recent CALayerParams, to make
// the content display on-screen.
- const gfx::CALayerParams* ca_layer_params =
- compositor_->widget()->GetCALayerParams();
- if (ca_layer_params)
- display_ca_layer_tree_->UpdateCALayerTree(*ca_layer_params);
+ display_ca_layer_tree_->UpdateCALayerTree(ca_layer_params);
if (ca_transaction_sync_suppressed_)
ca_transaction_sync_suppressed_ = false;
@@ -1137,6 +1079,27 @@ void BridgedNativeWidget::AcceleratedWidgetCALayerParamsUpdated() {
}
}
+void BridgedNativeWidget::MakeFirstResponder() {
+ [window_ makeFirstResponder:bridged_view_];
+}
+
+void BridgedNativeWidget::SetWindowTitle(const base::string16& title) {
+ NSString* new_title = base::SysUTF16ToNSString(title);
+ [window_ setTitle:new_title];
+}
+
+void BridgedNativeWidget::ClearTouchBar() {
+ if (@available(macOS 10.12.2, *)) {
+ if ([bridged_view_ respondsToSelector:@selector(setTouchBar:)])
+ [bridged_view_ setTouchBar:nil];
+ }
+}
+
+void BridgedNativeWidget::SetTextInputClient(
+ ui::TextInputClient* text_input_client) {
+ [bridged_view_ setTextInputClient:text_input_client];
+}
+
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidget, BridgedNativeWidgetOwner:
@@ -1166,18 +1129,6 @@ void BridgedNativeWidget::RemoveChildWindow(BridgedNativeWidget* child) {
}
////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, DialogObserver:
-
-void BridgedNativeWidget::OnDialogModelChanged() {
- // Note it's only necessary to clear the TouchBar. If the OS needs it again,
- // a new one will be created.
- if (@available(macOS 10.12.2, *)) {
- if ([bridged_view_ respondsToSelector:@selector(setTouchBar:)])
- [bridged_view_ setTouchBar:nil];
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidget, private:
void BridgedNativeWidget::RemoveOrDestroyChildren() {
@@ -1241,59 +1192,6 @@ void BridgedNativeWidget::NotifyVisibilityChangeDown() {
CountBridgedWindows([window_ childWindows]));
}
-gfx::Size BridgedNativeWidget::GetClientAreaSize() const {
- NSRect content_rect = [window_ contentRectForFrameRect:[window_ frame]];
- return gfx::Size(NSWidth(content_rect), NSHeight(content_rect));
-}
-
-void BridgedNativeWidget::CreateCompositor() {
- DCHECK(!compositor_);
- DCHECK(ViewsDelegate::GetInstance());
-
- ui::ContextFactory* context_factory =
- ViewsDelegate::GetInstance()->GetContextFactory();
- DCHECK(context_factory);
- ui::ContextFactoryPrivate* context_factory_private =
- ViewsDelegate::GetInstance()->GetContextFactoryPrivate();
-
- AddCompositorSuperview();
-
- compositor_ = ui::RecyclableCompositorMacFactory::Get()->CreateCompositor(
- context_factory, context_factory_private);
- compositor_->widget()->SetNSView(this);
-}
-
-void BridgedNativeWidget::InitCompositor() {
- TRACE_EVENT0("ui", "BridgedNativeWidget::InitCompositor");
- DCHECK(layer());
- float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_);
- gfx::Size size_in_dip = GetClientAreaSize();
- compositor_->UpdateSurface(ConvertSizeToPixel(scale_factor, size_in_dip),
- scale_factor);
- compositor_->compositor()->SetRootLayer(layer());
- compositor_->Unsuspend();
-}
-
-void BridgedNativeWidget::DestroyCompositor() {
- if (layer()) {
- // LayerOwner supports a change in ownership, e.g., to animate a closing
- // window, but that won't work as expected for the root layer in
- // BridgedNativeWidget.
- DCHECK_EQ(this, layer()->owner());
- layer()->CompleteAllAnimations();
- layer()->SuppressPaint();
- layer()->set_delegate(nullptr);
- }
- DestroyLayer();
-
- if (!compositor_)
- return;
- compositor_->widget()->ResetNSView();
- compositor_->compositor()->SetRootLayer(nullptr);
- ui::RecyclableCompositorMacFactory::Get()->RecycleCompositor(
- std::move(compositor_));
-}
-
void BridgedNativeWidget::AddCompositorSuperview() {
DCHECK(!compositor_superview_);
compositor_superview_.reset(
@@ -1323,46 +1221,31 @@ void BridgedNativeWidget::AddCompositorSuperview() {
[bridged_view_ addSubview:compositor_superview_];
}
-void BridgedNativeWidget::UpdateLayerProperties() {
- DCHECK(layer());
- DCHECK(compositor_superview_);
- float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_);
- gfx::Size size_in_dip = GetClientAreaSize();
- gfx::Size size_in_pixel = ConvertSizeToPixel(scale_factor, size_in_dip);
+void BridgedNativeWidget::UpdateWindowGeometry() {
+ gfx::Rect window_in_screen = gfx::ScreenRectFromNSRect([window_ frame]);
+ gfx::Rect content_in_screen = gfx::ScreenRectFromNSRect(
+ [window_ contentRectForFrameRect:[window_ frame]]);
+ bool content_resized = content_dip_size_ != content_in_screen.size();
+ content_dip_size_ = content_in_screen.size();
- if (!ca_transaction_sync_suppressed_)
- ui::CATransactionCoordinator::Get().Synchronize();
+ host_->OnWindowGeometryChanged(window_in_screen, content_in_screen);
- layer()->SetBounds(gfx::Rect(size_in_dip));
- compositor_->UpdateSurface(size_in_pixel, scale_factor);
+ if (content_resized && !ca_transaction_sync_suppressed_)
+ ui::CATransactionCoordinator::Get().Synchronize();
// For a translucent window, the shadow calculation needs to be carried out
// after the frame from the compositor arrives.
- if (![window_ isOpaque])
+ if (content_resized && ![window_ isOpaque])
invalidate_shadow_on_frame_swap_ = true;
}
-void BridgedNativeWidget::MaybeWaitForFrame(const gfx::Size& size_in_dip) {
- return; // TODO(https://crbug.com/682825): Delete this during cleanup.
- if (!layer()->IsDrawn() || compositor_->widget()->HasFrameOfSize(size_in_dip))
- return;
+void BridgedNativeWidget::UpdateWindowDisplay() {
+ host_->OnWindowDisplayChanged(
+ display::Screen::GetScreen()->GetDisplayNearestWindow(window_));
+}
- const int kPaintMsgTimeoutMS = 50;
- const base::TimeTicks start_time = base::TimeTicks::Now();
- const base::TimeTicks timeout_time =
- start_time + base::TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
-
- ui::WindowResizeHelperMac* resize_helper = ui::WindowResizeHelperMac::Get();
- for (base::TimeTicks now = start_time; now < timeout_time;
- now = base::TimeTicks::Now()) {
- if (!resize_helper->WaitForSingleTaskToRun(timeout_time - now))
- return; // Timeout.
-
- // Since the UI thread is blocked, the size shouldn't change.
- DCHECK(size_in_dip == GetClientAreaSize());
- if (compositor_->widget()->HasFrameOfSize(size_in_dip))
- return; // Frame arrived.
- }
+bool BridgedNativeWidget::IsWindowModalSheet() const {
+ return parent_ && modal_type_ == ui::MODAL_TYPE_WINDOW;
}
void BridgedNativeWidget::ShowAsModalSheet() {
@@ -1370,9 +1253,7 @@ void BridgedNativeWidget::ShowAsModalSheet() {
// So that it doesn't animate a fully transparent window, first wait for a
// frame. The first step is to pretend that the window is already visible.
window_visible_ = true;
- UpdateLayerVisibility();
- native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(true);
- MaybeWaitForFrame(GetClientAreaSize());
+ host_->OnVisibilityChanged(window_visible_);
NSWindow* parent_window = parent_->GetNSWindow();
DCHECK(parent_window);
@@ -1399,12 +1280,4 @@ NSMutableDictionary* BridgedNativeWidget::GetWindowProperties() const {
return properties;
}
-void BridgedNativeWidget::UpdateLayerVisibility() {
- layer()->SetVisible(window_visible_);
- if (window_visible_)
- compositor_->Unsuspend();
- else
- compositor_->Suspend();
-}
-
} // namespace views
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_host.h b/chromium/ui/views/cocoa/bridged_native_widget_host.h
new file mode 100644
index 00000000000..9fa2c68091c
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host.h
@@ -0,0 +1,152 @@
+// Copyright 2018 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_COCOA_BRIDGED_NATIVE_WIDGET_HOST_H_
+#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_HOST_H_
+
+#include "ui/base/ui_base_types.h"
+#include "ui/events/event_utils.h"
+#include "ui/gfx/decorated_text.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/views_export.h"
+
+@class NSView;
+
+namespace views {
+
+// The interface through which the app shim (BridgedNativeWidgetImpl)
+// communicates with the browser process (BridgedNativeWidgetHostImpl).
+class VIEWS_EXPORT BridgedNativeWidgetHost {
+ public:
+ virtual ~BridgedNativeWidgetHost() = default;
+
+ // Retrieve the NSView for accessibility for this widget.
+ // TODO(ccameron): This interface cannot be implemented over IPC. A scheme
+ // for implementing accessibility across processes needs to be designed and
+ // implemented.
+ virtual NSView* GetNativeViewAccessible() = 0;
+
+ // Update the views::Widget, ui::Compositor and ui::Layer's visibility.
+ virtual void OnVisibilityChanged(bool visible) = 0;
+
+ // Resize the underlying views::View to |new_size|. Note that this will not
+ // necessarily match the content bounds from OnWindowGeometryChanged.
+ virtual void SetViewSize(const gfx::Size& new_size) = 0;
+
+ // Indicate if full keyboard accessibility is needed and updates focus if
+ // needed.
+ virtual void SetKeyboardAccessible(bool enabled) = 0;
+
+ // Indicate if the NSView is the first responder.
+ virtual void SetIsFirstResponder(bool is_first_responder) = 0;
+
+ // Indicate if mouse capture is active.
+ virtual void OnMouseCaptureActiveChanged(bool capture_is_active) = 0;
+
+ // Handle events. Note that whether or not the event is actually handled is
+ // not returned.
+ virtual void OnScrollEvent(const ui::ScrollEvent& const_event) = 0;
+ virtual void OnMouseEvent(const ui::MouseEvent& const_event) = 0;
+ virtual void OnGestureEvent(const ui::GestureEvent& const_event) = 0;
+
+ // Synchronously dispatch a key event and return in |event_handled| whether
+ // or not the event was handled.
+ virtual void DispatchKeyEvent(const ui::KeyEvent& const_event,
+ bool* event_handled) = 0;
+
+ // Synchronously dispatch a key event to the current menu controller (if any)
+ // exists. Return in |event_swallowed| whether or not the event was swallowed
+ // (that is, if the menu's dispatch returned POST_DISPATCH_NONE). Return in
+ // in |event_handled| whether or not the event was handled (that is, if the
+ // event in the caller's frame should be marked as handled).
+ virtual void DispatchKeyEventToMenuController(const ui::KeyEvent& const_event,
+ bool* event_swallowed,
+ bool* event_handled) = 0;
+
+ // Synchronously return in |has_menu_controller| whether or not a menu
+ // controller exists for this widget.
+ virtual void GetHasMenuController(bool* has_menu_controller) = 0;
+
+ // Synchronously query if |location_in_content| is a draggable background.
+ virtual void GetIsDraggableBackgroundAt(const gfx::Point& location_in_content,
+ bool* is_draggable_background) = 0;
+
+ // Synchronously query the tooltip text for |location_in_content|.
+ virtual void GetTooltipTextAt(const gfx::Point& location_in_content,
+ base::string16* new_tooltip_text) = 0;
+
+ // Synchronously query the quicklook text at |location_in_content|. Return in
+ // |found_word| whether or not a word was found.
+ virtual void GetWordAt(const gfx::Point& location_in_content,
+ bool* found_word,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) = 0;
+
+ // Synchronously query the value of IsModal for this widget and store it in
+ // |*widget_is_modal|.
+ virtual void GetWidgetIsModal(bool* widget_is_modal) = 0;
+
+ // Synchronously return in |is_textual| whether or not the focused view
+ // contains text that can be selected and copied.
+ virtual void GetIsFocusedViewTextual(bool* is_textual) = 0;
+
+ // Called whenever the NSWindow's size or position changes.
+ virtual void OnWindowGeometryChanged(
+ const gfx::Rect& window_bounds_in_screen_dips,
+ const gfx::Rect& content_bounds_in_screen_dips) = 0;
+
+ // Called when the window begins transitioning to or from being fullscreen.
+ virtual void OnWindowFullscreenTransitionStart(
+ bool target_fullscreen_state) = 0;
+
+ // Called when the window has completed its transition to or from being
+ // fullscreen. Note that if there are multiple consecutive transitions
+ // (because a new transition was initiated before the previous one completed)
+ // then this will only be called when all transitions have competed.
+ virtual void OnWindowFullscreenTransitionComplete(bool is_fullscreen) = 0;
+
+ // Called when the window is miniaturized or deminiaturized.
+ virtual void OnWindowMiniaturizedChanged(bool miniaturized) = 0;
+
+ // Called when the current display or the properties of the current display
+ // change.
+ virtual void OnWindowDisplayChanged(const display::Display& display) = 0;
+
+ // Called before the NSWindow is closed and destroyed.
+ virtual void OnWindowWillClose() = 0;
+
+ // Called after the NSWindow has been closed and destroyed.
+ virtual void OnWindowHasClosed() = 0;
+
+ // Called when the NSWindow becomes key or resigns from being key. Additional
+ // state required for the transition include whether or not the content NSView
+ // is the first responder for the NSWindow in |is_content_first_responder| and
+ // whether or not the NSApp's full keyboard access is enabled in
+ // |full_keyboard_access_enabled|.
+ virtual void OnWindowKeyStatusChanged(bool is_key,
+ bool is_content_first_responder,
+ bool full_keyboard_access_enabled) = 0;
+
+ // Accept or cancel the current dialog window (depending on the value of
+ // |button|), if a current dialog exists.
+ virtual void DoDialogButtonAction(ui::DialogButton button) = 0;
+
+ // Synchronously determine if the specified button exists in the current
+ // dialog (if any), along with its label, whether or not it is enabled, and
+ // whether or not it is the default button..
+ virtual void GetDialogButtonInfo(ui::DialogButton button,
+ bool* button_exists,
+ base::string16* title,
+ bool* is_button_enabled,
+ bool* is_button_default) = 0;
+
+ // Synchronously return in |buttons_exist| whether or not any buttons exist
+ // for the current dialog.
+ virtual void GetDoDialogButtonsExist(bool* buttons_exist) = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_HOST_H_
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
new file mode 100644
index 00000000000..561f3553ca6
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -0,0 +1,230 @@
+// Copyright 2018 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_COCOA_BRIDGED_NATIVE_WIDGET_HOST_IMPL_H_
+#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_HOST_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
+#include "ui/accelerated_widget_mac/display_link_mac.h"
+#include "ui/base/ime/input_method_delegate.h"
+#include "ui/compositor/layer_owner.h"
+#include "ui/views/cocoa/bridged_native_widget_host.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/views_export.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_observer.h"
+
+namespace views_bridge_mac {
+namespace mojom {
+class BridgedNativeWidget;
+} // namespace mojom
+} // namespace views_bridge_mac
+
+namespace ui {
+class RecyclableCompositorMac;
+} // namespace ui
+
+namespace views {
+
+class BridgedNativeWidget;
+class NativeWidgetMac;
+
+// The portion of NativeWidgetMac that lives in the browser process. This
+// communicates to the BridgedNativeWidget, which interacts with the Cocoa
+// APIs, and which may live in an app shim process.
+class VIEWS_EXPORT BridgedNativeWidgetHostImpl
+ : public BridgedNativeWidgetHost,
+ public DialogObserver,
+ public FocusChangeListener,
+ public ui::internal::InputMethodDelegate,
+ public ui::LayerDelegate,
+ public ui::LayerOwner,
+ public ui::AcceleratedWidgetMacNSView {
+ public:
+ // Creates one side of the bridge. |parent| must not be NULL.
+ explicit BridgedNativeWidgetHostImpl(NativeWidgetMac* parent);
+ ~BridgedNativeWidgetHostImpl() override;
+
+ // Provide direct access to the BridgedNativeWidget that this is hosting.
+ // TODO(ccameron): Remove all accesses to this member, and replace them
+ // with methods that may be sent across processes.
+ BridgedNativeWidget* bridge_impl() const { return bridge_impl_.get(); }
+ views_bridge_mac::mojom::BridgedNativeWidget* bridge() const;
+
+ void InitWindow(const Widget::InitParams& params);
+
+ // Changes the bounds of the window and the hosted layer if present. The
+ // origin is a location in screen coordinates except for "child" windows,
+ // which are positioned relative to their parent. SetBounds() considers a
+ // "child" window to be one initialized with InitParams specifying all of:
+ // a |parent| NSWindow, the |child| attribute, and a |type| that
+ // views::GetAuraWindowTypeForWidgetType does not consider a "popup" type.
+ void SetBounds(const gfx::Rect& bounds);
+
+ // Tell the window to transition to being fullscreen or not-fullscreen.
+ void SetFullscreen(bool fullscreen);
+
+ // The ultimate fullscreen state that is being targeted (irrespective of any
+ // active transitions).
+ bool target_fullscreen_state() const { return target_fullscreen_state_; }
+
+ // Set the root view (set during initialization and un-set during teardown).
+ void SetRootView(views::View* root_view);
+
+ // Initialize the ui::Compositor and ui::Layer.
+ void CreateCompositor(const Widget::InitParams& params);
+
+ // Sets or clears the focus manager to use for tracking focused views.
+ // This does NOT take ownership of |focus_manager|.
+ void SetFocusManager(FocusManager* focus_manager);
+
+ // Set the window's title, returning true if the title has changed.
+ bool SetWindowTitle(const base::string16& title);
+
+ // Called when the owning Widget's Init method has completed.
+ void OnWidgetInitDone();
+
+ // See widget.h for documentation.
+ ui::InputMethod* GetInputMethod();
+
+ // Geometry of the window, in DIPs.
+ const gfx::Rect& GetWindowBoundsInScreen() const {
+ DCHECK(has_received_window_geometry_);
+ return window_bounds_in_screen_;
+ }
+
+ // Geometry of the content area of the window, in DIPs. Note that this is not
+ // necessarily the same as the views::View's size.
+ const gfx::Rect& GetContentBoundsInScreen() const {
+ DCHECK(has_received_window_geometry_);
+ return content_bounds_in_screen_;
+ }
+
+ // The display that the window is currently on (or best guess thereof).
+ const display::Display& GetCurrentDisplay() const { return display_; }
+
+ // The restored bounds will be derived from the current NSWindow frame unless
+ // fullscreen or transitioning between fullscreen states.
+ gfx::Rect GetRestoredBounds() const;
+
+ bool IsVisible() const { return is_visible_; }
+ bool IsMiniaturized() const { return is_miniaturized_; }
+ bool IsWindowKey() const { return is_window_key_; }
+ bool IsMouseCaptureActive() const { return is_mouse_capture_active_; }
+
+ private:
+ gfx::Vector2d GetBoundsOffsetForParent() const;
+ void UpdateCompositorProperties();
+ void DestroyCompositor();
+
+ // views::BridgedNativeWidgetHost:
+ NSView* GetNativeViewAccessible() override;
+ void OnVisibilityChanged(bool visible) override;
+ void SetViewSize(const gfx::Size& new_size) override;
+ void SetKeyboardAccessible(bool enabled) override;
+ void SetIsFirstResponder(bool is_first_responder) override;
+ void OnMouseCaptureActiveChanged(bool capture_is_active) override;
+ void OnScrollEvent(const ui::ScrollEvent& const_event) override;
+ void OnMouseEvent(const ui::MouseEvent& const_event) override;
+ void OnGestureEvent(const ui::GestureEvent& const_event) override;
+ void DispatchKeyEvent(const ui::KeyEvent& const_event,
+ bool* event_handled) override;
+ void DispatchKeyEventToMenuController(const ui::KeyEvent& const_event,
+ bool* event_swallowed,
+ bool* event_handled) override;
+ void GetHasMenuController(bool* has_menu_controller) override;
+ void GetIsDraggableBackgroundAt(const gfx::Point& location_in_content,
+ bool* is_draggable_background) override;
+ void GetTooltipTextAt(const gfx::Point& location_in_content,
+ base::string16* new_tooltip_text) override;
+ void GetWordAt(const gfx::Point& location_in_content,
+ bool* found_word,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) override;
+ void GetWidgetIsModal(bool* widget_is_modal) override;
+ void GetIsFocusedViewTextual(bool* is_textual) override;
+ void OnWindowGeometryChanged(
+ const gfx::Rect& window_bounds_in_screen_dips,
+ const gfx::Rect& content_bounds_in_screen_dips) override;
+ void OnWindowFullscreenTransitionStart(bool target_fullscreen_state) override;
+ void OnWindowFullscreenTransitionComplete(
+ bool target_fullscreen_state) override;
+ void OnWindowMiniaturizedChanged(bool miniaturized) override;
+ void OnWindowDisplayChanged(const display::Display& display) override;
+ void OnWindowWillClose() override;
+ void OnWindowHasClosed() override;
+ void OnWindowKeyStatusChanged(bool is_key,
+ bool is_content_first_responder,
+ bool full_keyboard_access_enabled) override;
+ void DoDialogButtonAction(ui::DialogButton button) override;
+ void GetDialogButtonInfo(ui::DialogButton type,
+ bool* button_exists,
+ base::string16* button_label,
+ bool* is_button_enabled,
+ bool* is_button_default) override;
+ void GetDoDialogButtonsExist(bool* buttons_exist) override;
+
+ // DialogObserver:
+ void OnDialogModelChanged() override;
+
+ // FocusChangeListener:
+ void OnWillChangeFocus(View* focused_before, View* focused_now) override;
+ void OnDidChangeFocus(View* focused_before, View* focused_now) override;
+
+ // ui::internal::InputMethodDelegate:
+ ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override;
+
+ // ui::LayerDelegate:
+ void OnPaintLayer(const ui::PaintContext& context) override;
+ void OnDeviceScaleFactorChanged(float old_device_scale_factor,
+ float new_device_scale_factor) override;
+
+ // ui::AcceleratedWidgetMacNSView:
+ void AcceleratedWidgetCALayerParamsUpdated() override;
+
+ views::NativeWidgetMac* const native_widget_mac_; // Weak. Owns |this_|.
+
+ Widget::InitParams::Type widget_type_ = Widget::InitParams::TYPE_WINDOW;
+
+ views::View* root_view_ = nullptr; // Weak. Owned by |native_widget_mac_|.
+
+ // TODO(ccameron): Rather than instantiate a BridgedNativeWidget here,
+ // we will instantiate a mojo BridgedNativeWidget interface to a Cocoa
+ // instance that may be in another process.
+ std::unique_ptr<BridgedNativeWidget> bridge_impl_;
+
+ std::unique_ptr<ui::InputMethod> input_method_;
+ FocusManager* focus_manager_ = nullptr; // Weak. Owned by our Widget.
+
+ base::string16 window_title_;
+
+ // The display that the window is currently on.
+ display::Display display_;
+
+ // Display link for getting vsync info for |display_|.
+ scoped_refptr<ui::DisplayLinkMac> display_link_;
+
+ // The geometry of the window and its contents view, in screen coordinates.
+ bool has_received_window_geometry_ = false;
+ gfx::Rect window_bounds_in_screen_;
+ gfx::Rect content_bounds_in_screen_;
+ bool is_visible_ = false;
+ bool target_fullscreen_state_ = false;
+ bool in_fullscreen_transition_ = false;
+ bool is_miniaturized_ = false;
+ bool is_window_key_ = false;
+ bool is_mouse_capture_active_ = false;
+ gfx::Rect window_bounds_before_fullscreen_;
+
+ std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
+
+ DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetHostImpl);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_HOST_IMPL_H_
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
new file mode 100644
index 00000000000..53e6a582b6c
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -0,0 +1,651 @@
+// Copyright 2018 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/cocoa/bridged_native_widget_host_impl.h"
+
+#include "ui/base/hit_test.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/input_method_factory.h"
+#include "ui/base/models/dialog_model.h"
+#include "ui/compositor/recyclable_compositor_mac.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/views/cocoa/bridged_native_widget.h"
+#include "ui/views/controls/menu/menu_config.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/native_widget_mac.h"
+#include "ui/views/widget/widget_aura_utils.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/dialog_client_view.h"
+#include "ui/views/window/dialog_delegate.h"
+#include "ui/views/word_lookup_client.h"
+
+using views_bridge_mac::mojom::BridgedNativeWidgetInitParams;
+using views_bridge_mac::mojom::WindowVisibilityState;
+
+namespace views {
+
+namespace {
+
+// Returns true if bounds passed to window in SetBounds should be treated as
+// though they are in screen coordinates.
+bool PositionWindowInScreenCoordinates(Widget* widget,
+ Widget::InitParams::Type type) {
+ // Replicate the logic in desktop_aura/desktop_screen_position_client.cc.
+ if (GetAuraWindowTypeForWidgetType(type) == aura::client::WINDOW_TYPE_POPUP)
+ return true;
+
+ return widget && widget->is_top_level();
+}
+
+} // namespace
+
+BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(
+ NativeWidgetMac* parent)
+ : native_widget_mac_(parent),
+ bridge_impl_(new BridgedNativeWidget(this, parent)) {}
+
+BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {
+ // Destroy the bridge first to prevent any calls back into this during
+ // destruction.
+ // TODO(ccameron): When all communication from |bridge_| to this goes through
+ // the BridgedNativeWidgetHost, this can be replaced with closing that pipe.
+ bridge_impl_.reset();
+ SetFocusManager(nullptr);
+ DestroyCompositor();
+}
+
+views_bridge_mac::mojom::BridgedNativeWidget*
+BridgedNativeWidgetHostImpl::bridge() const {
+ return bridge_impl_.get();
+}
+
+void BridgedNativeWidgetHostImpl::InitWindow(const Widget::InitParams& params) {
+ // Tooltip Widgets shouldn't have their own tooltip manager, but tooltips are
+ // native on Mac, so nothing should ever want one in Widget form.
+ DCHECK_NE(params.type, Widget::InitParams::TYPE_TOOLTIP);
+ widget_type_ = params.type;
+
+ bridge_impl_->SetParent(params.parent);
+
+ // Initialize the window.
+ {
+ auto bridge_params = BridgedNativeWidgetInitParams::New();
+ bridge_params->modal_type =
+ native_widget_mac_->GetWidget()->widget_delegate()->GetModalType();
+ bridge_params->is_translucent =
+ params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
+
+ // OSX likes to put shadows on most things. However, frameless windows (with
+ // styleMask = NSBorderlessWindowMask) default to no shadow. So change that.
+ // SHADOW_TYPE_DROP is used for Menus, which get the same shadow style on
+ // Mac.
+ switch (params.shadow_type) {
+ case Widget::InitParams::SHADOW_TYPE_NONE:
+ bridge_params->has_window_server_shadow = false;
+ break;
+ case Widget::InitParams::SHADOW_TYPE_DEFAULT:
+ // Controls should get views shadows instead of native shadows.
+ bridge_params->has_window_server_shadow =
+ params.type != Widget::InitParams::TYPE_CONTROL;
+ break;
+ case Widget::InitParams::SHADOW_TYPE_DROP:
+ bridge_params->has_window_server_shadow = true;
+ break;
+ } // No default case, to pick up new types.
+
+ // Include "regular" windows without the standard frame in the window cycle.
+ // These use NSBorderlessWindowMask so do not get it by default.
+ bridge_params->force_into_collection_cycle =
+ widget_type_ == Widget::InitParams::TYPE_WINDOW &&
+ params.remove_standard_frame;
+
+ bridge()->InitWindow(std::move(bridge_params));
+ }
+
+ // Set a meaningful initial bounds. Note that except for frameless widgets
+ // with no WidgetDelegate, the bounds will be set again by Widget after
+ // initializing the non-client view. In the former case, if bounds were not
+ // set at all, the creator of the Widget is expected to call SetBounds()
+ // before calling Widget::Show() to avoid a kWindowSizeDeterminedLater-sized
+ // (i.e. 1x1) window appearing.
+ bridge()->SetInitialBounds(params.bounds,
+ native_widget_mac_->GetWidget()->GetMinimumSize(),
+ GetBoundsOffsetForParent());
+
+ // Widgets for UI controls (usually layered above web contents) start visible.
+ if (widget_type_ == Widget::InitParams::TYPE_CONTROL)
+ bridge()->SetVisibilityState(WindowVisibilityState::kShowInactive);
+}
+
+void BridgedNativeWidgetHostImpl::SetBounds(const gfx::Rect& bounds) {
+ gfx::Rect adjusted_bounds = bounds;
+ adjusted_bounds.Offset(GetBoundsOffsetForParent());
+ bridge()->SetBounds(adjusted_bounds,
+ native_widget_mac_->GetWidget()->GetMinimumSize());
+}
+
+gfx::Vector2d BridgedNativeWidgetHostImpl::GetBoundsOffsetForParent() const {
+ gfx::Vector2d offset;
+ Widget* widget = native_widget_mac_->GetWidget();
+ BridgedNativeWidgetOwner* parent = bridge_impl_->parent();
+ if (parent && !PositionWindowInScreenCoordinates(widget, widget_type_))
+ offset = parent->GetChildWindowOffset();
+ return offset;
+}
+
+void BridgedNativeWidgetHostImpl::SetFullscreen(bool fullscreen) {
+ // Note that when the NSWindow begins a fullscreen transition, the value of
+ // |target_fullscreen_state_| updates via OnWindowFullscreenTransitionStart.
+ // The update here is necessary for the case where we are currently in
+ // transition (and therefore OnWindowFullscreenTransitionStart will not be
+ // called until the current transition completes).
+ target_fullscreen_state_ = fullscreen;
+ bridge()->SetFullscreen(target_fullscreen_state_);
+}
+
+void BridgedNativeWidgetHostImpl::SetRootView(views::View* root_view) {
+ root_view_ = root_view;
+}
+
+void BridgedNativeWidgetHostImpl::CreateCompositor(
+ const Widget::InitParams& params) {
+ DCHECK(!compositor_);
+ DCHECK(!layer());
+ DCHECK(ViewsDelegate::GetInstance());
+
+ // "Infer" must be handled by ViewsDelegate::OnBeforeWidgetInit().
+ DCHECK_NE(Widget::InitParams::INFER_OPACITY, params.opacity);
+ bool translucent = params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
+
+ // Create the layer.
+ SetLayer(std::make_unique<ui::Layer>(params.layer_type));
+ layer()->set_delegate(this);
+ layer()->SetFillsBoundsOpaquely(!translucent);
+
+ // Create the compositor and attach the layer to it.
+ ui::ContextFactory* context_factory =
+ ViewsDelegate::GetInstance()->GetContextFactory();
+ DCHECK(context_factory);
+ ui::ContextFactoryPrivate* context_factory_private =
+ ViewsDelegate::GetInstance()->GetContextFactoryPrivate();
+ compositor_ = ui::RecyclableCompositorMacFactory::Get()->CreateCompositor(
+ context_factory, context_factory_private);
+ compositor_->widget()->SetNSView(this);
+ compositor_->compositor()->SetBackgroundColor(
+ translucent ? SK_ColorTRANSPARENT : SK_ColorWHITE);
+ compositor_->compositor()->SetRootLayer(layer());
+
+ // The compositor is locked (prevented from producing frames) until the widget
+ // is made visible.
+ UpdateCompositorProperties();
+ layer()->SetVisible(is_visible_);
+ if (is_visible_)
+ compositor_->Unsuspend();
+
+ bridge()->InitCompositorView();
+}
+
+void BridgedNativeWidgetHostImpl::UpdateCompositorProperties() {
+ if (!compositor_)
+ return;
+ gfx::Size surface_size_in_dip = content_bounds_in_screen_.size();
+ layer()->SetBounds(gfx::Rect(surface_size_in_dip));
+ compositor_->UpdateSurface(
+ ConvertSizeToPixel(display_.device_scale_factor(), surface_size_in_dip),
+ display_.device_scale_factor());
+}
+
+void BridgedNativeWidgetHostImpl::DestroyCompositor() {
+ if (layer()) {
+ // LayerOwner supports a change in ownership, e.g., to animate a closing
+ // window, but that won't work as expected for the root layer in
+ // BridgedNativeWidget.
+ DCHECK_EQ(this, layer()->owner());
+ layer()->CompleteAllAnimations();
+ layer()->SuppressPaint();
+ layer()->set_delegate(nullptr);
+ }
+ DestroyLayer();
+ if (!compositor_)
+ return;
+ compositor_->widget()->ResetNSView();
+ compositor_->compositor()->SetRootLayer(nullptr);
+ ui::RecyclableCompositorMacFactory::Get()->RecycleCompositor(
+ std::move(compositor_));
+}
+
+void BridgedNativeWidgetHostImpl::SetFocusManager(FocusManager* focus_manager) {
+ if (focus_manager_ == focus_manager)
+ return;
+
+ if (focus_manager_) {
+ // Only the destructor can replace the focus manager (and it passes null).
+ DCHECK(!focus_manager);
+ if (View* old_focus = focus_manager_->GetFocusedView())
+ OnDidChangeFocus(old_focus, nullptr);
+ focus_manager_->RemoveFocusChangeListener(this);
+ focus_manager_ = nullptr;
+ return;
+ }
+
+ focus_manager_ = focus_manager;
+ focus_manager_->AddFocusChangeListener(this);
+ if (View* new_focus = focus_manager_->GetFocusedView())
+ OnDidChangeFocus(nullptr, new_focus);
+}
+
+bool BridgedNativeWidgetHostImpl::SetWindowTitle(const base::string16& title) {
+ if (window_title_ == title)
+ return false;
+ window_title_ = title;
+ bridge()->SetWindowTitle(window_title_);
+ return true;
+}
+
+void BridgedNativeWidgetHostImpl::OnWidgetInitDone() {
+ Widget* widget = native_widget_mac_->GetWidget();
+ if (DialogDelegate* dialog = widget->widget_delegate()->AsDialogDelegate())
+ dialog->AddObserver(this);
+}
+
+ui::InputMethod* BridgedNativeWidgetHostImpl::GetInputMethod() {
+ if (!input_method_) {
+ input_method_ = ui::CreateInputMethod(this, gfx::kNullAcceleratedWidget);
+ // For now, use always-focused mode on Mac for the input method.
+ // TODO(tapted): Move this to OnWindowKeyStatusChangedTo() and balance.
+ input_method_->OnFocus();
+ }
+ return input_method_.get();
+}
+
+gfx::Rect BridgedNativeWidgetHostImpl::GetRestoredBounds() const {
+ if (target_fullscreen_state_ || in_fullscreen_transition_)
+ return window_bounds_before_fullscreen_;
+ return window_bounds_in_screen_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, views::BridgedNativeWidgetHost:
+
+NSView* BridgedNativeWidgetHostImpl::GetNativeViewAccessible() {
+ return root_view_ ? root_view_->GetNativeViewAccessible() : nil;
+}
+
+void BridgedNativeWidgetHostImpl::OnVisibilityChanged(bool window_visible) {
+ is_visible_ = window_visible;
+ if (compositor_) {
+ layer()->SetVisible(window_visible);
+ if (window_visible) {
+ compositor_->Unsuspend();
+ layer()->SchedulePaint(layer()->bounds());
+ } else {
+ compositor_->Suspend();
+ }
+ }
+ native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(
+ window_visible);
+}
+
+void BridgedNativeWidgetHostImpl::OnScrollEvent(
+ const ui::ScrollEvent& const_event) {
+ ui::ScrollEvent event = const_event;
+ root_view_->GetWidget()->OnScrollEvent(&event);
+}
+
+void BridgedNativeWidgetHostImpl::OnMouseEvent(
+ const ui::MouseEvent& const_event) {
+ ui::MouseEvent event = const_event;
+ root_view_->GetWidget()->OnMouseEvent(&event);
+}
+
+void BridgedNativeWidgetHostImpl::OnGestureEvent(
+ const ui::GestureEvent& const_event) {
+ ui::GestureEvent event = const_event;
+ root_view_->GetWidget()->OnGestureEvent(&event);
+}
+
+void BridgedNativeWidgetHostImpl::DispatchKeyEvent(
+ const ui::KeyEvent& const_event,
+ bool* event_handled) {
+ ui::KeyEvent event = const_event;
+ ignore_result(
+ root_view_->GetWidget()->GetInputMethod()->DispatchKeyEvent(&event));
+ *event_handled = event.handled();
+}
+
+void BridgedNativeWidgetHostImpl::DispatchKeyEventToMenuController(
+ const ui::KeyEvent& const_event,
+ bool* event_swallowed,
+ bool* event_handled) {
+ ui::KeyEvent event = const_event;
+ MenuController* menu_controller = MenuController::GetActiveInstance();
+ if (menu_controller && root_view_ &&
+ menu_controller->owner() == root_view_->GetWidget()) {
+ *event_swallowed = menu_controller->OnWillDispatchKeyEvent(&event) ==
+ ui::POST_DISPATCH_NONE;
+ } else {
+ *event_swallowed = false;
+ }
+ *event_handled = event.handled();
+}
+
+void BridgedNativeWidgetHostImpl::GetHasMenuController(
+ bool* has_menu_controller) {
+ MenuController* menu_controller = MenuController::GetActiveInstance();
+ *has_menu_controller = menu_controller && root_view_ &&
+ menu_controller->owner() == root_view_->GetWidget();
+}
+
+void BridgedNativeWidgetHostImpl::SetViewSize(const gfx::Size& new_size) {
+ root_view_->SetSize(new_size);
+}
+
+void BridgedNativeWidgetHostImpl::SetKeyboardAccessible(bool enabled) {
+ views::FocusManager* focus_manager =
+ root_view_->GetWidget()->GetFocusManager();
+ if (focus_manager)
+ focus_manager->SetKeyboardAccessible(enabled);
+}
+
+void BridgedNativeWidgetHostImpl::SetIsFirstResponder(bool is_first_responder) {
+ if (is_first_responder)
+ root_view_->GetWidget()->GetFocusManager()->RestoreFocusedView();
+ else
+ root_view_->GetWidget()->GetFocusManager()->StoreFocusedView(true);
+}
+
+void BridgedNativeWidgetHostImpl::OnMouseCaptureActiveChanged(bool is_active) {
+ DCHECK_NE(is_mouse_capture_active_, is_active);
+ is_mouse_capture_active_ = is_active;
+ if (!is_mouse_capture_active_)
+ native_widget_mac_->GetWidget()->OnMouseCaptureLost();
+}
+
+void BridgedNativeWidgetHostImpl::GetIsDraggableBackgroundAt(
+ const gfx::Point& location_in_content,
+ bool* is_draggable_background) {
+ int component =
+ root_view_->GetWidget()->GetNonClientComponent(location_in_content);
+ *is_draggable_background = component == HTCAPTION;
+}
+
+void BridgedNativeWidgetHostImpl::GetTooltipTextAt(
+ const gfx::Point& location_in_content,
+ base::string16* new_tooltip_text) {
+ views::View* view =
+ root_view_->GetTooltipHandlerForPoint(location_in_content);
+ if (view) {
+ gfx::Point view_point = location_in_content;
+ views::View::ConvertPointToScreen(root_view_, &view_point);
+ views::View::ConvertPointFromScreen(view, &view_point);
+ if (!view->GetTooltipText(view_point, new_tooltip_text))
+ DCHECK(new_tooltip_text->empty());
+ }
+}
+
+void BridgedNativeWidgetHostImpl::GetWordAt(
+ const gfx::Point& location_in_content,
+ bool* found_word,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) {
+ *found_word = false;
+
+ views::View* target =
+ root_view_->GetEventHandlerForPoint(location_in_content);
+ if (!target)
+ return;
+
+ views::WordLookupClient* word_lookup_client = target->GetWordLookupClient();
+ if (!word_lookup_client)
+ return;
+
+ gfx::Point location_in_target = location_in_content;
+ views::View::ConvertPointToTarget(root_view_, target, &location_in_target);
+ if (!word_lookup_client->GetWordLookupDataAtPoint(
+ location_in_target, decorated_word, baseline_point)) {
+ return;
+ }
+
+ // Convert |baselinePoint| to the coordinate system of |root_view_|.
+ views::View::ConvertPointToTarget(target, root_view_, baseline_point);
+ *found_word = true;
+}
+
+void BridgedNativeWidgetHostImpl::GetWidgetIsModal(bool* widget_is_modal) {
+ *widget_is_modal = native_widget_mac_->GetWidget()->IsModal();
+}
+
+void BridgedNativeWidgetHostImpl::GetIsFocusedViewTextual(bool* is_textual) {
+ views::FocusManager* focus_manager =
+ root_view_ ? root_view_->GetWidget()->GetFocusManager() : nullptr;
+ *is_textual = focus_manager && focus_manager->GetFocusedView() &&
+ focus_manager->GetFocusedView()->GetClassName() ==
+ views::Label::kViewClassName;
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowGeometryChanged(
+ const gfx::Rect& new_window_bounds_in_screen,
+ const gfx::Rect& new_content_bounds_in_screen) {
+ has_received_window_geometry_ = true;
+
+ bool window_has_moved =
+ new_window_bounds_in_screen.origin() != window_bounds_in_screen_.origin();
+ bool content_has_resized =
+ new_content_bounds_in_screen.size() != content_bounds_in_screen_.size();
+
+ window_bounds_in_screen_ = new_window_bounds_in_screen;
+ content_bounds_in_screen_ = new_content_bounds_in_screen;
+
+ // When a window grows vertically, the AppKit origin changes, but as far as
+ // tookit-views is concerned, the window hasn't moved. Suppress these.
+ if (window_has_moved)
+ native_widget_mac_->GetWidget()->OnNativeWidgetMove();
+
+ // Note we can't use new_window_bounds_in_screen.size(), since it includes the
+ // titlebar for the purposes of detecting a window move.
+ if (content_has_resized)
+ native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(
+ content_bounds_in_screen_.size());
+
+ // Update the compositor surface and layer size.
+ UpdateCompositorProperties();
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowFullscreenTransitionStart(
+ bool target_fullscreen_state) {
+ target_fullscreen_state_ = target_fullscreen_state;
+ in_fullscreen_transition_ = true;
+
+ // If going into fullscreen, store an answer for GetRestoredBounds().
+ if (target_fullscreen_state)
+ window_bounds_before_fullscreen_ = window_bounds_in_screen_;
+
+ // Notify that fullscreen state changed.
+ native_widget_mac_->OnWindowFullscreenStateChange();
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowFullscreenTransitionComplete(
+ bool actual_fullscreen_state) {
+ in_fullscreen_transition_ = false;
+
+ // Ensure constraints are re-applied when completing a transition.
+ native_widget_mac_->OnSizeConstraintsChanged();
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowMiniaturizedChanged(
+ bool miniaturized) {
+ is_miniaturized_ = miniaturized;
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowDisplayChanged(
+ const display::Display& new_display) {
+ bool scale_factor_changed =
+ display_.device_scale_factor() != new_display.device_scale_factor();
+ bool display_id_changed = display_.id() != new_display.id();
+ display_ = new_display;
+ if (scale_factor_changed && compositor_ && has_received_window_geometry_) {
+ compositor_->UpdateSurface(
+ ConvertSizeToPixel(display_.device_scale_factor(),
+ content_bounds_in_screen_.size()),
+ display_.device_scale_factor());
+ }
+ if (display_id_changed) {
+ display_link_ = ui::DisplayLinkMac::GetForDisplay(display_.id());
+ if (!display_link_) {
+ // Note that on some headless systems, the display link will fail to be
+ // created, so this should not be a fatal error.
+ LOG(ERROR) << "Failed to create display link.";
+ }
+ }
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowWillClose() {
+ Widget* widget = native_widget_mac_->GetWidget();
+ if (DialogDelegate* dialog = widget->widget_delegate()->AsDialogDelegate())
+ dialog->RemoveObserver(this);
+ native_widget_mac_->WindowDestroying();
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowHasClosed() {
+ native_widget_mac_->WindowDestroyed();
+}
+
+void BridgedNativeWidgetHostImpl::OnWindowKeyStatusChanged(
+ bool is_key,
+ bool is_content_first_responder,
+ bool full_keyboard_access_enabled) {
+ is_window_key_ = is_key;
+ Widget* widget = native_widget_mac_->GetWidget();
+ if (!widget->OnNativeWidgetActivationChanged(is_key))
+ return;
+ // The contentView is the BridgedContentView hosting the views::RootView. The
+ // focus manager will already know if a native subview has focus.
+ if (is_content_first_responder) {
+ if (is_key) {
+ widget->OnNativeFocus();
+ // Explicitly set the keyboard accessibility state on regaining key
+ // window status.
+ SetKeyboardAccessible(full_keyboard_access_enabled);
+ widget->GetFocusManager()->RestoreFocusedView();
+ } else {
+ widget->OnNativeBlur();
+ widget->GetFocusManager()->StoreFocusedView(true);
+ }
+ }
+}
+
+void BridgedNativeWidgetHostImpl::DoDialogButtonAction(
+ ui::DialogButton button) {
+ views::DialogDelegate* dialog =
+ root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
+ DCHECK(dialog);
+ views::DialogClientView* client = dialog->GetDialogClientView();
+ if (button == ui::DIALOG_BUTTON_OK) {
+ client->AcceptWindow();
+ } else {
+ DCHECK_EQ(button, ui::DIALOG_BUTTON_CANCEL);
+ client->CancelWindow();
+ }
+}
+
+void BridgedNativeWidgetHostImpl::GetDialogButtonInfo(
+ ui::DialogButton button,
+ bool* button_exists,
+ base::string16* button_label,
+ bool* is_button_enabled,
+ bool* is_button_default) {
+ *button_exists = false;
+ ui::DialogModel* model =
+ root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
+ if (!model || !(model->GetDialogButtons() & button))
+ return;
+ *button_exists = true;
+ *button_label = model->GetDialogButtonLabel(button);
+ *is_button_enabled = model->IsDialogButtonEnabled(button);
+ *is_button_default = button == model->GetDefaultDialogButton();
+}
+
+void BridgedNativeWidgetHostImpl::GetDoDialogButtonsExist(bool* buttons_exist) {
+ ui::DialogModel* model =
+ root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
+ *buttons_exist = model && model->GetDialogButtons();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, DialogObserver:
+
+void BridgedNativeWidgetHostImpl::OnDialogModelChanged() {
+ // Note it's only necessary to clear the TouchBar. If the OS needs it again,
+ // a new one will be created.
+ bridge()->ClearTouchBar();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, FocusChangeListener:
+
+void BridgedNativeWidgetHostImpl::OnWillChangeFocus(View* focused_before,
+ View* focused_now) {}
+
+void BridgedNativeWidgetHostImpl::OnDidChangeFocus(View* focused_before,
+ View* focused_now) {
+ ui::InputMethod* input_method =
+ native_widget_mac_->GetWidget()->GetInputMethod();
+ if (input_method) {
+ ui::TextInputClient* input_client = input_method->GetTextInputClient();
+ // Sanity check: When focus moves away from the widget (i.e. |focused_now|
+ // is nil), then the textInputClient will be cleared.
+ DCHECK(!!focused_now || !input_client);
+ bridge_impl_->SetTextInputClient(input_client);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidget, internal::InputMethodDelegate:
+
+ui::EventDispatchDetails BridgedNativeWidgetHostImpl::DispatchKeyEventPostIME(
+ ui::KeyEvent* key) {
+ DCHECK(focus_manager_);
+ if (!focus_manager_->OnKeyEvent(*key))
+ key->StopPropagation();
+ else
+ native_widget_mac_->GetWidget()->OnKeyEvent(key);
+ return ui::EventDispatchDetails();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, LayerDelegate:
+
+void BridgedNativeWidgetHostImpl::OnPaintLayer(
+ const ui::PaintContext& context) {
+ native_widget_mac_->GetWidget()->OnNativeWidgetPaint(context);
+}
+
+void BridgedNativeWidgetHostImpl::OnDeviceScaleFactorChanged(
+ float old_device_scale_factor,
+ float new_device_scale_factor) {
+ native_widget_mac_->GetWidget()->DeviceScaleFactorChanged(
+ old_device_scale_factor, new_device_scale_factor);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, AcceleratedWidgetMac:
+
+void BridgedNativeWidgetHostImpl::AcceleratedWidgetCALayerParamsUpdated() {
+ const gfx::CALayerParams* ca_layer_params =
+ compositor_->widget()->GetCALayerParams();
+ if (ca_layer_params)
+ bridge()->SetCALayerParams(*ca_layer_params);
+
+ // Take this opportunity to update the VSync parameters, if needed.
+ if (display_link_) {
+ base::TimeTicks timebase;
+ base::TimeDelta interval;
+ if (display_link_->GetVSyncParameters(&timebase, &interval))
+ compositor_->compositor()->SetDisplayVSyncParameters(timebase, interval);
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
index f02e1b94c08..53c32814537 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -15,6 +15,7 @@
#include "ui/base/test/ui_controls.h"
#import "ui/base/test/windowed_nsnotification_observer.h"
#import "ui/events/test/cocoa_test_event_utils.h"
+#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/test/views_interactive_ui_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/native_widget_mac.h"
@@ -256,7 +257,7 @@ class HitTestNativeWidgetMac : public NativeWidgetMac {
HitTestNativeWidgetMac(internal::NativeWidgetDelegate* delegate,
NativeFrameView* native_frame_view)
: NativeWidgetMac(delegate), native_frame_view_(native_frame_view) {
- NativeWidgetMac::bridge_.reset(new BridgedNativeWidget(this));
+ bridge_host_ = std::make_unique<BridgedNativeWidgetHostImpl>(this);
}
// internal::NativeWidgetPrivate:
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
index f25287d5bb5..8f3abc65650 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -26,6 +26,7 @@
#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/views/cocoa/bridged_content_view.h"
+#import "ui/views/cocoa/bridged_native_widget_host_impl.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"
@@ -211,12 +212,15 @@ NSTextInputContext* g_fake_current_input_context = nullptr;
} // namespace
-// Class to hook [NSView interpretKeyEvents:] to simulate it interacting with an
-// IME window.
-@interface InterpretKeyEventsDonorForNSView : NSView
+// Subclass of BridgedContentView with an override of interpretKeyEvents:. Note
+// the size of the class must match BridgedContentView since the method table
+// is swapped out at runtime. This is basically a mock, but mocks are banned
+// under ui/views. Method swizzling causes these tests to flake when
+// parallelized in the same process.
+@interface InterpretKeyEventMockedBridgedContentView : BridgedContentView
@end
-@implementation InterpretKeyEventsDonorForNSView
+@implementation InterpretKeyEventMockedBridgedContentView
- (void)interpretKeyEvents:(NSArray<NSEvent*>*)eventArray {
ASSERT_TRUE(g_fake_interpret_key_events);
@@ -251,15 +255,18 @@ NSTextInputContext* g_fake_current_input_context = nullptr;
// NSWindow's behavior when attempting to toggle fullscreen state again, when
// the last attempt failed but Cocoa has not yet sent
// windowDidFailToEnterFullScreen:.
-@interface BridgedNativeWidgetTestFullScreenWindow : NativeWidgetMacNSWindow {
+@interface BridgedNativeWidgetTestWindow : NativeWidgetMacNSWindow {
@private
+ BOOL ignoreToggleFullScreen_;
int ignoredToggleFullScreenCount_;
}
+@property(assign, nonatomic) BOOL ignoreToggleFullScreen;
@property(readonly, nonatomic) int ignoredToggleFullScreenCount;
@end
-@implementation BridgedNativeWidgetTestFullScreenWindow
+@implementation BridgedNativeWidgetTestWindow
+@synthesize ignoreToggleFullScreen = ignoreToggleFullScreen_;
@synthesize ignoredToggleFullScreenCount = ignoredToggleFullScreenCount_;
- (void)performSelector:(SEL)aSelector
@@ -268,14 +275,17 @@ NSTextInputContext* g_fake_current_input_context = nullptr;
// This is used in simulations without a message loop. Don't start a message
// loop since that would expose the tests to system notifications and
// potential flakes. Instead, just pretend the message loop is flushed here.
- if (aSelector == @selector(toggleFullScreen:))
+ if (ignoreToggleFullScreen_ && aSelector == @selector(toggleFullScreen:))
[self toggleFullScreen:anArgument];
else
[super performSelector:aSelector withObject:anArgument afterDelay:delay];
}
- (void)toggleFullScreen:(id)sender {
- ++ignoredToggleFullScreenCount_;
+ if (ignoreToggleFullScreen_)
+ ++ignoredToggleFullScreenCount_;
+ else
+ [super toggleFullScreen:sender];
}
@end
@@ -288,20 +298,28 @@ class MockNativeWidgetMac : public NativeWidgetMac {
public:
explicit MockNativeWidgetMac(internal::NativeWidgetDelegate* delegate)
: NativeWidgetMac(delegate) {}
-
- // Expose a reference, so that it can be reset() independently.
- std::unique_ptr<BridgedNativeWidget>& bridge() { return bridge_; }
+ using NativeWidgetMac::bridge;
+ using NativeWidgetMac::bridge_host_for_testing;
// internal::NativeWidgetPrivate:
void InitNativeWidget(const Widget::InitParams& params) override {
ownership_ = params.ownership;
+ base::scoped_nsobject<NativeWidgetMacNSWindow> window(
+ [[BridgedNativeWidgetTestWindow alloc]
+ initWithContentRect:ui::kWindowSizeDeterminedLater
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ bridge()->SetWindow(window);
+ bridge_host_for_testing()->InitWindow(params);
+
// Usually the bridge gets initialized here. It is skipped to run extra
// checks in tests, and so that a second window isn't created.
delegate()->OnNativeWidgetCreated(true);
// To allow events to dispatch to a view, it needs a way to get focus.
- bridge_->SetFocusManager(GetWidget()->GetFocusManager());
+ bridge_host_for_testing()->SetFocusManager(GetWidget()->GetFocusManager());
}
void ReorderNativeViews() override {
@@ -324,8 +342,9 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
explicit BridgedNativeWidgetTestBase(SkipInitialization tag)
: native_widget_mac_(nullptr) {}
- std::unique_ptr<BridgedNativeWidget>& bridge() {
- return native_widget_mac_->bridge();
+ BridgedNativeWidget* bridge() { return native_widget_mac_->bridge(); }
+ BridgedNativeWidgetHostImpl* bridge_host() {
+ return native_widget_mac_->bridge_host_for_testing();
}
// Overridden from testing::Test:
@@ -357,10 +376,18 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
}
void TearDown() override {
+ // ui::CocoaTest::TearDown will wait until all NSWindows are destroyed, so
+ // be sure to destroy the widget (which will destroy its NSWindow)
+ // beforehand.
+ widget_.reset();
ui::test::MaterialDesignControllerTestAPI::Uninitialize();
ui::CocoaTest::TearDown();
}
+ NSWindow* bridge_window() const {
+ return native_widget_mac_->bridge()->ns_window();
+ }
+
protected:
std::unique_ptr<Widget> widget_;
MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|.
@@ -464,6 +491,23 @@ class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase,
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest);
};
+// Class that counts occurrences of a VKEY_RETURN accelerator, marking them
+// processed.
+class EnterAcceleratorView : public View {
+ public:
+ EnterAcceleratorView() { AddAccelerator({ui::VKEY_RETURN, 0}); }
+ int count() const { return count_; }
+
+ // View:
+ bool AcceleratorPressed(const ui::Accelerator& accelerator) override {
+ ++count_;
+ return true;
+ }
+
+ private:
+ int count_ = 0;
+};
+
BridgedNativeWidgetTest::BridgedNativeWidgetTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
@@ -565,30 +609,27 @@ void BridgedNativeWidgetTest::SetUp() {
BridgedNativeWidgetTestBase::SetUp();
view_.reset(new views::internal::RootView(widget_.get()));
- base::scoped_nsobject<NSWindow> window([test_window() retain]);
-
- // BridgedNativeWidget expects to be initialized with a hidden (deferred)
- // window.
- [window orderOut:nil];
- EXPECT_FALSE([window delegate]);
- bridge()->Init(window, init_params_);
+ base::scoped_nsobject<NSWindow> window([bridge_window() retain]);
// The delegate should exist before setting the root view.
EXPECT_TRUE([window delegate]);
- bridge()->SetRootView(view_.get());
+ bridge_host()->SetRootView(view_.get());
+ bridge()->CreateContentView(view_->bounds());
ns_view_ = bridge()->ns_view();
// Pretend it has been shown via NativeWidgetMac::Show().
[window orderFront:nil];
- [test_window() makePretendKeyWindowAndSetFirstResponder:bridge()->ns_view()];
+ [window makeFirstResponder:bridge()->ns_view()];
}
void BridgedNativeWidgetTest::TearDown() {
// Clear kill buffer so that no state persists between tests.
TextfieldModel::ClearKillBuffer();
- if (bridge())
- bridge()->SetRootView(nullptr);
+ if (bridge_host()) {
+ bridge_host()->SetRootView(nullptr);
+ bridge()->DestroyContentView();
+ }
view_.reset();
BridgedNativeWidgetTestBase::TearDown();
}
@@ -740,12 +781,13 @@ void BridgedNativeWidgetTest::TestEditingCommands(NSArray* selectors) {
// what TEST_VIEW usually does.
TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewAddRemove) {
base::scoped_nsobject<BridgedContentView> view([bridge()->ns_view() retain]);
- EXPECT_NSEQ([test_window() contentView], view);
- EXPECT_NSEQ(test_window(), [view window]);
+ base::scoped_nsobject<NSWindow> window([bridge_window() retain]);
+ EXPECT_NSEQ([window contentView], view);
+ EXPECT_NSEQ(window, [view window]);
// The superview of a contentView is an NSNextStepFrame.
EXPECT_TRUE([view superview]);
- EXPECT_TRUE([view hostedView]);
+ EXPECT_TRUE([view bridge]);
// Ensure the tracking area to propagate mouseMoved: events to the RootView is
// installed.
@@ -753,13 +795,13 @@ TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewAddRemove) {
// Closing the window should tear down the C++ bridge, remove references to
// any C++ objects in the ObjectiveC object, and remove it from the hierarchy.
- [test_window() close];
- EXPECT_FALSE([view hostedView]);
+ [window close];
+ EXPECT_FALSE([view bridge]);
EXPECT_FALSE([view superview]);
EXPECT_FALSE([view window]);
EXPECT_EQ(0u, [[view trackingAreas] count]);
- EXPECT_FALSE([test_window() contentView]);
- EXPECT_FALSE([test_window() delegate]);
+ EXPECT_FALSE([window contentView]);
+ EXPECT_FALSE([window delegate]);
}
TEST_F(BridgedNativeWidgetTest, BridgedNativeWidgetTest_TestViewDisplay) {
@@ -771,8 +813,8 @@ TEST_F(BridgedNativeWidgetTest, ViewSizeTracksWindow) {
const int kTestNewWidth = 400;
const int kTestNewHeight = 300;
- // |test_window()| is borderless, so these should align.
- NSSize window_size = [test_window() frame].size;
+ // |bridge_window()| is borderless, so these should align.
+ NSSize window_size = [bridge_window() frame].size;
EXPECT_EQ(view_->width(), static_cast<int>(window_size.width));
EXPECT_EQ(view_->height(), static_cast<int>(window_size.height));
@@ -780,14 +822,14 @@ TEST_F(BridgedNativeWidgetTest, ViewSizeTracksWindow) {
EXPECT_NE(kTestNewWidth, view_->width());
EXPECT_NE(kTestNewHeight, view_->height());
- [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
- display:NO];
+ [bridge_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
+ display:NO];
EXPECT_EQ(kTestNewWidth, view_->width());
EXPECT_EQ(kTestNewHeight, view_->height());
}
TEST_F(BridgedNativeWidgetTest, GetInputMethodShouldNotReturnNull) {
- EXPECT_TRUE(bridge()->GetInputMethod());
+ EXPECT_TRUE(bridge_host()->GetInputMethod());
}
// A simpler test harness for testing initialization flows.
@@ -797,13 +839,7 @@ class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase {
: BridgedNativeWidgetTestBase(SkipInitialization()) {}
// Prepares a new |window_| and |widget_| for a call to PerformInit().
- void CreateNewWidgetToInit(NSUInteger style_mask) {
- window_.reset(
- [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:style_mask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
+ void CreateNewWidgetToInit() {
widget_.reset(new Widget);
native_widget_mac_ = new MockNativeWidgetMac(widget_.get());
init_params_.native_widget = native_widget_mac_;
@@ -811,12 +847,8 @@ class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase {
void PerformInit() {
widget_->Init(init_params_);
- bridge()->Init(window_, init_params_);
}
- protected:
- base::scoped_nsobject<NSWindow> window_;
-
private:
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetInitTest);
};
@@ -841,34 +873,32 @@ TEST_F(BridgedNativeWidgetInitTest, ShadowType) {
EXPECT_EQ(Widget::InitParams::OPAQUE_WINDOW, init_params_.opacity);
EXPECT_EQ(Widget::InitParams::SHADOW_TYPE_DEFAULT, init_params_.shadow_type);
- CreateNewWidgetToInit(NSBorderlessWindowMask);
- EXPECT_FALSE([window_ hasShadow]); // Default for NSBorderlessWindowMask.
+ CreateNewWidgetToInit();
+ EXPECT_FALSE(
+ [bridge_window() hasShadow]); // Default for NSBorderlessWindowMask.
PerformInit();
// Borderless is 0, so isn't really a mask. Check that nothing is set.
- EXPECT_EQ(NSBorderlessWindowMask, [window_ styleMask]);
- EXPECT_TRUE([window_ hasShadow]); // SHADOW_TYPE_DEFAULT means a shadow.
+ EXPECT_EQ(NSBorderlessWindowMask, [bridge_window() styleMask]);
+ EXPECT_TRUE(
+ [bridge_window() hasShadow]); // SHADOW_TYPE_DEFAULT means a shadow.
- CreateNewWidgetToInit(NSBorderlessWindowMask);
+ CreateNewWidgetToInit();
init_params_.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE;
PerformInit();
- EXPECT_FALSE([window_ hasShadow]); // Preserves lack of shadow.
+ EXPECT_FALSE([bridge_window() hasShadow]); // Preserves lack of shadow.
// Default for Widget::InitParams::TYPE_WINDOW.
- NSUInteger kBorderedMask =
- NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
- NSResizableWindowMask | NSTexturedBackgroundWindowMask;
- CreateNewWidgetToInit(kBorderedMask);
- EXPECT_TRUE([window_ hasShadow]); // Default for non-borderless.
+ CreateNewWidgetToInit();
PerformInit();
- EXPECT_FALSE([window_ hasShadow]); // SHADOW_TYPE_NONE removes shadow.
+ EXPECT_FALSE(
+ [bridge_window() hasShadow]); // SHADOW_TYPE_NONE removes shadow.
init_params_.shadow_type = Widget::InitParams::SHADOW_TYPE_DEFAULT;
- CreateNewWidgetToInit(kBorderedMask);
+ CreateNewWidgetToInit();
PerformInit();
- EXPECT_TRUE([window_ hasShadow]); // Preserves shadow.
+ EXPECT_TRUE([bridge_window() hasShadow]); // Preserves shadow.
- window_.reset();
widget_.reset();
}
@@ -1072,6 +1102,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
widget_->GetNativeWindow(), true, ui::VKEY_A, 0));
[ns_view_ insertText:@"a" replacementRange:EmptyRange()];
[dummy_text_view_ insertText:@"a" replacementRange:EmptyRange()];
+ SetKeyDownEvent(nil);
EXPECT_EQ_3(NO, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]);
EXPECT_NSEQ_3(@"abca", GetExpectedText(), GetActualText());
@@ -1086,6 +1117,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
[dummy_text_view_ setMarkedText:@"à"
selectedRange:NSMakeRange(0, 1)
replacementRange:NSMakeRange(3, 1)];
+ SetKeyDownEvent(nil);
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]);
@@ -1098,6 +1130,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0));
[ns_view_ insertText:@"à" replacementRange:EmptyRange()];
[dummy_text_view_ insertText:@"à" replacementRange:EmptyRange()];
+ SetKeyDownEvent(nil);
EXPECT_EQ_3(NO, [dummy_text_view_ hasMarkedText], [ns_view_ hasMarkedText]);
EXPECT_EQ_RANGE_3(NSMakeRange(4, 0), GetExpectedSelectionRange(),
GetActualSelectionRange());
@@ -1397,9 +1430,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_SimulatePhoneticIme) {
Textfield* textfield = InstallTextField("");
EXPECT_TRUE([ns_view_ textInputClient]);
- base::mac::ScopedObjCClassSwizzler interpret_key_events_swizzler(
- [NSView class], [InterpretKeyEventsDonorForNSView class],
- @selector(interpretKeyEvents:));
+ object_setClass(ns_view_, [InterpretKeyEventMockedBridgedContentView class]);
// Sequence of calls (and corresponding keyDown events) obtained via tracing
// with 2-Set Korean IME and pressing q, o, then Enter on the keyboard.
@@ -1465,6 +1496,136 @@ TEST_F(BridgedNativeWidgetTest, TextInput_SimulatePhoneticIme) {
g_fake_interpret_key_events = nullptr;
}
+// Simulate 'a', Enter in Hiragana. This should just insert "あ", suppressing
+// accelerators.
+TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorEnterComposition) {
+ Textfield* textfield = InstallTextField("");
+ EXPECT_TRUE([ns_view_ textInputClient]);
+
+ EnterAcceleratorView* enter_view = new EnterAcceleratorView();
+ textfield->parent()->AddChildView(enter_view);
+
+ // Sequence of calls (and corresponding keyDown events) obtained via tracing
+ // with Hiragana IME and pressing 'a', then Enter on the keyboard.
+ NSEvent* a_in_ime = cocoa_test_event_utils::KeyEventWithKeyCode(
+ 0, [@"a" characterAtIndex:0], NSKeyDown, 0);
+ InterpretKeyEventsCallback handle_a_in_ime = base::BindRepeating([](id view) {
+ // TODO(crbug/612675): |text| should be an NSAttributedString.
+ [view setMarkedText:@"あ"
+ selectedRange:NSMakeRange(1, 0)
+ replacementRange:NSMakeRange(NSNotFound, 0)];
+ });
+
+ NSEvent* return_event = cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0);
+ InterpretKeyEventsCallback handle_return_in_ime =
+ base::BindRepeating([](id view) {
+ [view insertText:@"あ" replacementRange:NSMakeRange(NSNotFound, 0)];
+ });
+
+ EXPECT_EQ(base::UTF8ToUTF16(""), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ object_setClass(ns_view_, [InterpretKeyEventMockedBridgedContentView class]);
+ g_fake_interpret_key_events = &handle_a_in_ime;
+ [ns_view_ keyDown:a_in_ime];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"あ"), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ g_fake_interpret_key_events = &handle_return_in_ime;
+ [ns_view_ keyDown:return_event];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"あ"), textfield->text());
+ EXPECT_EQ(0, enter_view->count()); // Not seen as an accelerator.
+
+ // IME Window is dismissed here and there is no marked text, so remove the
+ // swizzler.
+ object_setClass(ns_view_, [BridgedContentView class]);
+
+ [ns_view_ keyDown:return_event]; // Sanity check: send Enter again.
+ EXPECT_EQ(base::SysNSStringToUTF16(@"あ"), textfield->text()); // No change.
+ EXPECT_EQ(1, enter_view->count()); // Now we see the accelerator.
+}
+
+// Simulate 'a', Tab, Enter, Enter in Hiragana. This should just insert "a",
+// suppressing accelerators.
+TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorTabEnterComposition) {
+ Textfield* textfield = InstallTextField("");
+ EXPECT_TRUE([ns_view_ textInputClient]);
+
+ EnterAcceleratorView* enter_view = new EnterAcceleratorView();
+ textfield->parent()->AddChildView(enter_view);
+
+ // Sequence of calls (and corresponding keyDown events) obtained via tracing
+ // with Hiragana IME and pressing 'a', Tab, then Enter on the keyboard.
+ NSEvent* a_in_ime = cocoa_test_event_utils::KeyEventWithKeyCode(
+ 0, [@"a" characterAtIndex:0], NSKeyDown, 0);
+ InterpretKeyEventsCallback handle_a_in_ime = base::BindRepeating([](id view) {
+ // TODO(crbug/612675): |text| should have an underline.
+ [view setMarkedText:@"あ"
+ selectedRange:NSMakeRange(1, 0)
+ replacementRange:NSMakeRange(NSNotFound, 0)];
+ });
+
+ NSEvent* tab_in_ime = cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true, ui::VKEY_TAB, 0);
+ InterpretKeyEventsCallback handle_tab_in_ime =
+ base::BindRepeating([](id view) {
+ // TODO(crbug/612675): |text| should be an NSAttributedString (now with
+ // a different underline color).
+ [view setMarkedText:@"a"
+ selectedRange:NSMakeRange(0, 1)
+ replacementRange:NSMakeRange(NSNotFound, 0)];
+ });
+
+ NSEvent* return_event = cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0);
+ InterpretKeyEventsCallback handle_first_return_in_ime =
+ base::BindRepeating([](id view) {
+ // Do *nothing*. Enter does not confirm nor change the composition, it
+ // just dismisses the IME window, leaving the text marked.
+ });
+ InterpretKeyEventsCallback handle_second_return_in_ime =
+ base::BindRepeating([](id view) {
+ // The second return will confirm the composition.
+ [view insertText:@"a" replacementRange:NSMakeRange(NSNotFound, 0)];
+ });
+
+ EXPECT_EQ(base::UTF8ToUTF16(""), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ object_setClass(ns_view_, [InterpretKeyEventMockedBridgedContentView class]);
+ g_fake_interpret_key_events = &handle_a_in_ime;
+ [ns_view_ keyDown:a_in_ime];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"あ"), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ g_fake_interpret_key_events = &handle_tab_in_ime;
+ [ns_view_ keyDown:tab_in_ime];
+ // Tab will switch to a Romanji (Latin) character.
+ EXPECT_EQ(base::SysNSStringToUTF16(@"a"), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ g_fake_interpret_key_events = &handle_first_return_in_ime;
+ [ns_view_ keyDown:return_event];
+ // Enter just dismisses the IME window. The composition is still active.
+ EXPECT_EQ(base::SysNSStringToUTF16(@"a"), textfield->text());
+ EXPECT_EQ(0, enter_view->count()); // Not seen as an accelerator.
+
+ g_fake_interpret_key_events = &handle_second_return_in_ime;
+ [ns_view_ keyDown:return_event];
+ // Enter now confirms the composition (unmarks text). Note there is still no
+ // IME window visible but, since there is marked text, IME is still active.
+ EXPECT_EQ(base::SysNSStringToUTF16(@"a"), textfield->text());
+ EXPECT_EQ(0, enter_view->count()); // Not seen as an accelerator.
+
+ // No marked text, no IME window. We could remove the swizzler here, but
+ // that is equivalent to the "do nothing" case, so set than handler again.
+ g_fake_interpret_key_events = &handle_first_return_in_ime;
+ [ns_view_ keyDown:return_event]; // Send Enter a _third_ time.
+ EXPECT_EQ(base::SysNSStringToUTF16(@"a"), textfield->text()); // No change.
+ EXPECT_EQ(1, enter_view->count()); // Now we see the accelerator.
+}
+
// Test a codepath that could hypothetically cause [NSApp updateWindows] to be
// called recursively due to IME dismissal during teardown triggering a focus
// change. Twice.
@@ -1472,9 +1633,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
Textfield* textfield = InstallTextField("");
EXPECT_TRUE([ns_view_ textInputClient]);
- base::mac::ScopedObjCClassSwizzler interpret_key_events_swizzler(
- [NSView class], [InterpretKeyEventsDonorForNSView class],
- @selector(interpretKeyEvents:));
+ object_setClass(ns_view_, [InterpretKeyEventMockedBridgedContentView class]);
base::mac::ScopedObjCClassSwizzler update_windows_swizzler(
[NSApplication class], [UpdateWindowsDonorForNSApp class],
@selector(updateWindows));
@@ -1580,18 +1739,10 @@ typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest;
// mashing Ctrl+Left/Right to keep OSX in a transition between Spaces to cause
// the fullscreen transition to fail.
TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
- base::scoped_nsobject<NSWindow> owned_window(
- [[BridgedNativeWidgetTestFullScreenWindow alloc]
- initWithContentRect:NSMakeRect(50, 50, 400, 300)
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [owned_window setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
- bridge()->Init(owned_window, init_params_); // Transfers ownership.
-
- BridgedNativeWidgetTestFullScreenWindow* window =
- base::mac::ObjCCastStrict<BridgedNativeWidgetTestFullScreenWindow>(
+ BridgedNativeWidgetTestWindow* window =
+ base::mac::ObjCCastStrict<BridgedNativeWidgetTestWindow>(
widget_->GetNativeWindow());
+ [window setIgnoreToggleFullScreen:YES];
widget_->Show();
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
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 dd5edea74a8..9f3559de2ef 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -14,6 +14,7 @@
#import "ui/base/clipboard/clipboard_util_mac.h"
#include "ui/gfx/image/image_unittest_util.h"
#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view.h"
#include "ui/views/widget/native_widget_mac.h"
@@ -187,6 +188,8 @@ class DragDropClientMacTest : public WidgetTest {
bridge_ =
NativeWidgetMac::GetBridgeForNativeWindow(widget_->GetNativeWindow());
+ bridge_host_ = NativeWidgetMac::GetBridgeHostImplForNativeWindow(
+ widget_->GetNativeWindow());
widget_->Show();
target_ = new DragDropView();
@@ -205,6 +208,7 @@ class DragDropClientMacTest : public WidgetTest {
protected:
Widget* widget_ = nullptr;
BridgedNativeWidget* bridge_ = nullptr;
+ BridgedNativeWidgetHostImpl* bridge_host_ = nullptr;
DragDropView* target_ = nullptr;
base::scoped_nsobject<MockDraggingInfo> dragging_info_;
@@ -236,7 +240,7 @@ TEST_F(DragDropClientMacTest, ReleaseCapture) {
// since the runloop will exit before the system has any opportunity to
// capture anything.
bridge_->AcquireCapture();
- EXPECT_TRUE(bridge_->HasCapture());
+ EXPECT_TRUE(bridge_host_->IsMouseCaptureActive());
// Create the drop data
OSExchangeData data;
@@ -262,7 +266,7 @@ TEST_F(DragDropClientMacTest, ReleaseCapture) {
target_, data, 0, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
// The capture should be released.
- EXPECT_FALSE(bridge_->HasCapture());
+ EXPECT_FALSE(bridge_host_->IsMouseCaptureActive());
}
// Tests if the drag and drop target rejects the dropped data with the
diff --git a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
index ea244d97722..3e5775bc184 100644
--- a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
+++ b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
@@ -7,6 +7,7 @@
#include "base/mac/foundation_util.h"
#import "base/mac/sdk_forward_declarations.h"
#import "ui/base/cocoa/user_interface_item_command_handler.h"
+#import "ui/base/cocoa/window_size_constants.h"
#import "ui/views/cocoa/bridged_native_widget.h"
#import "ui/views/cocoa/views_nswindow_delegate.h"
#import "ui/views/cocoa/window_touch_bar_delegate.h"
@@ -88,7 +89,8 @@
styleMask:(NSUInteger)windowStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)deferCreation {
- if ((self = [super initWithContentRect:contentRect
+ DCHECK(NSEqualRects(contentRect, ui::kWindowSizeDeterminedLater));
+ if ((self = [super initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:windowStyle
backing:bufferingType
defer:deferCreation])) {
diff --git a/chromium/ui/views/cocoa/views_nswindow_delegate.mm b/chromium/ui/views/cocoa/views_nswindow_delegate.mm
index 9472e5e4043..bce74956126 100644
--- a/chromium/ui/views/cocoa/views_nswindow_delegate.mm
+++ b/chromium/ui/views/cocoa/views_nswindow_delegate.mm
@@ -9,6 +9,7 @@
#include "base/threading/thread_task_runner_handle.h"
#import "ui/views/cocoa/bridged_content_view.h"
#import "ui/views/cocoa/bridged_native_widget.h"
+#include "ui/views/cocoa/bridged_native_widget_host.h"
#include "ui/views/widget/native_widget_mac.h"
@implementation ViewsNSWindowDelegate
@@ -155,10 +156,12 @@
}
- (void)windowDidMiniaturize:(NSNotification*)notification {
+ parent_->host()->OnWindowMiniaturizedChanged(true);
parent_->OnVisibilityChanged();
}
- (void)windowDidDeminiaturize:(NSNotification*)notification {
+ parent_->host()->OnWindowMiniaturizedChanged(false);
parent_->OnVisibilityChanged();
}
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index f73a3102e63..9656e5dc4a3 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -476,6 +476,7 @@ Button::Button(ButtonListener* listener)
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
SetProperty(kIsButtonProperty, true);
hover_animation_.SetSlideDuration(kHoverFadeDurationMs);
+ SetInstallFocusRingOnFocus(PlatformStyle::kPreferFocusRings);
}
Button::KeyClickAction Button::GetKeyClickActionForEvent(
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index 5dc51b40272..91e398ebfe3 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -9,7 +9,6 @@
#include <utility>
#include "ui/accessibility/ax_node_data.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/color_palette.h"
@@ -33,72 +32,23 @@ namespace views {
// static
const char Checkbox::kViewClassName[] = "Checkbox";
-Checkbox::Checkbox(const base::string16& label,
- ButtonListener* listener,
- bool force_md)
- : LabelButton(listener, label),
- checked_(false),
- label_ax_id_(0),
- use_md_(force_md ||
- ui::MaterialDesignController::IsSecondaryUiMaterial()) {
+Checkbox::Checkbox(const base::string16& label, ButtonListener* listener)
+ : LabelButton(listener, label), checked_(false), label_ax_id_(0) {
SetHorizontalAlignment(gfx::ALIGN_LEFT);
SetFocusForPlatform();
SetFocusPainter(nullptr);
- if (UseMd()) {
- set_request_focus_on_press(false);
- SetInkDropMode(InkDropMode::ON);
- set_has_ink_drop_action_on_click(true);
- focus_ring_ = FocusRing::Install(this);
- } else {
- std::unique_ptr<LabelButtonBorder> button_border(new LabelButtonBorder());
- // Inset the trailing side by a couple pixels for the focus border.
- button_border->set_insets(gfx::Insets(0, 0, 0, 2));
- SetBorder(std::move(button_border));
- set_request_focus_on_press(true);
-
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
- // Unchecked/Unfocused images.
- SetCustomImage(false, false, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX));
- SetCustomImage(false, false, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_HOVER));
- SetCustomImage(false, false, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_PRESSED));
- SetCustomImage(false, false, STATE_DISABLED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_DISABLED));
-
- // Checked/Unfocused images.
- SetCustomImage(true, false, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED));
- SetCustomImage(true, false, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED_HOVER));
- SetCustomImage(true, false, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED_PRESSED));
- SetCustomImage(true, false, STATE_DISABLED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_CHECKED_DISABLED));
-
- // Unchecked/Focused images.
- SetCustomImage(false, true, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED));
- SetCustomImage(false, true, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_HOVER));
- SetCustomImage(false, true, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_PRESSED));
-
- // Checked/Focused images.
- SetCustomImage(true, true, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_CHECKED));
- SetCustomImage(true, true, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_CHECKED_HOVER));
- SetCustomImage(true, true, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_CHECKBOX_FOCUSED_CHECKED_PRESSED));
- }
+ set_request_focus_on_press(false);
+ SetInkDropMode(InkDropMode::ON);
+ set_has_ink_drop_action_on_click(true);
// Limit the checkbox height to match the legacy appearance.
const gfx::Size preferred_size(LabelButton::CalculatePreferredSize());
SetMinSize(gfx::Size(0, preferred_size.height() + 4));
+
+ // Checkboxes always have a focus ring, even when the platform otherwise
+ // doesn't generally use them for buttons.
+ SetInstallFocusRingOnFocus(true);
}
Checkbox::~Checkbox() {
@@ -125,12 +75,6 @@ void Checkbox::SetAssociatedLabel(View* labelling_view) {
node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
}
-// TODO(tetsui): Remove this method and |use_md_| when MD for secondary UI
-// becomes default and IsSecondaryUiMaterial() is tautology.
-bool Checkbox::UseMd() const {
- return use_md_;
-}
-
const char* Checkbox::GetClassName() const {
return kViewClassName;
}
@@ -155,22 +99,9 @@ void Checkbox::GetAccessibleNodeData(ui::AXNodeData* node_data) {
}
}
-void Checkbox::OnFocus() {
- LabelButton::OnFocus();
- if (!UseMd())
- UpdateImage();
-}
-
-void Checkbox::OnBlur() {
- LabelButton::OnBlur();
- if (!UseMd())
- UpdateImage();
-}
-
void Checkbox::OnNativeThemeChanged(const ui::NativeTheme* theme) {
LabelButton::OnNativeThemeChanged(theme);
- if (UseMd())
- UpdateImage();
+ UpdateImage();
}
std::unique_ptr<InkDrop> Checkbox::CreateInkDrop() {
@@ -194,19 +125,10 @@ SkColor Checkbox::GetInkDropBaseColor() const {
}
gfx::ImageSkia Checkbox::GetImage(ButtonState for_state) const {
- if (UseMd()) {
- const int checked = checked_ ? IconState::CHECKED : 0;
- const int enabled = for_state != STATE_DISABLED ? IconState::ENABLED : 0;
- return gfx::CreateVectorIcon(GetVectorIcon(), 16,
- GetIconImageColor(checked | enabled));
- }
-
- const size_t checked_index = checked_ ? 1 : 0;
- const size_t focused_index = HasFocus() ? 1 : 0;
- if (for_state != STATE_NORMAL &&
- images_[checked_index][focused_index][for_state].isNull())
- return images_[checked_index][focused_index][STATE_NORMAL];
- return images_[checked_index][focused_index][for_state];
+ const int checked = checked_ ? IconState::CHECKED : 0;
+ const int enabled = for_state != STATE_DISABLED ? IconState::ENABLED : 0;
+ return gfx::CreateVectorIcon(GetVectorIcon(), 16,
+ GetIconImageColor(checked | enabled));
}
std::unique_ptr<LabelButtonBorder> Checkbox::CreateDefaultBorder() const {
@@ -219,8 +141,8 @@ std::unique_ptr<LabelButtonBorder> Checkbox::CreateDefaultBorder() const {
void Checkbox::Layout() {
LabelButton::Layout();
- if (focus_ring_ && !image()->bounds().IsEmpty())
- focus_ring_->SetPath(GetFocusRingPath());
+ if (focus_ring() && !image()->bounds().IsEmpty())
+ focus_ring()->SetPath(GetFocusRingPath());
}
SkPath Checkbox::GetFocusRingPath() const {
@@ -231,22 +153,11 @@ SkPath Checkbox::GetFocusRingPath() const {
return path;
}
-void Checkbox::SetCustomImage(bool checked,
- bool focused,
- ButtonState for_state,
- const gfx::ImageSkia& image) {
- const size_t checked_index = checked ? 1 : 0;
- const size_t focused_index = focused ? 1 : 0;
- images_[checked_index][focused_index][for_state] = image;
- UpdateImage();
-}
-
const gfx::VectorIcon& Checkbox::GetVectorIcon() const {
return checked() ? kCheckboxActiveIcon : kCheckboxNormalIcon;
}
SkColor Checkbox::GetIconImageColor(int icon_state) const {
- DCHECK(UseMd());
const SkColor active_color =
(icon_state & IconState::CHECKED)
? GetNativeTheme()->GetSystemColor(
diff --git a/chromium/ui/views/controls/button/checkbox.h b/chromium/ui/views/controls/button/checkbox.h
index 6fb4c93b61a..d2b6f12e698 100644
--- a/chromium/ui/views/controls/button/checkbox.h
+++ b/chromium/ui/views/controls/button/checkbox.h
@@ -28,8 +28,7 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// |force_md| forces MD even when --secondary-ui-md flag is not set.
explicit Checkbox(const base::string16& label,
- ButtonListener* listener = nullptr,
- bool force_md = false);
+ ButtonListener* listener = nullptr);
~Checkbox() override;
// Sets/Gets whether or not the checkbox is checked.
@@ -48,14 +47,8 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
protected:
- // Returns whether MD is enabled. Returns true if |force_md| in the
- // constructor or --secondary-ui-md flag is set.
- bool UseMd() const;
-
// LabelButton:
const char* GetClassName() const override;
- void OnFocus() override;
- void OnBlur() override;
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
std::unique_ptr<InkDrop> CreateInkDrop() override;
std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
@@ -64,13 +57,6 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override;
void Layout() override;
- // Set the image shown for each button state depending on whether it is
- // [checked] or [focused].
- void SetCustomImage(bool checked,
- bool focused,
- ButtonState for_state,
- const gfx::ImageSkia& image);
-
// Gets the vector icon to use based on the current state of |checked_|.
virtual const gfx::VectorIcon& GetVectorIcon() const;
@@ -95,17 +81,9 @@ class VIEWS_EXPORT Checkbox : public LabelButton {
// True if the checkbox is checked.
bool checked_;
- // The images for each button node_data.
- gfx::ImageSkia images_[2][2][STATE_COUNT];
-
// The unique id for the associated label's accessible object.
int32_t label_ax_id_;
- // The focus ring to use for this Checkbox.
- std::unique_ptr<FocusRing> focus_ring_;
-
- bool use_md_;
-
DISALLOW_COPY_AND_ASSIGN(Checkbox);
};
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index e3c0f6e9dc2..4e6011dc24e 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -27,47 +27,20 @@
namespace views {
-namespace {
-
-bool UseMaterialSecondaryButtons() {
-#if defined(OS_MACOSX)
- return true;
-#else
- return ui::MaterialDesignController::IsSecondaryUiMaterial();
-#endif // defined(OS_MACOSX)
-}
-
-LabelButton* CreateButton(ButtonListener* listener,
- const base::string16& text,
- bool md) {
- if (md)
- return MdTextButton::Create(listener, text, style::CONTEXT_BUTTON_MD);
-
- LabelButton* button = new LabelButton(listener, text, style::CONTEXT_BUTTON);
- button->SetStyleDeprecated(Button::STYLE_BUTTON);
- return button;
-}
-
-} // namespace
-
// static
LabelButton* MdTextButton::CreateSecondaryUiButton(ButtonListener* listener,
const base::string16& text) {
- return CreateButton(listener, text, UseMaterialSecondaryButtons());
+ return MdTextButton::Create(listener, text, style::CONTEXT_BUTTON_MD);
}
// static
LabelButton* MdTextButton::CreateSecondaryUiBlueButton(
ButtonListener* listener,
const base::string16& text) {
- if (UseMaterialSecondaryButtons()) {
- MdTextButton* md_button =
- MdTextButton::Create(listener, text, style::CONTEXT_BUTTON_MD);
- md_button->SetProminent(true);
- return md_button;
- }
-
- return new BlueButton(listener, text);
+ MdTextButton* md_button =
+ MdTextButton::Create(listener, text, style::CONTEXT_BUTTON_MD);
+ md_button->SetProminent(true);
+ return md_button;
}
// static
@@ -106,7 +79,11 @@ void MdTextButton::OnPaintBackground(gfx::Canvas* canvas) {
if (hover_animation().is_animating() || state() == STATE_HOVERED) {
const int kHoverAlpha = is_prominent_ ? 0x0c : 0x05;
SkScalar alpha = hover_animation().CurrentValueBetween(0, kHoverAlpha);
- canvas->FillRect(GetLocalBounds(), SkColorSetA(SK_ColorBLACK, alpha));
+ cc::PaintFlags flags;
+ flags.setColor(SkColorSetA(SK_ColorBLACK, alpha));
+ flags.setStyle(cc::PaintFlags::kFill_Style);
+ flags.setAntiAlias(true);
+ canvas->DrawRoundRect(gfx::RectF(GetLocalBounds()), corner_radius_, flags);
}
}
@@ -303,25 +280,10 @@ void MdTextButton::UpdateColors() {
// Harmony and non-Harmony colors.
stroke_alpha = 0x43;
} else {
- // These alpha values will take the enabled button colors, 5a5a5a @ 1.0
- // alpha for non-Harmony, 757575 @ 1.0 alpha for Harmony and turn it into
- // an effective b2b2b2 @ 1.0 alpha or 000000 @ 0.3 for the stroke_color.
- stroke_alpha = UseMaterialSecondaryButtons() ? 0x8f : 0x77;
-#if defined(OS_MACOSX)
- // Without full secondary UI MD support, the text color is solid black,
- // and so the border is too dark on Mac. On Retina it looks OK, so
- // heuristically determine the scale factor as well.
- if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- // The Compositor may only be set when attached to a Widget. But, since
- // that also determines the theme, UpdateColors() will always be called
- // after attaching to a Widget.
- // TODO(tapted): Move this into SolidRoundRectPainter if we like this
- // logic for Harmony.
- auto* compositor = layer()->GetCompositor();
- if (compositor && compositor->device_scale_factor() == 1)
- stroke_alpha = 0x4d; // Chosen to match full secondary UI MD (0.3).
- }
-#endif
+ // These alpha values will take the enabled button colors, 757575 @ 1.0
+ // alpha turn it into an effective b2b2b2 @ 1.0 alpha or 000000 @ 0.3 for
+ // the stroke_color.
+ stroke_alpha = 0x8f;
}
stroke_color = SkColorSetA(text_color, stroke_alpha);
}
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index b9dbdbe82dc..9adf4949221 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -19,51 +19,9 @@ namespace views {
// static
const char RadioButton::kViewClassName[] = "RadioButton";
-RadioButton::RadioButton(const base::string16& label,
- int group_id,
- bool force_md)
- : Checkbox(label, nullptr, force_md) {
+RadioButton::RadioButton(const base::string16& label, int group_id)
+ : Checkbox(label, nullptr) {
SetGroup(group_id);
-
- if (!UseMd()) {
- set_request_focus_on_press(true);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- // Unchecked/Unfocused images.
- SetCustomImage(false, false, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_RADIO));
- SetCustomImage(false, false, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_RADIO_HOVER));
- SetCustomImage(false, false, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_RADIO_PRESSED));
- SetCustomImage(false, false, STATE_DISABLED,
- *rb.GetImageSkiaNamed(IDR_RADIO_DISABLED));
-
- // Checked/Unfocused images.
- SetCustomImage(true, false, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED));
- SetCustomImage(true, false, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_HOVER));
- SetCustomImage(true, false, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_PRESSED));
- SetCustomImage(true, false, STATE_DISABLED,
- *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_DISABLED));
-
- // Unchecked/Focused images.
- SetCustomImage(false, true, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED));
- SetCustomImage(false, true, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_HOVER));
- SetCustomImage(false, true, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_PRESSED));
-
- // Checked/Focused images.
- SetCustomImage(true, true, STATE_NORMAL,
- *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED));
- SetCustomImage(true, true, STATE_HOVERED,
- *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_HOVER));
- SetCustomImage(true, true, STATE_PRESSED,
- *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_PRESSED));
- }
}
RadioButton::~RadioButton() {
diff --git a/chromium/ui/views/controls/button/radio_button.h b/chromium/ui/views/controls/button/radio_button.h
index 02cf91dcf8d..2810468881f 100644
--- a/chromium/ui/views/controls/button/radio_button.h
+++ b/chromium/ui/views/controls/button/radio_button.h
@@ -19,8 +19,7 @@ class VIEWS_EXPORT RadioButton : public Checkbox {
// The button's class name.
static const char kViewClassName[];
- // |force_md| forces MD even when --secondary-ui-md flag is not set.
- RadioButton(const base::string16& label, int group_id, bool force_md = false);
+ RadioButton(const base::string16& label, int group_id);
~RadioButton() override;
// Overridden from View:
diff --git a/chromium/ui/views/controls/button/radio_button_unittest.cc b/chromium/ui/views/controls/button/radio_button_unittest.cc
index 19485e6c773..390809e36ee 100644
--- a/chromium/ui/views/controls/button/radio_button_unittest.cc
+++ b/chromium/ui/views/controls/button/radio_button_unittest.cc
@@ -6,7 +6,6 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/events/base_event_utils.h"
#include "ui/views/test/views_test_base.h"
@@ -113,26 +112,18 @@ TEST_F(RadioButtonTest, FocusOnClick) {
EXPECT_TRUE(button2->checked());
auto* focus_manager = button_container().GetFocusManager();
- // Focus behavior is different pre/post-Harmony.
- if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- // No focus on click.
- EXPECT_EQ(nullptr, focus_manager->GetFocusedView());
-
- ui::KeyEvent pressed_tab(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE);
- focus_manager->OnKeyEvent(pressed_tab);
- EXPECT_EQ(button2, focus_manager->GetFocusedView());
-
- button1->OnMousePressed(event);
- button1->OnMouseReleased(event);
- // Button 1 gets focus on click because button 2 already had it.
- EXPECT_TRUE(button1->checked());
- EXPECT_EQ(button1, focus_manager->GetFocusedView());
- } else if (button2->request_focus_on_press()) {
- EXPECT_EQ(button2, focus_manager->GetFocusedView());
- } else {
- // On Mac, buttons never (and can not be made to) request focus on clicks.
- EXPECT_EQ(nullptr, focus_manager->GetFocusedView());
- }
+ // No focus on click.
+ EXPECT_EQ(nullptr, focus_manager->GetFocusedView());
+
+ ui::KeyEvent pressed_tab(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE);
+ focus_manager->OnKeyEvent(pressed_tab);
+ EXPECT_EQ(button2, focus_manager->GetFocusedView());
+
+ button1->OnMousePressed(event);
+ button1->OnMouseReleased(event);
+ // Button 1 gets focus on click because button 2 already had it.
+ EXPECT_TRUE(button1->checked());
+ EXPECT_EQ(button1, focus_manager->GetFocusedView());
}
} // namespace views
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index 2cb22fea6dc..f900b99d012 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -15,7 +15,6 @@
#include "ui/accessibility/ax_node_data.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_observer.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
@@ -93,10 +92,6 @@ const int kFocusedPressedMenuButtonImages[] =
#undef MENU_IMAGE_GRID
-bool UseMd() {
- return ui::MaterialDesignController::IsSecondaryUiMaterial();
-}
-
SkColor GetTextColorForEnableState(const Combobox& combobox, bool enabled) {
return style::GetColor(
combobox, style::CONTEXT_TEXTFIELD,
@@ -130,10 +125,8 @@ class TransparentButton : public Button {
SetFocusBehavior(FocusBehavior::NEVER);
set_notify_action(PlatformStyle::kMenuNotifyActivationAction);
- if (UseMd()) {
- SetInkDropMode(InkDropMode::ON);
- set_has_ink_drop_action_on_click(true);
- }
+ SetInkDropMode(InkDropMode::ON);
+ set_has_ink_drop_action_on_click(true);
}
~TransparentButton() override {}
@@ -455,16 +448,10 @@ Combobox::Combobox(ui::ComboboxModel* model, Style style)
// 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();
- layer()->SetFillsBoundsOpaquely(false);
- } else {
- arrow_image_ = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
- IDR_MENU_DROPARROW);
- }
+ SetPaintToLayer();
+ layer()->SetFillsBoundsOpaquely(false);
- if (UseMd())
- focus_ring_ = FocusRing::Install(this);
+ focus_ring_ = FocusRing::Install(this);
}
Combobox::~Combobox() {
@@ -567,9 +554,6 @@ void Combobox::Layout() {
}
void Combobox::OnNativeThemeChanged(const ui::NativeTheme* theme) {
- if (!UseMd())
- return;
-
SetBackground(
CreateBackgroundFromPainter(Painter::CreateSolidRoundRectPainter(
theme->GetSystemColor(
@@ -795,9 +779,6 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
if (!enabled())
return;
- if (!UseMd())
- RequestFocus();
-
if (sender == text_button_) {
OnPerformAction();
} else {
@@ -865,7 +846,7 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
PositionArrowWithinContainer(arrow_bounds, ArrowSize(), style_);
AdjustBoundsForRTLUI(&arrow_bounds);
- 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.
@@ -890,8 +871,6 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
flags.setColor(arrow_color);
flags.setAntiAlias(true);
canvas->DrawPath(path, flags);
- } else {
- canvas->DrawImageInt(arrow_image_, arrow_bounds.x(), arrow_bounds.y());
}
}
@@ -1005,7 +984,7 @@ void Combobox::OnPerformAction() {
}
gfx::Size Combobox::ArrowSize() const {
- return UseMd() ? gfx::Size(8, 4) : arrow_image_.size();
+ return gfx::Size(8, 4);
}
gfx::Size Combobox::GetContentSize() const {
@@ -1031,11 +1010,9 @@ PrefixSelector* Combobox::GetPrefixSelector() {
}
int Combobox::GetArrowContainerWidth() const {
- constexpr int kMdPaddingWidth = 8;
- constexpr int kNormalPaddingWidth = 7;
- int arrow_pad = UseMd() ? kMdPaddingWidth : kNormalPaddingWidth;
+ constexpr int kPaddingWidth = 8;
int padding = style_ == STYLE_NORMAL
- ? arrow_pad * 2
+ ? kPaddingWidth * 2
: kActionLeftPadding + kActionRightPadding;
return ArrowSize().width() + padding;
}
diff --git a/chromium/ui/views/controls/focusable_border.cc b/chromium/ui/views/controls/focusable_border.cc
index 3b60677ecb0..800736a15d0 100644
--- a/chromium/ui/views/controls/focusable_border.cc
+++ b/chromium/ui/views/controls/focusable_border.cc
@@ -6,7 +6,6 @@
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkPath.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"
@@ -43,10 +42,7 @@ void FocusableBorder::Paint(const View& view, gfx::Canvas* canvas) {
gfx::ScopedCanvas scoped(canvas);
float dsf = canvas->UndoDeviceScaleFactor();
- const int stroke_width_px =
- ui::MaterialDesignController::IsSecondaryUiMaterial()
- ? 1
- : gfx::ToFlooredInt(dsf);
+ const int stroke_width_px = 1;
flags.setStrokeWidth(SkIntToScalar(stroke_width_px));
// Scale the rect and snap to pixel boundaries.
@@ -54,14 +50,10 @@ void FocusableBorder::Paint(const View& view, gfx::Canvas* canvas) {
rect.Inset(gfx::InsetsF(stroke_width_px / 2.0f));
SkPath path;
- if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
flags.setAntiAlias(true);
float corner_radius_px = kCornerRadiusDp * dsf;
path.addRoundRect(gfx::RectFToSkRect(rect), corner_radius_px,
corner_radius_px);
- } else {
- path.addRect(gfx::RectFToSkRect(rect), SkPath::kCW_Direction);
- }
canvas->DrawPath(path, flags);
}
@@ -85,18 +77,11 @@ void FocusableBorder::SetInsets(int vertical, int horizontal) {
SkColor FocusableBorder::GetCurrentColor(const View& view) const {
ui::NativeTheme::ColorId color_id =
ui::NativeTheme::kColorId_UnfocusedBorderColor;
- if (override_color_id_) {
+ if (override_color_id_)
color_id = *override_color_id_;
- } else if (view.HasFocus() &&
- !ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- // Note with --secondary-ui-md there is a FocusRing indicator, so the border
- // retains its unfocused color.
- color_id = ui::NativeTheme::kColorId_FocusedBorderColor;
- }
SkColor color = view.GetNativeTheme()->GetSystemColor(color_id);
- if (ui::MaterialDesignController::IsSecondaryUiMaterial() &&
- !view.enabled()) {
+ if (!view.enabled()) {
return color_utils::BlendTowardOppositeLuma(color,
gfx::kDisabledControlAlpha);
}
diff --git a/chromium/ui/views/controls/label.h b/chromium/ui/views/controls/label.h
index 1d35afeda78..9c78b30ab3a 100644
--- a/chromium/ui/views/controls/label.h
+++ b/chromium/ui/views/controls/label.h
@@ -258,7 +258,7 @@ class VIEWS_EXPORT Label : public View,
FRIEND_TEST_ALL_PREFIXES(LabelTest, MultilineSupportedRenderText);
FRIEND_TEST_ALL_PREFIXES(LabelTest, TextChangeWithoutLayout);
FRIEND_TEST_ALL_PREFIXES(LabelTest, EmptyLabel);
- FRIEND_TEST_ALL_PREFIXES(MDLabelTest, FocusBounds);
+ FRIEND_TEST_ALL_PREFIXES(LabelTest, FocusBounds);
FRIEND_TEST_ALL_PREFIXES(LabelTest, MultiLineSizingWithElide);
friend class LabelSelectionTest;
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index e5eafe1bd53..d87acf7c42d 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -9,13 +9,11 @@
#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/compositor/canvas_painter.h"
#include "ui/events/base_event_utils.h"
@@ -97,13 +95,6 @@ base::string16 GetClipboardText(ui::ClipboardType clipboard_type) {
return clipboard_text;
}
-enum class SecondaryUiMode { NON_MD, MD };
-
-std::string SecondaryUiModeToString(
- const ::testing::TestParamInfo<SecondaryUiMode>& info) {
- return info.param == SecondaryUiMode::MD ? "MD" : "NonMD";
-}
-
// Makes an RTL string by mapping 0..6 to [א,ב,ג,ד,ה,ו,ז].
base::string16 ToRTL(const char* ascii) {
base::string16 rtl;
@@ -269,31 +260,6 @@ class LabelSelectionTest : public LabelTest {
DISALLOW_COPY_AND_ASSIGN(LabelSelectionTest);
};
-// LabelTest harness that runs both with and without secondary UI set to MD.
-class MDLabelTest : public LabelTest,
- public ::testing::WithParamInterface<SecondaryUiMode> {
- public:
- MDLabelTest() {}
-
- // LabelTest:
- void SetUp() override {
- if (GetParam() == SecondaryUiMode::MD) {
- scoped_feature_list_.InitAndEnableFeature(features::kSecondaryUiMd);
- } else {
- // Force Refresh UI to be off, since that mode implies MD secondary UI.
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kTopChromeMD, switches::kTopChromeMDMaterial);
- scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
- }
- LabelTest::SetUp();
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-
- DISALLOW_COPY_AND_ASSIGN(MDLabelTest);
-};
-
// Crashes on Linux only. http://crbug.com/612406
#if defined(OS_LINUX)
#define MAYBE_FontPropertySymbol DISABLED_FontPropertySymbol
@@ -933,7 +899,7 @@ TEST_F(LabelTest, NoSchedulePaintInOnPaint) {
EXPECT_EQ(count, label.schedule_paint_count()); // Unchanged.
}
-TEST_P(MDLabelTest, FocusBounds) {
+TEST_F(LabelTest, FocusBounds) {
label()->SetText(ASCIIToUTF16("Example"));
Link concrete_link(ASCIIToUTF16("Example"));
Label* link = &concrete_link; // Allow LabelTest to call methods as friend.
@@ -959,16 +925,10 @@ TEST_P(MDLabelTest, FocusBounds) {
gfx::Size normal_link_size = link->GetPreferredSize();
link->SetFocusBehavior(View::FocusBehavior::ALWAYS);
gfx::Size focusable_link_size = link->GetPreferredSize();
- if (GetParam() == SecondaryUiMode::MD) {
- // Everything should match under MD since underlines indicates focus.
- EXPECT_EQ(normal_label_size, normal_link_size);
- EXPECT_EQ(normal_link_size, focusable_link_size);
- } else {
- // Otherwise, links get bigger in order to paint the focus rectangle.
- EXPECT_NE(normal_link_size, focusable_link_size);
- EXPECT_GT(focusable_link_size.width(), normal_link_size.width());
- EXPECT_GT(focusable_link_size.height(), normal_link_size.height());
- }
+
+ // Everything should match since underlines indicates focus.
+ EXPECT_EQ(normal_label_size, normal_link_size);
+ EXPECT_EQ(normal_link_size, focusable_link_size);
// Requesting focus doesn't change the preferred size since that would mess up
// layout.
@@ -1405,10 +1365,4 @@ TEST_F(LabelSelectionTest, ContextMenuContents) {
EXPECT_FALSE(IsMenuCommandEnabled(IDS_APP_SELECT_ALL));
}
-INSTANTIATE_TEST_CASE_P(,
- MDLabelTest,
- ::testing::Values(SecondaryUiMode::MD,
- SecondaryUiMode::NON_MD),
- &SecondaryUiModeToString);
-
} // namespace views
diff --git a/chromium/ui/views/controls/link.cc b/chromium/ui/views/controls/link.cc
index f4e605aaedb..e47a0c89edb 100644
--- a/chromium/ui/views/controls/link.cc
+++ b/chromium/ui/views/controls/link.cc
@@ -10,7 +10,6 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/cursor/cursor.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
@@ -39,9 +38,7 @@ Link::~Link() {
// static
Link::FocusStyle Link::GetDefaultFocusStyle() {
- return ui::MaterialDesignController::IsSecondaryUiMaterial()
- ? FocusStyle::UNDERLINE
- : FocusStyle::RING;
+ return FocusStyle::UNDERLINE;
}
Link::FocusStyle Link::GetFocusStyle() const {
diff --git a/chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.h b/chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.h
new file mode 100644
index 00000000000..96e55221033
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.h
@@ -0,0 +1,36 @@
+// Copyright 2018 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_COCOA_WATCHER_MAC_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_COCOA_WATCHER_MAC_H_
+
+#include <objc/objc.h>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// This class executes a callback when a native menu begins tracking. With
+// native menus, each one automatically closes when a new one begins tracking.
+// This allows Views menus to tie into this behavior.
+class VIEWS_EXPORT MenuCocoaWatcherMac {
+ public:
+ explicit MenuCocoaWatcherMac(base::OnceClosure callback);
+ ~MenuCocoaWatcherMac();
+
+ private:
+ // The closure to call when the notification comes in.
+ base::OnceClosure callback_;
+
+ // The token representing the notification observer.
+ id observer_token_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuCocoaWatcherMac);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_COCOA_WATCHER_MAC_H_
diff --git a/chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.mm b/chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.mm
new file mode 100644
index 00000000000..da563e6a4cd
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_cocoa_watcher_mac.mm
@@ -0,0 +1,28 @@
+// Copyright 2018 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_cocoa_watcher_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import <utility>
+
+namespace views {
+
+MenuCocoaWatcherMac::MenuCocoaWatcherMac(base::OnceClosure callback)
+ : callback_(std::move(callback)) {
+ observer_token_ = [[NSNotificationCenter defaultCenter]
+ addObserverForName:NSMenuDidBeginTrackingNotification
+ object:[NSApp mainMenu]
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ std::move(this->callback_).Run();
+ }];
+}
+
+MenuCocoaWatcherMac::~MenuCocoaWatcherMac() {
+ [[NSNotificationCenter defaultCenter] removeObserver:observer_token_];
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index db532134db5..7ea5c0104bc 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -68,7 +68,8 @@ MenuConfig::MenuConfig()
vertical_touchable_menu_item_padding(8),
padded_separator_left_margin(64),
arrow_key_selection_wraps(true),
- show_context_menu_accelerators(true) {
+ show_context_menu_accelerators(true),
+ all_menus_use_prefix_selection(false) {
Init();
}
diff --git a/chromium/ui/views/controls/menu/menu_config.h b/chromium/ui/views/controls/menu/menu_config.h
index df02a976c59..885aa4ceb9e 100644
--- a/chromium/ui/views/controls/menu/menu_config.h
+++ b/chromium/ui/views/controls/menu/menu_config.h
@@ -38,7 +38,9 @@ struct VIEWS_EXPORT MenuConfig {
// Color for the arrow to scroll bookmarks.
SkColor arrow_color;
- // Menu border sizes.
+ // Menu border sizes. The vertical border size does not apply to menus with
+ // rounded corners - those menus always use the corner radius as the vertical
+ // border size.
int menu_vertical_border_size;
int menu_horizontal_border_size;
@@ -195,6 +197,9 @@ struct VIEWS_EXPORT MenuConfig {
// Whether to show accelerators in context menus.
bool show_context_menu_accelerators;
+ // Whether all types of menus use prefix selection for items.
+ bool all_menus_use_prefix_selection;
+
private:
// Configures a MenuConfig as appropriate for the current platform.
void Init();
diff --git a/chromium/ui/views/controls/menu/menu_config_mac.mm b/chromium/ui/views/controls/menu/menu_config_mac.mm
index 90939262b2e..607ed754986 100644
--- a/chromium/ui/views/controls/menu/menu_config_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_config_mac.mm
@@ -7,7 +7,6 @@
#import <AppKit/AppKit.h>
#include "base/mac/mac_util.h"
-#include "ui/base/material_design/material_design_controller.h"
namespace {
@@ -46,8 +45,8 @@ void MenuConfig::Init() {
arrow_key_selection_wraps = false;
use_mnemonics = false;
show_context_menu_accelerators = false;
- if (ui::MaterialDesignController::IsSecondaryUiMaterial())
- InitMaterialMenuConfig(this);
+ all_menus_use_prefix_selection = true;
+ InitMaterialMenuConfig(this);
}
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index beecb7f2717..d6806061652 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -31,6 +31,7 @@
#include "ui/views/controls/menu/menu_controller_delegate.h"
#include "ui/views/controls/menu/menu_host_root_view.h"
#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_pre_target_handler.h"
#include "ui/views/controls/menu/menu_scroll_view_container.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/drag_utils.h"
@@ -55,7 +56,6 @@
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/views/controls/menu/menu_pre_target_handler.h"
#endif
using base::TimeDelta;
@@ -461,13 +461,16 @@ void MenuController::Run(Widget* parent,
if (owner_)
owner_->AddObserver(this);
-#if defined(USE_AURA)
// 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
+ menu_pre_target_handler_ = MenuPreTargetHandler::Create(this, owner_);
}
+#if defined(OS_MACOSX)
+ menu_cocoa_watcher_ = std::make_unique<MenuCocoaWatcherMac>(
+ base::BindOnce(&MenuController::CancelAll, base::Unretained(this)));
+#endif
+
// Reset current state.
pending_state_ = State();
state_ = State();
@@ -582,7 +585,13 @@ bool MenuController::OnMousePressed(SubmenuView* source,
// Empty menu items are always handled by the menu controller.
if (!view || view->id() != MenuItemView::kEmptyMenuItemViewID) {
+ base::WeakPtr<MenuController> this_ref = AsWeakPtr();
bool processed = forward_to_root->ProcessMousePressed(event_for_root);
+ // This object may be destroyed as a result of a mouse press event (some
+ // item may close the menu).
+ if (!this_ref)
+ return true;
+
// If the event was processed, the root view becomes our current mouse
// handler...
if (processed && !current_mouse_event_target_) {
@@ -863,6 +872,10 @@ void MenuController::OnGestureEvent(SubmenuView* source,
}
void MenuController::OnTouchEvent(SubmenuView* source, ui::TouchEvent* event) {
+ // Bail if owner wants the current active gesture sequence.
+ if (owner_ && send_gesture_events_to_owner())
+ return;
+
if (event->type() == ui::ET_TOUCH_PRESSED) {
MenuPart part = GetMenuPart(source, event->location());
if (part.type == MenuPart::NONE) {
@@ -1371,6 +1384,15 @@ void MenuController::OnKeyDown(ui::KeyboardCode key_code) {
#if defined(OS_MACOSX)
case ui::VKEY_SPACE:
#endif
+ // An odd special case: if a prefix selection is in flight, space should
+ // add to that selection rather than activating the menu. This is
+ // important for allowing the user to select between items that have the
+ // same first word.
+ if (key_code == ui::VKEY_SPACE &&
+ MenuConfig::instance().all_menus_use_prefix_selection &&
+ ShouldContinuePrefixSelection()) {
+ break;
+ }
if (pending_state_.item) {
if (pending_state_.item->HasSubmenu()) {
if (key_code == ui::VKEY_F4 &&
@@ -1400,6 +1422,7 @@ void MenuController::OnKeyDown(ui::KeyboardCode key_code) {
CloseSubmenu();
break;
+#if !defined(OS_MACOSX)
case ui::VKEY_APPS: {
Button* hot_view = GetFirstHotTrackedView(pending_state_.item);
if (hot_view) {
@@ -1419,6 +1442,7 @@ void MenuController::OnKeyDown(ui::KeyboardCode key_code) {
}
break;
}
+#endif
#if defined(OS_WIN)
// On Windows, pressing Alt and F10 keys should hide the menu to match the
@@ -2046,7 +2070,10 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
const int right_of_parent =
item_loc.x() + item->width() - submenu_horizontal_inset;
- menu_bounds.set_y(item_loc.y() - menu_config.menu_vertical_border_size);
+ int border_size = menu_config.CornerRadiusForMenu(this);
+ if (!border_size)
+ border_size = menu_config.menu_vertical_border_size;
+ menu_bounds.set_y(item_loc.y() - border_size);
// Assume the menu can be placed in the preferred location.
menu_bounds.set_x(create_on_right ? right_of_parent : left_of_parent);
@@ -2111,7 +2138,14 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
item->actual_menu_position() == MenuItemView::POSITION_ABOVE_BOUNDS) {
// Menu has been drawn below/above the anchor bounds, make sure it fits
// on the screen in its current location.
+ const int drawn_width = menu_bounds.width();
menu_bounds.Intersect(monitor_bounds);
+
+ // Do not allow the menu to get narrower. This handles the case where the
+ // menu would have drawn off-screen, but the effective anchor was shifted
+ // at the end of this function. Preserve the width, so it is shifted
+ // again.
+ menu_bounds.set_width(drawn_width);
} else if (menu_bounds.bottom() <= monitor_bounds.bottom()) {
// Menu fits below anchor bounds.
item->set_actual_menu_position(MenuItemView::POSITION_BELOW_BOUNDS);
@@ -2140,6 +2174,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
}
}
+ // Ensure the menu is not displayed off screen.
menu_bounds.set_x(
base::ClampToRange(menu_bounds.x(), monitor_bounds.x(),
monitor_bounds.right() - menu_bounds.width()));
@@ -2161,7 +2196,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
SubmenuView* submenu = item->GetSubmenu();
DCHECK(submenu);
- gfx::Size pref = submenu->GetScrollViewContainer()->GetPreferredSize();
+ gfx::Size menu_size = submenu->GetScrollViewContainer()->GetPreferredSize();
int x = 0;
int y = 0;
const MenuConfig& menu_config = MenuConfig::instance();
@@ -2171,119 +2206,117 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
BubbleBorder::GetBorderAndShadowInsets(
menu_config.touchable_menu_shadow_elevation);
+ const gfx::Rect& monitor_bounds = state_.monitor_bounds;
+
if (!item->GetParentMenuItem()) {
// This is a top-level menu, position it relative to the anchor bounds.
- const gfx::Rect& owner_bounds = pending_state_.initial_bounds;
+ const gfx::Rect& anchor_bounds = pending_state_.initial_bounds;
// First the size gets reduced to the possible space.
- if (!state_.monitor_bounds.IsEmpty()) {
- int max_width = state_.monitor_bounds.width();
- int max_height = state_.monitor_bounds.height();
+ if (!monitor_bounds.IsEmpty()) {
+ int max_width = monitor_bounds.width();
+ int max_height = monitor_bounds.height();
// In case of bubbles, the maximum width is limited by the space
// between the display corner and the target area + the tip size.
if (state_.anchor == MENU_ANCHOR_BUBBLE_LEFT) {
- max_width = owner_bounds.x() - state_.monitor_bounds.x() +
- kBubbleTipSizeLeftRight;
+ max_width =
+ anchor_bounds.x() - monitor_bounds.x() + kBubbleTipSizeLeftRight;
} else if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT) {
- max_width = state_.monitor_bounds.right() - owner_bounds.right() +
+ max_width = monitor_bounds.right() - anchor_bounds.right() +
kBubbleTipSizeLeftRight;
} else if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE) {
- max_height = owner_bounds.y() - state_.monitor_bounds.y() +
- kBubbleTipSizeTopBottom;
+ max_height =
+ anchor_bounds.y() - monitor_bounds.y() + kBubbleTipSizeTopBottom;
} else if (state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
- max_height = state_.monitor_bounds.bottom() - owner_bounds.bottom() +
+ max_height = monitor_bounds.bottom() - anchor_bounds.bottom() +
kBubbleTipSizeTopBottom;
}
// The menu should always have a non-empty available area.
DCHECK_GE(max_width, kBubbleTipSizeLeftRight);
DCHECK_GE(max_height, kBubbleTipSizeTopBottom);
- pref.set_width(std::min(pref.width(), max_width));
- pref.set_height(std::min(pref.height(), max_height));
+ menu_size.SetToMin(gfx::Size(max_width, max_height));
}
// Respect the delegate's maximum width.
- pref.set_width(
- std::min(pref.width(), item->GetDelegate()->GetMaxWidthForMenu(item)));
+ menu_size.set_width(std::min(
+ menu_size.width(), item->GetDelegate()->GetMaxWidthForMenu(item)));
if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE ||
state_.anchor == MENU_ANCHOR_BUBBLE_BELOW) {
if (state_.anchor == MENU_ANCHOR_BUBBLE_ABOVE)
- y = owner_bounds.y() - pref.height() + kBubbleTipSizeTopBottom;
+ y = anchor_bounds.y() - menu_size.height() + kBubbleTipSizeTopBottom;
else
- y = owner_bounds.bottom() - kBubbleTipSizeTopBottom;
+ y = anchor_bounds.bottom() - kBubbleTipSizeTopBottom;
- x = owner_bounds.CenterPoint().x() - pref.width() / 2;
+ x = anchor_bounds.CenterPoint().x() - menu_size.width() / 2;
int x_old = x;
- if (x < state_.monitor_bounds.x())
- x = state_.monitor_bounds.x();
- else if (x + pref.width() > state_.monitor_bounds.right())
- x = state_.monitor_bounds.right() - pref.width();
- submenu->GetScrollViewContainer()->SetBubbleArrowOffset(pref.width() / 2 -
- x + x_old);
+ x = base::ClampToRange(x, monitor_bounds.x(),
+ monitor_bounds.right() - menu_size.width());
+ submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
+ menu_size.width() / 2 - x + x_old);
+ } else if (state_.anchor == MENU_ANCHOR_BUBBLE_LEFT ||
+ state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT) {
+ if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT)
+ x = anchor_bounds.right() - kBubbleTipSizeLeftRight;
+ else
+ x = anchor_bounds.x() - menu_size.width() + kBubbleTipSizeLeftRight;
+
+ y = anchor_bounds.CenterPoint().y() - menu_size.height() / 2;
+ int y_old = y;
+ y = base::ClampToRange(y, monitor_bounds.y(),
+ monitor_bounds.bottom() - menu_size.height());
+ submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
+ menu_size.height() / 2 - y + y_old);
} else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_ABOVE) {
// Align the left edges of the menu and anchor, and the bottom of the menu
// with the top of the anchor.
- x = owner_bounds.origin().x() - border_and_shadow_insets.left();
- y = owner_bounds.origin().y() - pref.height() +
+ x = anchor_bounds.x() - border_and_shadow_insets.left();
+ y = anchor_bounds.y() - menu_size.height() +
border_and_shadow_insets.bottom() -
menu_config.touchable_anchor_offset;
// Align the right of the container with the right of the anchor.
- if (x + pref.width() > state_.monitor_bounds.width()) {
- x = owner_bounds.right() - pref.width() +
+ if (x + menu_size.width() > monitor_bounds.width()) {
+ x = anchor_bounds.right() - menu_size.width() +
border_and_shadow_insets.right();
}
// Align the top of the menu with the bottom of the anchor.
- if (y < state_.monitor_bounds.y()) {
- y = owner_bounds.bottom() - border_and_shadow_insets.top() +
+ if (y < monitor_bounds.y()) {
+ y = anchor_bounds.bottom() - border_and_shadow_insets.top() +
menu_config.touchable_anchor_offset;
}
} else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_LEFT) {
// Align the right of the menu with the left of the anchor, and the top of
// the menu with the top of the anchor.
- x = owner_bounds.origin().x() - pref.width() +
+ x = anchor_bounds.x() - menu_size.width() +
border_and_shadow_insets.right() -
menu_config.touchable_anchor_offset;
- y = owner_bounds.origin().y() - border_and_shadow_insets.top();
+ y = anchor_bounds.y() - border_and_shadow_insets.top();
// Align the left of the menu with the right of the anchor.
- if (x < state_.monitor_bounds.x()) {
- x = owner_bounds.right() - border_and_shadow_insets.left() +
+ if (x < monitor_bounds.x()) {
+ x = anchor_bounds.right() - border_and_shadow_insets.left() +
menu_config.touchable_anchor_offset;
}
// Align the bottom of the menu to the bottom of the anchor.
- if (y + pref.height() > state_.monitor_bounds.height()) {
- y = owner_bounds.bottom() - pref.height() +
+ if (y + menu_size.height() > monitor_bounds.height()) {
+ y = anchor_bounds.bottom() - menu_size.height() +
border_and_shadow_insets.bottom();
}
} else if (state_.anchor == MENU_ANCHOR_BUBBLE_TOUCHABLE_RIGHT) {
// Align the left of the menu with the right of the anchor, and the top of
// the menu with the top of the anchor.
- x = owner_bounds.right() - border_and_shadow_insets.left() +
+ x = anchor_bounds.right() - border_and_shadow_insets.left() +
menu_config.touchable_anchor_offset;
- y = owner_bounds.origin().y() - border_and_shadow_insets.top();
- if (x + pref.width() > state_.monitor_bounds.width()) {
+ y = anchor_bounds.y() - border_and_shadow_insets.top();
+ if (x + menu_size.width() > monitor_bounds.width()) {
// Align the right of the menu with the left of the anchor.
- x = owner_bounds.origin().x() - pref.width() +
+ x = anchor_bounds.x() - menu_size.width() +
border_and_shadow_insets.right() -
menu_config.touchable_anchor_offset;
}
- if (y + pref.height() > state_.monitor_bounds.height()) {
+ if (y + menu_size.height() > monitor_bounds.height()) {
// Align the bottom of the menu with the bottom of the anchor.
- y = owner_bounds.bottom() - pref.height() +
+ y = anchor_bounds.bottom() - menu_size.height() +
border_and_shadow_insets.bottom();
}
- } else {
- if (state_.anchor == MENU_ANCHOR_BUBBLE_RIGHT)
- x = owner_bounds.right() - kBubbleTipSizeLeftRight;
- else
- x = owner_bounds.x() - pref.width() + kBubbleTipSizeLeftRight;
-
- y = owner_bounds.CenterPoint().y() - pref.height() / 2;
- int y_old = y;
- if (y < state_.monitor_bounds.y())
- y = state_.monitor_bounds.y();
- else if (y + pref.height() > state_.monitor_bounds.bottom())
- y = state_.monitor_bounds.bottom() - pref.height();
- submenu->GetScrollViewContainer()->SetBubbleArrowOffset(
- pref.height() / 2 - y + y_old);
}
} else {
if (!use_touchable_layout_) {
@@ -2296,14 +2329,12 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
// If the layout is RTL, then a 'leading' menu is positioned to the left of
// the parent menu item and not to the right.
const bool layout_is_rtl = base::i18n::IsRTL();
- const bool create_on_the_right = (prefer_leading && !layout_is_rtl) ||
- (!prefer_leading && layout_is_rtl);
- if (create_on_the_right) {
+ const bool create_on_right = prefer_leading != layout_is_rtl;
+ if (create_on_right) {
x = item_bounds.right() - border_and_shadow_insets.left();
- if (state_.monitor_bounds.width() != 0 &&
- (x + menu_config.touchable_menu_width -
- border_and_shadow_insets.right() >
- state_.monitor_bounds.right())) {
+ if (monitor_bounds.width() != 0 && (x + menu_config.touchable_menu_width -
+ border_and_shadow_insets.right() >
+ monitor_bounds.right())) {
*is_leading = prefer_leading;
x = item_bounds.x() - menu_config.touchable_menu_width -
border_and_shadow_insets.right();
@@ -2311,7 +2342,7 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
} else {
x = item_bounds.x() - menu_config.touchable_menu_width -
border_and_shadow_insets.right();
- if (state_.monitor_bounds.width() != 0 && x < state_.monitor_bounds.x()) {
+ if (monitor_bounds.width() != 0 && x < monitor_bounds.x()) {
*is_leading = !prefer_leading;
x = item_bounds.x() + menu_config.touchable_menu_width -
border_and_shadow_insets.left();
@@ -2319,15 +2350,12 @@ gfx::Rect MenuController::CalculateBubbleMenuBounds(MenuItemView* item,
}
y = item_bounds.y() - border_and_shadow_insets.top() -
menu_config.vertical_touchable_menu_item_padding;
- if (y + pref.height() - border_and_shadow_insets.bottom() >
- state_.monitor_bounds.bottom()) {
- y = state_.monitor_bounds.bottom() - pref.height() +
- border_and_shadow_insets.top();
- }
- if (y < state_.monitor_bounds.y())
- y = state_.monitor_bounds.y() - border_and_shadow_insets.top();
+ y = base::ClampToRange(y,
+ monitor_bounds.y() - border_and_shadow_insets.top(),
+ monitor_bounds.bottom() - menu_size.height() +
+ border_and_shadow_insets.top());
}
- return gfx::Rect(x, y, pref.width(), pref.height());
+ return gfx::Rect(x, y, menu_size.width(), menu_size.height());
}
// static
@@ -2522,7 +2550,7 @@ void MenuController::SelectByChar(base::char16 character) {
return;
}
- if (is_combobox_) {
+ if (is_combobox_ || MenuConfig::instance().all_menus_use_prefix_selection) {
item->GetSubmenu()->GetPrefixSelector()->InsertText(char_array);
} else {
// If no mnemonics found, look at first character of titles.
@@ -2860,6 +2888,13 @@ void MenuController::SetHotTrackedButton(Button* hot_button) {
}
}
+bool MenuController::ShouldContinuePrefixSelection() const {
+ MenuItemView* item = pending_state_.item;
+ if (!item->SubmenuIsShowing())
+ item = item->GetParentMenuItem();
+ return item->GetSubmenu()->GetPrefixSelector()->ShouldContinueSelection();
+}
+
bool MenuController::CanProcessInputEvents() const {
#if defined(OS_MACOSX)
return !menu_closure_animation_;
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 1fcfaa99d46..588612b1edc 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -28,6 +28,7 @@
#if defined(OS_MACOSX)
#include "ui/views/controls/menu/menu_closure_animation_mac.h"
+#include "ui/views/controls/menu/menu_cocoa_watcher_mac.h"
#endif
namespace ui {
@@ -38,15 +39,12 @@ namespace views {
class MenuButton;
class MenuHostRootView;
class MenuItemView;
+class MenuPreTargetHandler;
class MouseEvent;
class SubmenuView;
class View;
class ViewTracker;
-#if defined(USE_AURA)
-class MenuPreTargetHandler;
-#endif
-
namespace internal {
class MenuControllerDelegate;
class MenuRunnerImpl;
@@ -582,6 +580,12 @@ class VIEWS_EXPORT MenuController
// Updates the current |hot_button_| and its hot tracked state.
void SetHotTrackedButton(Button* hot_button);
+ // Returns whether typing a new character will continue the existing prefix
+ // selection. If this returns false, typing a new character will start a new
+ // prefix selection, and some characters (such as Space) will be treated as
+ // commands instead of parts of the prefix.
+ bool ShouldContinuePrefixSelection() const;
+
// The active instance.
static MenuController* active_instance_;
@@ -727,11 +731,10 @@ class VIEWS_EXPORT MenuController
#if defined(OS_MACOSX)
std::unique_ptr<MenuClosureAnimationMac> menu_closure_animation_;
+ std::unique_ptr<MenuCocoaWatcherMac> menu_cocoa_watcher_;
#endif
-#if defined(USE_AURA)
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 c8052ea2734..57c22228ae9 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -16,7 +16,6 @@
#include "ui/events/event_constants.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_utils.h"
-#include "ui/events/null_event_targeter.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
@@ -35,6 +34,7 @@
#if defined(USE_AURA)
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_client_observer.h"
+#include "ui/aura/null_window_targeter.h"
#include "ui/aura/scoped_window_targeter.h"
#include "ui/aura/window.h"
#include "ui/views/controls/menu/menu_pre_target_handler.h"
@@ -240,6 +240,27 @@ void DestructingTestViewsDelegate::ReleaseRef() {
release_ref_callback_.Run();
}
+// View which cancels the menu it belongs to on mouse press.
+class CancelMenuOnMousePressView : public View {
+ public:
+ explicit CancelMenuOnMousePressView(MenuController* controller)
+ : controller_(controller) {}
+
+ // View:
+ bool OnMousePressed(const ui::MouseEvent& event) override {
+ controller_->CancelAll();
+ return true;
+ }
+
+ // This is needed to prevent the view from being "squashed" to zero height
+ // when the menu which owns it is shown. In such state the logic which
+ // determines if the menu contains the mouse press location doesn't work.
+ gfx::Size CalculatePreferredSize() const override { return size(); }
+
+ private:
+ MenuController* controller_;
+};
+
} // namespace
class TestMenuItemViewShown : public MenuItemView {
@@ -257,6 +278,9 @@ class TestMenuItemViewShown : public MenuItemView {
void SetActualMenuPosition(MenuItemView::MenuPosition position) {
set_actual_menu_position(position);
}
+ MenuItemView::MenuPosition ActualMenuPosition() {
+ return actual_menu_position();
+ }
private:
DISALLOW_COPY_AND_ASSIGN(TestMenuItemViewShown);
@@ -627,11 +651,11 @@ class MenuControllerTest : public ViewsTestBase {
// event dispatcher.
TEST_F(MenuControllerTest, EventTargeter) {
{
- // With the |ui::NullEventTargeter| instantiated and assigned we expect
+ // With the aura::NullWindowTargeter instantiated and assigned we expect
// the menu to not handle the key event.
aura::ScopedWindowTargeter scoped_targeter(
owner()->GetNativeWindow()->GetRootWindow(),
- std::unique_ptr<ui::EventTargeter>(new ui::NullEventTargeter));
+ std::make_unique<aura::NullWindowTargeter>());
PressKey(ui::VKEY_ESCAPE);
EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
}
@@ -1068,8 +1092,7 @@ TEST_F(MenuControllerTest, AsynchronousPerformDrop) {
SetDropMenuItem(target, MenuDelegate::DropPosition::DROP_AFTER);
ui::OSExchangeData drop_data;
- gfx::Rect bounds(target->bounds());
- gfx::Point location(bounds.x(), bounds.y());
+ gfx::PointF location(target->origin());
ui::DropTargetEvent target_event(drop_data, location, location,
ui::DragDropTypes::DRAG_MOVE);
controller->OnPerformDrop(source, target_event);
@@ -1168,6 +1191,8 @@ TEST_F(MenuControllerTest, DoubleAsynchronousNested) {
EXPECT_EQ(1, nested_delegate->on_menu_closed_called());
}
+// Tests that setting send_gesture_events_to_owner flag forwards gesture events
+// to owner and the forwarding stops when the current gesture sequence ends.
TEST_F(MenuControllerTest, PreserveGestureForOwner) {
MenuController* controller = menu_controller();
MenuItemView* item = menu_item();
@@ -1204,6 +1229,40 @@ TEST_F(MenuControllerTest, PreserveGestureForOwner) {
EXPECT_EQ(CountOwnerOnGestureEvent(), 2);
}
+// Tests that touch outside menu does not closes the menu when forwarding
+// gesture events to owner.
+TEST_F(MenuControllerTest, NoTouchCloseWhenSendingGesturesToOwner) {
+ MenuController* controller = menu_controller();
+
+ // Owner wants the gesture events.
+ controller->set_send_gesture_events_to_owner(true);
+
+ // Show a sub menu and touch outside of it.
+ MenuItemView* item = menu_item();
+ SubmenuView* sub_menu = item->GetSubmenu();
+ sub_menu->ShowAt(owner(), item->bounds(), false);
+ gfx::Point location(sub_menu->bounds().bottom_right());
+ location.Offset(1, 1);
+ ui::TouchEvent touch_event(
+ ui::ET_TOUCH_PRESSED, location, ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+ controller->OnTouchEvent(sub_menu, &touch_event);
+
+ // Menu should still be visible.
+ EXPECT_TRUE(IsShowing());
+
+ // The current gesture sequence ends.
+ ui::GestureEvent gesture_end_event(
+ location.x(), location.y(), 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_END));
+ controller->OnGestureEvent(sub_menu, &gesture_end_event);
+
+ // Touch outside again and menu should be closed.
+ controller->OnTouchEvent(sub_menu, &touch_event);
+ EXPECT_FALSE(IsShowing());
+ EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
+}
+
// Tests that a nested menu does not crash when trying to repost events that
// occur outside of the bounds of the menu. Instead a proper shutdown should
// occur.
@@ -1548,6 +1607,37 @@ TEST_F(MenuControllerTest, CalculateMenuBoundsMonitorFitTest) {
EXPECT_EQ(expected, CalculateMenuBounds(options));
}
+// Test that a menu that was originally drawn below the anchor does not get
+// squished or move above the anchor when it grows vertically and horizontally
+// beyond the monitor bounds.
+TEST_F(MenuControllerTest, GrowingMenuMovesLaterallyNotVertically) {
+ MenuBoundsOptions options;
+ options.monitor_bounds = gfx::Rect(0, 0, 100, 100);
+ // The anchor should be near the bottom right side of the screen.
+ options.anchor_bounds = gfx::Rect(80, 70, 15, 10);
+ // The menu should fit the available space, below the anchor.
+ options.menu_size = gfx::Size(20, 20);
+
+ // Ensure the menu is initially drawn below the bounds, and the MenuPosition
+ // is set to POSITION_BELOW_BOUNDS;
+ const gfx::Rect first_drawn_expected(80, 80, 20, 20);
+ EXPECT_EQ(first_drawn_expected, CalculateMenuBounds(options));
+ EXPECT_EQ(MenuItemView::MenuPosition::POSITION_BELOW_BOUNDS,
+ menu_item()->ActualMenuPosition());
+
+ options.menu_position = MenuItemView::MenuPosition::POSITION_BELOW_BOUNDS;
+
+ // The menu bounds are larger than the remaining space on the monitor. This
+ // simulates the case where the menu has been grown vertically and
+ // horizontally to where it would no longer fit on the screen.
+ options.menu_size = gfx::Size(50, 50);
+
+ // The menu bounds should move left to show the wider menu, and grow to fill
+ // the remaining vertical space without moving upwards.
+ const gfx::Rect final_expected(50, 80, 50, 20);
+ EXPECT_EQ(final_expected, CalculateMenuBounds(options));
+}
+
#if defined(USE_AURA)
// This tests that mouse moved events from the initial position of the mouse
// when the menu was shown don't select the menu item at the mouse position.
@@ -1814,5 +1904,35 @@ TEST_F(MenuControllerTest, DragFromViewIntoMenuAndExit) {
#endif // defined(USE_AURA)
+// Tests that having the MenuController deleted during OnMousePressed does not
+// cause a crash. ASAN bots should not detect use-after-free in MenuController.
+TEST_F(MenuControllerTest, NoUseAfterFreeWhenMenuCanceledOnMousePress) {
+ MenuController* controller = menu_controller();
+ DestroyMenuControllerOnMenuClosed(menu_controller_delegate());
+
+ // Creating own MenuItem for a minimal test environment.
+ auto item = std::make_unique<TestMenuItemViewNotShown>(menu_delegate());
+ item->SetController(controller);
+ item->SetBounds(0, 0, 50, 50);
+
+ SubmenuView* sub_menu = item->CreateSubmenu();
+ auto* canceling_view = new CancelMenuOnMousePressView(controller);
+ sub_menu->AddChildView(canceling_view);
+ canceling_view->SetBoundsRect(item->bounds());
+
+ controller->Run(owner(), nullptr, item.get(), item->bounds(),
+ MENU_ANCHOR_TOPLEFT, false, false);
+ sub_menu->ShowAt(owner(), item->bounds(), true);
+
+ // Simulate a mouse press in the middle of the |closing_widget|.
+ gfx::Point location(canceling_view->bounds().CenterPoint());
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location,
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0);
+ EXPECT_TRUE(controller->OnMousePressed(sub_menu, event));
+
+ // Close to remove observers before test TearDown.
+ sub_menu->Close();
+}
+
} // 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 14660727afd..56c3c51ca94 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -19,13 +19,7 @@ base::string16 MenuDelegate::GetLabel(int id) const {
return base::string16();
}
-const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const {
- return NULL;
-}
-
-bool MenuDelegate::GetShouldUseNormalForegroundColor(int command_id) const {
- return false;
-}
+void MenuDelegate::GetLabelStyle(int id, LabelStyle* style) const {}
base::string16 MenuDelegate::GetTooltipText(int id,
const gfx::Point& screen_loc) const {
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index 4dea63f9f28..706605182f9 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -10,9 +10,11 @@
#include "base/logging.h"
#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/ui_base_types.h"
+#include "ui/gfx/font_list.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/menu_types.h"
#include "ui/views/views_export.h"
@@ -59,6 +61,12 @@ class VIEWS_EXPORT MenuDelegate {
DROP_ON
};
+ // Used when indicating the style for a given label.
+ struct LabelStyle {
+ gfx::FontList font_list;
+ SkColor foreground;
+ };
+
virtual ~MenuDelegate();
// Whether or not an item should be shown as checked. This is invoked for
@@ -69,12 +77,9 @@ class VIEWS_EXPORT MenuDelegate {
// added with an empty label.
virtual base::string16 GetLabel(int id) const;
- // The font for the menu item label.
- virtual const gfx::FontList* GetLabelFontList(int 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;
+ // The style for the label with the given |id|. Implementations may update any
+ // parts of |style| or leave it unmodified.
+ virtual void GetLabelStyle(int id, LabelStyle* style) const;
// The tooltip shown for the menu item. This is invoked when the user
// hovers over the item, and no tooltip text has been set for that item.
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index f14a1c06685..104ae4c6da5 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -84,7 +84,7 @@ void TransferGesture(Widget* source, Widget* target) {
#if defined(OS_MACOSX)
NOTIMPLEMENTED();
#else // !defined(OS_MACOSX)
- ui::GestureRecognizer::Get()->TransferEventsTo(
+ source->GetGestureRecognizer()->TransferEventsTo(
source->GetNativeView(), target->GetNativeView(),
ui::GestureRecognizer::ShouldCancelTouches::DontCancel);
#endif // defined(OS_MACOSX)
@@ -126,6 +126,11 @@ void MenuHost::InitMenuHost(Widget* parent,
Widget::InitParams::OPAQUE_WINDOW;
params.parent = parent ? parent->GetNativeView() : NULL;
params.bounds = bounds;
+ // If MenuHost has no parent widget, it needs to be marked
+ // Activatable, so that calling Show in ShowMenuHost will
+ // get keyboard focus.
+ if (parent == nullptr)
+ params.activatable = Widget::InitParams::ACTIVATABLE_YES;
#if defined(OS_WIN)
// On Windows use the software compositor to ensure that we don't block
// the UI thread blocking issue during command buffer creation. We can
@@ -166,13 +171,17 @@ void MenuHost::ShowMenuHost(bool do_capture) {
// gesture events instead of being dropped.
internal::TransferGesture(owner_, this);
} else {
- ui::GestureRecognizer::Get()->CancelActiveTouchesExcept(nullptr);
+ GetGestureRecognizer()->CancelActiveTouchesExcept(nullptr);
}
#if defined(MACOSX)
// Cancel existing touches, so we don't miss some touch release/cancel
// events due to the menu taking capture.
- ui::GestureRecognizer::Get()->CancelActiveTouchesExcept(nullptr);
+ GetGestureRecognizer()->CancelActiveTouchesExcept(nullptr);
#endif // defined (OS_MACOSX)
+ // If MenuHost has no parent widget, it needs to call Show to get focus,
+ // so that it will get keyboard events.
+ if (owner_ == nullptr)
+ Show();
native_widget_private()->SetCapture();
}
}
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 4ede4cb5fa0..6c007a1030c 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -849,17 +849,20 @@ int MenuItemView::GetDrawStringFlags() {
return flags;
}
-const gfx::FontList& MenuItemView::GetFontList() const {
- const MenuDelegate* delegate = GetDelegate();
- if (delegate) {
- const gfx::FontList* font_list = delegate->GetLabelFontList(GetCommand());
- if (font_list)
- return *font_list;
+void MenuItemView::GetLabelStyle(MenuDelegate::LabelStyle* style) const {
+ // Start with the default font:
+ style->font_list = MenuConfig::instance().font_list;
+
+ // Replace it with the touchable font in touchable menus:
+ if (GetMenuController() && GetMenuController()->use_touchable_layout()) {
+ style->font_list =
+ style::GetFont(style::CONTEXT_TOUCH_MENU, style::STYLE_PRIMARY);
}
- if (GetMenuController() && GetMenuController()->use_touchable_layout())
- return style::GetFont(style::CONTEXT_TOUCH_MENU, style::STYLE_PRIMARY);
- return MenuConfig::instance().font_list;
+ // Then let the delegate replace any part of |style|.
+ const MenuDelegate* delegate = GetDelegate();
+ if (delegate)
+ delegate->GetLabelStyle(GetCommand(), style);
}
void MenuItemView::AddEmptyMenus() {
@@ -908,8 +911,6 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
render_selection = *forced_visual_selection_;
MenuDelegate *delegate = GetDelegate();
- bool emphasized =
- delegate && delegate->GetShouldUseNormalForegroundColor(GetCommand());
// Render the background. As MenuScrollViewContainer draws the background, we
// only need the background when we want it to look different, as when we're
// selected.
@@ -939,8 +940,11 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
const int available_height = height() - top_margin - bottom_margin;
// Calculate some colors.
- SkColor fg_color = GetTextColor(false, render_selection, emphasized);
- SkColor icon_color = color_utils::DeriveDefaultIconColor(fg_color);
+ MenuDelegate::LabelStyle style;
+ style.foreground = GetTextColor(false, render_selection);
+ GetLabelStyle(&style);
+
+ SkColor icon_color = color_utils::DeriveDefaultIconColor(style.foreground);
if (GetMenuController() && GetMenuController()->use_touchable_layout())
icon_color = config.touchable_icon_color;
@@ -953,7 +957,6 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
}
// Render the foreground.
- const gfx::FontList& font_list = GetFontList();
int accel_width = parent_menu_item_->GetSubmenu()->max_minor_text_width();
int label_start = GetLabelStartForThisItem();
@@ -968,25 +971,26 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
int flags = GetDrawStringFlags();
if (mode == PB_FOR_DRAG)
flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING;
- canvas->DrawStringRectWithFlags(title(), font_list, fg_color, text_bounds,
- flags);
+ canvas->DrawStringRectWithFlags(title(), style.font_list, style.foreground,
+ text_bounds, flags);
if (!subtitle_.empty()) {
canvas->DrawStringRectWithFlags(
- subtitle_, font_list,
+ subtitle_, style.font_list,
GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_MenuItemMinorTextColor),
- text_bounds + gfx::Vector2d(0, font_list.GetHeight()), flags);
+ text_bounds + gfx::Vector2d(0, style.font_list.GetHeight()), flags);
}
- PaintMinorIconAndText(canvas,
- GetTextColor(true, render_selection, emphasized));
+ PaintMinorIconAndText(canvas, style);
// Set the submenu indicator (arrow) image and color.
if (HasSubmenu())
submenu_arrow_image_view_->SetImage(GetSubmenuArrowImage(icon_color));
}
-void MenuItemView::PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color) {
+void MenuItemView::PaintMinorIconAndText(
+ gfx::Canvas* canvas,
+ const MenuDelegate::LabelStyle& style) {
base::string16 minor_text = GetMinorText();
const gfx::VectorIcon* minor_icon = GetMinorIcon();
if (minor_text.empty() && !minor_icon)
@@ -1007,8 +1011,8 @@ void MenuItemView::PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color) {
auto render_text = gfx::RenderText::CreateHarfBuzzInstance();
if (!minor_text.empty()) {
render_text->SetText(minor_text);
- render_text->SetFontList(GetFontList());
- render_text->SetColor(color);
+ render_text->SetFontList(style.font_list);
+ render_text->SetColor(style.foreground);
render_text->SetDisplayRect(minor_text_bounds);
render_text->SetHorizontalAlignment(base::i18n::IsRTL() ? gfx::ALIGN_LEFT
: gfx::ALIGN_RIGHT);
@@ -1016,7 +1020,7 @@ void MenuItemView::PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color) {
}
if (minor_icon) {
- gfx::ImageSkia image = CreateVectorIcon(*minor_icon, color);
+ gfx::ImageSkia image = CreateVectorIcon(*minor_icon, style.foreground);
int image_x = GetMirroredRect(minor_text_bounds).right() -
render_text->GetContentWidth() -
@@ -1030,9 +1034,7 @@ void MenuItemView::PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color) {
}
}
-SkColor MenuItemView::GetTextColor(bool minor,
- bool render_selection,
- bool emphasized) const {
+SkColor MenuItemView::GetTextColor(bool minor, bool render_selection) const {
ui::NativeTheme::ColorId color_id =
minor ? ui::NativeTheme::kColorId_MenuItemMinorTextColor
: ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor;
@@ -1040,8 +1042,7 @@ SkColor MenuItemView::GetTextColor(bool minor,
if (render_selection)
color_id = ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor;
} else {
- if (!emphasized)
- color_id = ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
+ color_id = ui::NativeTheme::kColorId_DisabledMenuItemForegroundColor;
}
if (GetMenuController() && GetMenuController()->use_touchable_layout())
@@ -1138,7 +1139,8 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
return dimensions;
}
- const gfx::FontList& font_list = GetFontList();
+ MenuDelegate::LabelStyle style;
+ GetLabelStyle(&style);
base::string16 minor_text = GetMinorText();
dimensions.height = child_size.height();
@@ -1170,23 +1172,23 @@ MenuItemView::MenuItemDimensions MenuItemView::CalculateDimensions() const {
int label_start = GetLabelStartForThisItem();
// Determine the length of the label text.
- int string_width = gfx::GetStringWidth(title_, font_list);
+ int string_width = gfx::GetStringWidth(title_, style.font_list);
if (!subtitle_.empty()) {
- string_width = std::max(string_width,
- gfx::GetStringWidth(subtitle_, font_list));
+ string_width =
+ std::max(string_width, gfx::GetStringWidth(subtitle_, style.font_list));
}
dimensions.standard_width = string_width + label_start +
item_right_margin_;
// Determine the length of the right-side text.
dimensions.minor_text_width =
- minor_text.empty() ? 0 : gfx::GetStringWidth(minor_text, font_list);
+ minor_text.empty() ? 0 : gfx::GetStringWidth(minor_text, style.font_list);
// Determine the height to use.
- dimensions.height =
- std::max(dimensions.height,
- (subtitle_.empty() ? 0 : font_list.GetHeight()) +
- font_list.GetHeight() + GetBottomMargin() + GetTopMargin());
+ dimensions.height = std::max(
+ dimensions.height, (subtitle_.empty() ? 0 : style.font_list.GetHeight()) +
+ style.font_list.GetHeight() + GetBottomMargin() +
+ GetTopMargin());
dimensions.height =
std::max(dimensions.height, MenuConfig::instance().item_min_height);
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index 929f3f87204..160a0069256 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -28,7 +28,6 @@
#endif
namespace gfx {
-class FontList;
struct VectorIcon;
}
@@ -406,8 +405,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns the flags passed to DrawStringRect.
int GetDrawStringFlags();
- // Returns the font list to use for menu text.
- const gfx::FontList& GetFontList() const;
+ // Returns the style for the menu text.
+ void GetLabelStyle(MenuDelegate::LabelStyle* style) const;
// If this menu item has no children a child is added showing it has no
// children. Otherwise AddEmtpyMenus is recursively invoked on child menu
@@ -426,7 +425,8 @@ class VIEWS_EXPORT MenuItemView : public View {
void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
// Paints the right-side icon and text.
- void PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color);
+ void PaintMinorIconAndText(gfx::Canvas* canvas,
+ const MenuDelegate::LabelStyle& style);
// Destroys the window used to display this menu and recursively destroys
// the windows used to display all descendants.
@@ -441,9 +441,7 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns the text color for the current state. |minor| specifies if the
// minor text or the normal text is desired.
- SkColor GetTextColor(bool minor,
- bool render_selection,
- bool emphasized) const;
+ SkColor GetTextColor(bool minor, bool render_selection) const;
// Calculates and returns the MenuItemDimensions.
MenuItemDimensions CalculateDimensions() const;
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index e9cfe1c466c..cbccee16e4c 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -172,17 +172,19 @@ base::string16 MenuModelAdapter::GetLabel(int id) const {
return base::string16();
}
-const gfx::FontList* MenuModelAdapter::GetLabelFontList(int id) const {
+void MenuModelAdapter::GetLabelStyle(int id, LabelStyle* style) const {
ui::MenuModel* model = menu_model_;
int index = 0;
if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) {
const gfx::FontList* font_list = model->GetLabelFontListAt(index);
- if (font_list)
- return font_list;
+ if (font_list) {
+ style->font_list = *font_list;
+ return;
+ }
}
// This line may be reached for the empty menu item.
- return MenuDelegate::GetLabelFontList(id);
+ return MenuDelegate::GetLabelStyle(id, style);
}
bool MenuModelAdapter::IsCommandEnabled(int id) const {
@@ -269,6 +271,10 @@ void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) {
const int item_count = model->GetItemCount();
for (int i = 0; i < item_count; ++i) {
MenuItemView* item = AppendMenuItem(menu, model, i);
+ if (item) {
+ item->SetEnabled(model->IsEnabledAt(i));
+ item->SetVisible(model->IsVisibleAt(i));
+ }
if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU ||
model->GetTypeAt(i) == ui::MenuModel::TYPE_ACTIONABLE_SUBMENU) {
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.h b/chromium/ui/views/controls/menu/menu_model_adapter.h
index 0ac493c3c6a..e52edfe5edd 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.h
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.h
@@ -71,7 +71,7 @@ class VIEWS_EXPORT MenuModelAdapter : public MenuDelegate {
bool IsTriggerableEvent(MenuItemView* source, const ui::Event& e) override;
bool GetAccelerator(int id, ui::Accelerator* accelerator) const override;
base::string16 GetLabel(int id) const override;
- const gfx::FontList* GetLabelFontList(int id) const override;
+ void GetLabelStyle(int id, LabelStyle* style) const override;
bool IsCommandEnabled(int id) const override;
bool IsCommandVisible(int id) const override;
bool IsItemChecked(int id) const override;
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 df3bb3ef251..00da8e3ebcc 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -4,6 +4,10 @@
#include "ui/views/controls/menu/menu_model_adapter.h"
+#include <memory>
+#include <string>
+#include <vector>
+
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/models/menu_model.h"
@@ -70,9 +74,9 @@ class MenuModelBase : public ui::MenuModel {
return NULL;
}
- bool IsEnabledAt(int index) const override { return true; }
+ bool IsEnabledAt(int index) const override { return items_[index].enabled; }
- bool IsVisibleAt(int index) const override { return true; }
+ bool IsVisibleAt(int index) const override { return items_[index].visible; }
MenuModel* GetSubmenuModelAt(int index) const override {
return items_[index].submenu;
@@ -99,12 +103,26 @@ class MenuModelBase : public ui::MenuModel {
ui::MenuModel* item_submenu)
: type(item_type),
label(base::ASCIIToUTF16(item_label)),
- submenu(item_submenu) {
- }
+ submenu(item_submenu),
+ enabled(true),
+ visible(true) {}
+
+ Item(ItemType item_type,
+ const std::string& item_label,
+ ui::MenuModel* item_submenu,
+ bool enabled,
+ bool visible)
+ : type(item_type),
+ label(base::ASCIIToUTF16(item_label)),
+ submenu(item_submenu),
+ enabled(enabled),
+ visible(visible) {}
ItemType type;
base::string16 label;
ui::MenuModel* submenu;
+ bool enabled;
+ bool visible;
};
const Item& GetItemDefinition(int index) {
@@ -130,7 +148,7 @@ class MenuModelBase : public ui::MenuModel {
class SubmenuModel : public MenuModelBase {
public:
SubmenuModel() : MenuModelBase(kSubmenuIdBase) {
- items_.push_back(Item(TYPE_COMMAND, "submenu item 0", NULL));
+ items_.push_back(Item(TYPE_COMMAND, "submenu item 0", NULL, false, true));
items_.push_back(Item(TYPE_COMMAND, "submenu item 1", NULL));
}
@@ -158,7 +176,7 @@ class RootModel : public MenuModelBase {
submenu_model_ = std::make_unique<SubmenuModel>();
actionable_submenu_model_ = std::make_unique<ActionableSubmenuModel>();
- items_.push_back(Item(TYPE_COMMAND, "command 0", NULL));
+ items_.push_back(Item(TYPE_COMMAND, "command 0", NULL, false, false));
items_.push_back(Item(TYPE_CHECK, "check 1", NULL));
items_.push_back(Item(TYPE_SEPARATOR, "", NULL));
items_.push_back(Item(TYPE_SUBMENU, "submenu 3", submenu_model_.get()));
@@ -225,6 +243,12 @@ void CheckSubmenu(const RootModel& model,
break;
}
+ // Check enabled state.
+ EXPECT_EQ(model_item.enabled, item->enabled());
+
+ // Check visibility.
+ EXPECT_EQ(model_item.visible, item->visible());
+
// Check activation.
static_cast<views::MenuDelegate*>(delegate)->ExecuteCommand(id);
EXPECT_EQ(i, submodel->last_activation());
@@ -290,6 +314,12 @@ TEST_F(MenuModelAdapterTest, BasicTest) {
break;
}
+ // Check enabled state.
+ EXPECT_EQ(model_item.enabled, item->enabled());
+
+ // Check visibility.
+ EXPECT_EQ(model_item.visible, item->visible());
+
// Check activation.
static_cast<views::MenuDelegate*>(&delegate)->ExecuteCommand(id);
EXPECT_EQ(i, model.last_activation());
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler.h b/chromium/ui/views/controls/menu/menu_pre_target_handler.h
index 4ff27ddcea8..8a02e960543 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler.h
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler.h
@@ -1,56 +1,39 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2018 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_
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_H_
+#define UI_VIEWS_CONTROLS_MENU_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"
+#include <memory>
-namespace aura {
-class Window;
-} // namespace aura
+#include "base/macros.h"
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 wm::ActivationChangeObserver,
- public aura::WindowObserver,
- public ui::EventHandler {
+// A MenuPreTargetHandler is responsible for intercepting events destined for
+// another widget (the menu's owning widget) and letting the menu's controller
+// try dispatching them first.
+class MenuPreTargetHandler {
public:
- MenuPreTargetHandler(MenuController* controller, Widget* owner);
- ~MenuPreTargetHandler() override;
+ virtual ~MenuPreTargetHandler() = default;
- // aura::client:ActivationChangeObserver:
- void OnWindowActivated(wm::ActivationChangeObserver::ActivationReason reason,
- aura::Window* gained_active,
- aura::Window* lost_active) override;
+ // There are separate implementations of this method for Aura platforms and
+ // for Mac.
+ static std::unique_ptr<MenuPreTargetHandler> Create(
+ MenuController* controller,
+ Widget* owner);
- // aura::WindowObserver:
- void OnWindowDestroying(aura::Window* window) override;
-
- // ui::EventHandler:
- void OnCancelMode(ui::CancelModeEvent* event) override;
- void OnKeyEvent(ui::KeyEvent* event) override;
+ protected:
+ MenuPreTargetHandler() = default;
private:
- void Cleanup();
-
- MenuController* controller_;
- aura::Window* root_;
-
DISALLOW_COPY_AND_ASSIGN(MenuPreTargetHandler);
};
} // namespace views
-#endif // UI_VIEWS_CONTROLS_MENU_PRE_TARGET_HANDLER_H_
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_H_
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler.cc b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc
index 9f9dd9448a4..45b071661bb 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler.cc
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/views/controls/menu/menu_pre_target_handler.h"
+#include "ui/views/controls/menu/menu_pre_target_handler_aura.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
@@ -20,10 +20,10 @@ aura::Window* GetOwnerRootWindow(views::Widget* owner) {
} // namespace
-MenuPreTargetHandler::MenuPreTargetHandler(MenuController* controller,
- Widget* owner)
+MenuPreTargetHandlerAura::MenuPreTargetHandlerAura(MenuController* controller,
+ Widget* owner)
: controller_(controller), root_(GetOwnerRootWindow(owner)) {
- aura::Env::GetInstanceDontCreate()->AddPreTargetHandler(
+ aura::Env::GetInstance()->AddPreTargetHandler(
this, ui::EventTarget::Priority::kSystem);
if (root_) {
wm::GetActivationClient(root_)->AddObserver(this);
@@ -31,12 +31,12 @@ MenuPreTargetHandler::MenuPreTargetHandler(MenuController* controller,
}
}
-MenuPreTargetHandler::~MenuPreTargetHandler() {
- aura::Env::GetInstanceDontCreate()->RemovePreTargetHandler(this);
+MenuPreTargetHandlerAura::~MenuPreTargetHandlerAura() {
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
Cleanup();
}
-void MenuPreTargetHandler::OnWindowActivated(
+void MenuPreTargetHandlerAura::OnWindowActivated(
wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) {
@@ -44,19 +44,19 @@ void MenuPreTargetHandler::OnWindowActivated(
controller_->CancelAll();
}
-void MenuPreTargetHandler::OnWindowDestroying(aura::Window* window) {
+void MenuPreTargetHandlerAura::OnWindowDestroying(aura::Window* window) {
Cleanup();
}
-void MenuPreTargetHandler::OnCancelMode(ui::CancelModeEvent* event) {
+void MenuPreTargetHandlerAura::OnCancelMode(ui::CancelModeEvent* event) {
controller_->CancelAll();
}
-void MenuPreTargetHandler::OnKeyEvent(ui::KeyEvent* event) {
+void MenuPreTargetHandlerAura::OnKeyEvent(ui::KeyEvent* event) {
controller_->OnWillDispatchKeyEvent(event);
}
-void MenuPreTargetHandler::Cleanup() {
+void MenuPreTargetHandlerAura::Cleanup() {
if (!root_)
return;
// The ActivationClient may have been destroyed by the time we get here.
@@ -67,4 +67,11 @@ void MenuPreTargetHandler::Cleanup() {
root_ = nullptr;
}
+// static
+std::unique_ptr<MenuPreTargetHandler> MenuPreTargetHandler::Create(
+ MenuController* controller,
+ Widget* owner) {
+ return std::make_unique<MenuPreTargetHandlerAura>(controller, owner);
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h
new file mode 100644
index 00000000000..13fc79cbde2
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.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_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_AURA_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_AURA_H_
+
+#include "ui/aura/window_observer.h"
+#include "ui/events/event_handler.h"
+#include "ui/views/controls/menu/menu_pre_target_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;
+
+// MenuPreTargetHandlerAura 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 MenuPreTargetHandlerAura
+ : public wm::ActivationChangeObserver,
+ public aura::WindowObserver,
+ public ui::EventHandler,
+ public MenuPreTargetHandler {
+ public:
+ MenuPreTargetHandlerAura(MenuController* controller, Widget* owner);
+ ~MenuPreTargetHandlerAura() override;
+
+ // aura::client:ActivationChangeObserver:
+ void OnWindowActivated(wm::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(MenuPreTargetHandlerAura);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_AURA_H_
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h
new file mode 100644
index 00000000000..d2250979d3d
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h
@@ -0,0 +1,32 @@
+// Copyright 2018 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_PRE_TARGET_HANDLER_MAC_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_MAC_H_
+
+#include "ui/events/event_handler.h"
+#include "ui/views/controls/menu/menu_pre_target_handler.h"
+#include "ui/views/event_monitor_mac.h"
+
+namespace views {
+
+class MenuPreTargetHandlerMac : public MenuPreTargetHandler,
+ public ui::EventHandler {
+ public:
+ MenuPreTargetHandlerMac(MenuController* controller, Widget* widget);
+ ~MenuPreTargetHandlerMac() override;
+
+ // ui::EventHandler:
+ void OnKeyEvent(ui::KeyEvent* event) override;
+
+ private:
+ MenuController* controller_; // Weak. Owns |this|.
+ std::unique_ptr<EventMonitorMac> event_monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(MenuPreTargetHandlerMac);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_MAC_H_
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm
new file mode 100644
index 00000000000..81ce0dafa79
--- /dev/null
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm
@@ -0,0 +1,34 @@
+// Copyright 2018 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_mac.h"
+
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+MenuPreTargetHandlerMac::MenuPreTargetHandlerMac(MenuController* controller,
+ Widget* widget)
+ : controller_(controller),
+ event_monitor_(
+ std::make_unique<EventMonitorMac>(this, widget->GetNativeWindow())) {}
+
+MenuPreTargetHandlerMac::~MenuPreTargetHandlerMac() {}
+
+void MenuPreTargetHandlerMac::OnKeyEvent(ui::KeyEvent* event) {
+ if (controller_->OnWillDispatchKeyEvent(event) !=
+ ui::POST_DISPATCH_PERFORM_DEFAULT) {
+ event->SetHandled();
+ }
+}
+
+// static
+std::unique_ptr<MenuPreTargetHandler> MenuPreTargetHandler::Create(
+ MenuController* controller,
+ Widget* widget) {
+ return std::make_unique<MenuPreTargetHandlerMac>(controller, widget);
+}
+
+} // namespace views
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 ae0c8bafd05..2cc6a8c1a7c 100644
--- a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -45,7 +45,7 @@ class TestModel : public ui::SimpleMenuModel {
bool IsCommandIdEnabled(int command_id) const override { return true; }
void ExecuteCommand(int command_id, int event_flags) override {}
- void MenuWillShow(SimpleMenuModel* source) override {
+ void OnMenuWillShow(SimpleMenuModel* source) override {
if (!model_->menu_open_callback_.is_null())
std::move(model_->menu_open_callback_).Run();
}
diff --git a/chromium/ui/views/controls/menu/menu_runner_unittest.cc b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
index 704f242106d..bb3961c9af0 100644
--- a/chromium/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
@@ -10,8 +10,10 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_tick_clock.h"
#include "build/build_config.h"
#include "ui/base/ui_base_types.h"
+#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_delegate.h"
@@ -80,6 +82,11 @@ class MenuRunnerTest : public ViewsTestBase {
// ViewsTestBase:
void TearDown() override;
+ bool IsItemSelected(int command_id) {
+ MenuItemView* item = menu_item_view()->GetMenuItemByID(command_id);
+ return item ? item->IsSelected() : false;
+ }
+
private:
// Owned by menu_runner_.
MenuItemView* menu_item_view_ = nullptr;
@@ -167,6 +174,11 @@ TEST_F(MenuRunnerTest, LatinMnemonic) {
if (IsMus())
return;
+ // Menus that use prefix selection don't support mnemonics - the input is
+ // always part of the prefix.
+ if (MenuConfig::instance().all_menus_use_prefix_selection)
+ return;
+
views::test::DisableMenuClosureAnimations();
InitMenuRunner(0);
MenuRunner* runner = menu_runner();
@@ -193,6 +205,11 @@ TEST_F(MenuRunnerTest, NonLatinMnemonic) {
if (IsMus())
return;
+ // Menus that use prefix selection don't support mnemonics - the input is
+ // always part of the prefix.
+ if (MenuConfig::instance().all_menus_use_prefix_selection)
+ return;
+
views::test::DisableMenuClosureAnimations();
InitMenuRunner(0);
MenuRunner* runner = menu_runner();
@@ -201,7 +218,7 @@ TEST_F(MenuRunnerTest, NonLatinMnemonic) {
EXPECT_TRUE(runner->IsRunning());
ui::test::EventGenerator generator(GetContext(), owner()->GetNativeWindow());
- ui::KeyEvent key_press(0x062f, ui::VKEY_N, 0);
+ ui::KeyEvent key_press(0x062f, ui::VKEY_N, ui::DomCode::NONE, 0);
generator.Dispatch(&key_press);
views::test::WaitForMenuClosureAnimation();
EXPECT_FALSE(runner->IsRunning());
@@ -212,6 +229,85 @@ TEST_F(MenuRunnerTest, NonLatinMnemonic) {
}
#endif // !defined(OS_WIN)
+TEST_F(MenuRunnerTest, PrefixSelect) {
+ if (!MenuConfig::instance().all_menus_use_prefix_selection)
+ return;
+
+ base::SimpleTestTickClock clock;
+
+ // This test has a menu with three items:
+ // { 1, "One" }
+ // { 2, "\x062f\x0648" }
+ // { 3, "One Two" }
+ // It progressively prefix searches for "One " (note the space) and ensures
+ // that the right item is found.
+
+ views::test::DisableMenuClosureAnimations();
+ InitMenuRunner(0);
+ menu_item_view()->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("One Two"));
+
+ MenuRunner* runner = menu_runner();
+ runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+ ui::MENU_SOURCE_NONE);
+ EXPECT_TRUE(runner->IsRunning());
+
+ menu_item_view()
+ ->GetSubmenu()
+ ->GetPrefixSelector()
+ ->set_tick_clock_for_testing(&clock);
+
+ ui::test::EventGenerator generator(GetContext(), owner()->GetNativeWindow());
+ generator.PressKey(ui::VKEY_O, 0);
+ EXPECT_TRUE(IsItemSelected(1));
+ generator.PressKey(ui::VKEY_N, 0);
+ generator.PressKey(ui::VKEY_E, 0);
+ EXPECT_TRUE(IsItemSelected(1));
+
+ generator.PressKey(ui::VKEY_SPACE, 0);
+ EXPECT_TRUE(IsItemSelected(3));
+
+ // Wait out the PrefixSelector's timeout.
+ clock.Advance(base::TimeDelta::FromSeconds(10));
+
+ // Send Space to activate the selected menu item.
+ generator.PressKey(ui::VKEY_SPACE, 0);
+ views::test::WaitForMenuClosureAnimation();
+ EXPECT_FALSE(runner->IsRunning());
+ TestMenuDelegate* delegate = menu_delegate();
+ EXPECT_EQ(3, delegate->execute_command_id());
+ EXPECT_EQ(1, delegate->on_menu_closed_called());
+ EXPECT_NE(nullptr, delegate->on_menu_closed_menu());
+}
+
+// This test is Mac-specific: Mac is the only platform where VKEY_SPACE
+// activates menu items.
+#if defined(OS_MACOSX)
+TEST_F(MenuRunnerTest, SpaceActivatesItem) {
+ if (!MenuConfig::instance().all_menus_use_prefix_selection)
+ return;
+
+ views::test::DisableMenuClosureAnimations();
+ InitMenuRunner(0);
+
+ MenuRunner* runner = menu_runner();
+ runner->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+ ui::MENU_SOURCE_NONE);
+ EXPECT_TRUE(runner->IsRunning());
+
+ ui::test::EventGenerator generator(GetContext(), owner()->GetNativeWindow());
+ generator.PressKey(ui::VKEY_DOWN, 0);
+ EXPECT_TRUE(IsItemSelected(1));
+ generator.PressKey(ui::VKEY_SPACE, 0);
+ views::test::WaitForMenuClosureAnimation();
+
+ EXPECT_FALSE(runner->IsRunning());
+ TestMenuDelegate* delegate = menu_delegate();
+ EXPECT_EQ(1, delegate->execute_command_id());
+ EXPECT_EQ(1, delegate->on_menu_closed_called());
+ EXPECT_NE(nullptr, delegate->on_menu_closed_menu());
+}
+#endif // OS_MACOSX
+
// Tests that attempting to nest a menu within a drag-and-drop menu does not
// cause a crash. Instead the drag and drop action should be canceled, and the
// new menu should be openned.
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 16a1bef6715..ecbd5d773b9 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -286,7 +286,9 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
? kBorderPaddingDueToRoundedCorners
: 0;
- const int vertical_inset = menu_config.menu_vertical_border_size + padding;
+ const int vertical_inset =
+ (corner_radius ? corner_radius : menu_config.menu_vertical_border_size) +
+ padding;
const int horizontal_inset =
menu_config.menu_horizontal_border_size + padding;
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index cdb36b6df6c..c9ad4e4f5b9 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -374,7 +374,8 @@ void SubmenuView::SetSelectedRow(int row) {
}
base::string16 SubmenuView::GetTextForRow(int row) {
- return GetMenuItemAt(row)->title();
+ return MenuItemView::GetAccessibleNameForMenuItem(GetMenuItemAt(row)->title(),
+ base::string16());
}
bool SubmenuView::IsShowing() {
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.cc b/chromium/ui/views/controls/native/native_view_host_aura.cc
index 6afc8fbf9c3..4bd67c7a87d 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -69,34 +69,24 @@ class NativeViewHostAura::ClippingWindowDelegate : public aura::WindowDelegate {
aura::Window* native_view_;
};
-NativeViewHostAura::NativeViewHostAura(NativeViewHost* host)
- : host_(host),
- clipping_window_delegate_(new ClippingWindowDelegate()),
- clipping_window_(clipping_window_delegate_.get()) {
- // Set the type so descendant views (including popups) get positioned
- // appropriately.
- clipping_window_.SetType(aura::client::WINDOW_TYPE_CONTROL);
- clipping_window_.Init(ui::LAYER_NOT_DRAWN);
- clipping_window_.set_owned_by_parent(false);
- clipping_window_.SetName("NativeViewHostAuraClip");
- clipping_window_.layer()->SetMasksToBounds(true);
- clipping_window_.SetProperty(views::kHostViewKey, static_cast<View*>(host_));
-}
+NativeViewHostAura::NativeViewHostAura(NativeViewHost* host) : host_(host) {}
NativeViewHostAura::~NativeViewHostAura() {
if (host_->native_view()) {
host_->native_view()->RemoveObserver(this);
host_->native_view()->ClearProperty(views::kHostViewKey);
host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
- clipping_window_.ClearProperty(views::kHostViewKey);
- if (host_->native_view()->parent() == &clipping_window_)
- clipping_window_.RemoveChild(host_->native_view());
+ clipping_window_->ClearProperty(views::kHostViewKey);
+ if (host_->native_view()->parent() == clipping_window_.get())
+ clipping_window_->RemoveChild(host_->native_view());
}
}
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostAura, NativeViewHostWrapper implementation:
void NativeViewHostAura::AttachNativeView() {
+ if (!clipping_window_)
+ CreateClippingWindow();
clipping_window_delegate_->set_native_view(host_->native_view());
host_->native_view()->AddObserver(this);
host_->native_view()->SetProperty(views::kHostViewKey,
@@ -202,18 +192,17 @@ void NativeViewHostAura::ShowWidget(int x,
}
}
- clipping_window_.SetBounds(clip_rect_ ? *clip_rect_
- : gfx::Rect(x, y, w, h));
- gfx::Point clip_offset = clipping_window_.bounds().origin();
+ clipping_window_->SetBounds(clip_rect_ ? *clip_rect_ : gfx::Rect(x, y, w, h));
+ gfx::Point clip_offset = clipping_window_->bounds().origin();
host_->native_view()->SetBounds(
gfx::Rect(x - clip_offset.x(), y - clip_offset.y(), native_w, native_h));
host_->native_view()->Show();
- clipping_window_.Show();
+ clipping_window_->Show();
}
void NativeViewHostAura::HideWidget() {
host_->native_view()->Hide();
- clipping_window_.Hide();
+ clipping_window_->Hide();
}
void NativeViewHostAura::SetFocus() {
@@ -265,35 +254,48 @@ NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
return new NativeViewHostAura(host);
}
+void NativeViewHostAura::CreateClippingWindow() {
+ clipping_window_delegate_ = std::make_unique<ClippingWindowDelegate>();
+ // Use WINDOW_TYPE_CONTROLLER type so descendant views (including popups) get
+ // positioned appropriately.
+ clipping_window_ = std::make_unique<aura::Window>(
+ clipping_window_delegate_.get(), aura::client::WINDOW_TYPE_CONTROL,
+ host_->native_view()->env());
+ clipping_window_->Init(ui::LAYER_NOT_DRAWN);
+ clipping_window_->set_owned_by_parent(false);
+ clipping_window_->SetName("NativeViewHostAuraClip");
+ clipping_window_->layer()->SetMasksToBounds(true);
+ clipping_window_->SetProperty(views::kHostViewKey, static_cast<View*>(host_));
+}
+
void NativeViewHostAura::AddClippingWindow() {
RemoveClippingWindow();
host_->native_view()->SetProperty(aura::client::kHostWindowKey,
host_->GetWidget()->GetNativeView());
- Widget::ReparentNativeView(host_->native_view(),
- &clipping_window_);
+ Widget::ReparentNativeView(host_->native_view(), clipping_window_.get());
if (host_->GetWidget()->GetNativeView()) {
- Widget::ReparentNativeView(&clipping_window_,
+ Widget::ReparentNativeView(clipping_window_.get(),
host_->GetWidget()->GetNativeView());
}
}
void NativeViewHostAura::RemoveClippingWindow() {
- clipping_window_.Hide();
+ clipping_window_->Hide();
if (host_->native_view())
host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
- if (host_->native_view()->parent() == &clipping_window_) {
+ if (host_->native_view()->parent() == clipping_window_.get()) {
if (host_->GetWidget() && host_->GetWidget()->GetNativeView()) {
Widget::ReparentNativeView(host_->native_view(),
host_->GetWidget()->GetNativeView());
} else {
- clipping_window_.RemoveChild(host_->native_view());
+ clipping_window_->RemoveChild(host_->native_view());
}
- host_->native_view()->SetBounds(clipping_window_.bounds());
+ host_->native_view()->SetBounds(clipping_window_->bounds());
}
- if (clipping_window_.parent())
- clipping_window_.parent()->RemoveChild(&clipping_window_);
+ if (clipping_window_->parent())
+ clipping_window_->parent()->RemoveChild(clipping_window_.get());
}
void NativeViewHostAura::InstallMask() {
diff --git a/chromium/ui/views/controls/native/native_view_host_aura.h b/chromium/ui/views/controls/native/native_view_host_aura.h
index 0ea78965b8f..a6072997977 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.h
+++ b/chromium/ui/views/controls/native/native_view_host_aura.h
@@ -7,13 +7,16 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_owner.h"
#include "ui/gfx/transform.h"
#include "ui/views/controls/native/native_view_host_wrapper.h"
#include "ui/views/views_export.h"
+namespace aura {
+class Window;
+}
+
namespace views {
class NativeViewHost;
@@ -53,6 +56,8 @@ class NativeViewHostAura : public NativeViewHostWrapper,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
+ void CreateClippingWindow();
+
// Reparents the native view with the clipping window existing between it and
// its old parent, so that the fast resize path works.
void AddClippingWindow();
@@ -75,7 +80,7 @@ class NativeViewHostAura : public NativeViewHostWrapper,
// Window that exists between the native view and the parent that allows for
// clipping to occur. This is positioned in the coordinate space of
// host_->GetWidget().
- aura::Window clipping_window_;
+ std::unique_ptr<aura::Window> clipping_window_;
std::unique_ptr<gfx::Rect> clip_rect_;
// This mask exists for the sake of SetCornerRadius().
diff --git a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
index 349d1a1b8c5..4a7e05f70b8 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -97,7 +97,9 @@ class NativeViewHostAuraTest : public test::NativeViewHostTestBase {
return child_.get();
}
- aura::Window* clipping_window() { return &(native_host()->clipping_window_); }
+ aura::Window* clipping_window() {
+ return native_host()->clipping_window_.get();
+ }
void CreateHost() {
CreateTopLevel();
diff --git a/chromium/ui/views/controls/prefix_selector.cc b/chromium/ui/views/controls/prefix_selector.cc
index 9844d192d78..98aab8c61c7 100644
--- a/chromium/ui/views/controls/prefix_selector.cc
+++ b/chromium/ui/views/controls/prefix_selector.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/prefix_selector.h"
#include "base/i18n/case_conversion.h"
+#include "base/time/default_tick_clock.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/gfx/range/range.h"
@@ -21,8 +22,9 @@ const int64_t kTimeBeforeClearingMS = 1000;
} // namespace
PrefixSelector::PrefixSelector(PrefixDelegate* delegate, View* host_view)
- : prefix_delegate_(delegate), host_view_(host_view) {
-}
+ : prefix_delegate_(delegate),
+ host_view_(host_view),
+ tick_clock_(base::DefaultTickClock::GetInstance()) {}
PrefixSelector::~PrefixSelector() {
}
@@ -31,6 +33,11 @@ void PrefixSelector::OnViewBlur() {
ClearText();
}
+bool PrefixSelector::ShouldContinueSelection() const {
+ const base::TimeTicks now(tick_clock_->NowTicks());
+ return ((now - time_of_last_key_).InMilliseconds() < kTimeBeforeClearingMS);
+}
+
void PrefixSelector::SetCompositionText(
const ui::CompositionText& composition) {
}
@@ -174,15 +181,14 @@ void PrefixSelector::OnTextInput(const base::string16& text) {
// while search after the current row, otherwise search starting from the
// current row.
int row = std::max(0, prefix_delegate_->GetSelectedRow());
- const base::TimeTicks now(base::TimeTicks::Now());
- if ((now - time_of_last_key_).InMilliseconds() < kTimeBeforeClearingMS) {
+ if (ShouldContinueSelection()) {
current_text_ += text;
} else {
current_text_ = text;
if (prefix_delegate_->GetSelectedRow() >= 0)
row = (row + 1) % row_count;
}
- time_of_last_key_ = now;
+ time_of_last_key_ = tick_clock_->NowTicks();
const int start_row = row;
const base::string16 lower_text(base::i18n::ToLower(current_text_));
diff --git a/chromium/ui/views/controls/prefix_selector.h b/chromium/ui/views/controls/prefix_selector.h
index ba2005191b3..801c9112b73 100644
--- a/chromium/ui/views/controls/prefix_selector.h
+++ b/chromium/ui/views/controls/prefix_selector.h
@@ -14,6 +14,10 @@
#include "ui/base/ime/text_input_client.h"
#include "ui/views/views_export.h"
+namespace base {
+class TickClock;
+}
+
namespace views {
class PrefixDelegate;
@@ -29,6 +33,10 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
// Invoked from the view when it loses focus.
void OnViewBlur();
+ // Returns whether a key typed now would continue the existing search or start
+ // a new search.
+ bool ShouldContinueSelection() const;
+
// ui::TextInputClient:
void SetCompositionText(const ui::CompositionText& composition) override;
void ConfirmCompositionText() override;
@@ -63,6 +71,10 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
ukm::SourceId GetClientSourceForMetrics() const override;
bool ShouldDoLearning() override;
+ void set_tick_clock_for_testing(const base::TickClock* clock) {
+ tick_clock_ = clock;
+ }
+
private:
// Invoked when text is typed. Tries to change the selection appropriately.
void OnTextInput(const base::string16& text);
@@ -82,6 +94,10 @@ class VIEWS_EXPORT PrefixSelector : public ui::TextInputClient {
base::string16 current_text_;
+ // TickClock used for getting the time of the current keystroke, used for
+ // continuing or restarting selections.
+ const base::TickClock* tick_clock_;
+
DISALLOW_COPY_AND_ASSIGN(PrefixSelector);
};
diff --git a/chromium/ui/views/controls/scroll_view.cc b/chromium/ui/views/controls/scroll_view.cc
index e58ef7d3cdc..9f7028a505c 100644
--- a/chromium/ui/views/controls/scroll_view.cc
+++ b/chromium/ui/views/controls/scroll_view.cc
@@ -7,7 +7,6 @@
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/ui_base_features.h"
#include "ui/compositor/overscroll/scroll_input_handler.h"
#include "ui/events/event.h"
@@ -215,13 +214,11 @@ ScrollView::ScrollView()
}
UpdateBackground();
- if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
- focus_ring_ = FocusRing::Install(this);
- focus_ring_->SetHasFocusPredicate([](View* view) -> bool {
- auto* v = static_cast<ScrollView*>(view);
- return v->draw_focus_indicator_;
- });
- }
+ focus_ring_ = FocusRing::Install(this);
+ focus_ring_->SetHasFocusPredicate([](View* view) -> bool {
+ auto* v = static_cast<ScrollView*>(view);
+ return v->draw_focus_indicator_;
+ });
}
ScrollView::~ScrollView() {
@@ -335,10 +332,7 @@ void ScrollView::SetHasFocusIndicator(bool has_focus_indicator) {
return;
draw_focus_indicator_ = has_focus_indicator;
- if (ui::MaterialDesignController::IsSecondaryUiMaterial())
focus_ring_->SchedulePaint();
- else
- UpdateBorder();
SchedulePaint();
}
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index 4da3917fefb..4166c97c0bc 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -321,7 +321,6 @@ class WidgetScrollViewTest : public test::WidgetTest,
void OnCompositingStarted(ui::Compositor* compositor,
base::TimeTicks start_time) override {}
void OnCompositingEnded(ui::Compositor* compositor) override {}
- void OnCompositingLockStateChanged(ui::Compositor* compositor) override {}
void OnCompositingChildResizing(ui::Compositor* compositor) override {}
void OnCompositingShuttingDown(ui::Compositor* compositor) override {}
@@ -1654,8 +1653,9 @@ TEST_P(WidgetScrollViewTestRTLAndLayers, ScrollOffsetUsingLayers) {
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)));
+ cc::ElementId element_id =
+ container->layer()->cc_layer_for_testing()->element_id();
+ EXPECT_FALSE(compositor->ScrollLayerTo(element_id, gfx::ScrollOffset(0, 0)));
EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
WaitForCommit();
@@ -1663,13 +1663,13 @@ TEST_P(WidgetScrollViewTestRTLAndLayers, ScrollOffsetUsingLayers) {
// Upon commit, the impl side should report the same value too.
gfx::ScrollOffset impl_offset;
- EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+ EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_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())));
+ compositor->ScrollLayerTo(element_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.
@@ -1677,7 +1677,7 @@ TEST_P(WidgetScrollViewTestRTLAndLayers, ScrollOffsetUsingLayers) {
scroll_view->contents()->ScrollRectToVisible(offset);
EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset());
- EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+ EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset));
EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset);
// Test horizontal scrolling.
@@ -1686,7 +1686,7 @@ TEST_P(WidgetScrollViewTestRTLAndLayers, ScrollOffsetUsingLayers) {
EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()),
test_api.CurrentOffset());
- EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset));
+ EXPECT_TRUE(compositor->GetScrollOffsetForLayer(element_id, &impl_offset));
EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()), impl_offset);
}
diff --git a/chromium/ui/views/controls/separator.cc b/chromium/ui/views/controls/separator.cc
index 8be91e790d2..d6a43ea8249 100644
--- a/chromium/ui/views/controls/separator.cc
+++ b/chromium/ui/views/controls/separator.cc
@@ -50,10 +50,15 @@ void Separator::OnPaint(gfx::Canvas* canvas) {
: GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_SeparatorColor);
- // The separator fills its bounds, but avoid filling partial pixels.
float dsf = canvas->UndoDeviceScaleFactor();
- gfx::RectF contents = gfx::ScaleRect(gfx::RectF(GetContentsBounds()), dsf);
- canvas->FillRect(gfx::ToEnclosedRect(contents), color);
+
+ // The separator fills its bounds, but avoid filling partial pixels.
+ gfx::Rect aligned = gfx::ScaleToEnclosedRect(GetContentsBounds(), dsf, dsf);
+
+ // At least 1 pixel should be drawn to make the separator visible.
+ aligned.set_width(std::max(1, aligned.width()));
+ aligned.set_height(std::max(1, aligned.height()));
+ canvas->FillRect(aligned, color);
View::OnPaint(canvas);
}
diff --git a/chromium/ui/views/controls/separator_unittest.cc b/chromium/ui/views/controls/separator_unittest.cc
new file mode 100644
index 00000000000..44296c040d2
--- /dev/null
+++ b/chromium/ui/views/controls/separator_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 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/separator.h"
+
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_unittest_util.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace views {
+
+// Base test fixture for Separator tests.
+class SeparatorTest : public views::ViewsTestBase {
+ public:
+ SeparatorTest() = default;
+ ~SeparatorTest() override = default;
+
+ protected:
+ void ExpectDrawAtLeastOnePixel(float image_scale);
+
+ Separator separator_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SeparatorTest);
+};
+
+void SeparatorTest::ExpectDrawAtLeastOnePixel(float image_scale) {
+ const gfx::Size kTestImageSize = gfx::Size(24, 24);
+ const SkColor kBackgroundColor = SK_ColorRED;
+ gfx::Canvas init(kTestImageSize, image_scale, true);
+ gfx::Canvas canvas(kTestImageSize, image_scale, true);
+ init.DrawColor(kBackgroundColor);
+ canvas.DrawColor(kBackgroundColor);
+ ASSERT_TRUE(gfx::test::AreBitmapsEqual(canvas.GetBitmap(), init.GetBitmap()));
+ separator_.OnPaint(&canvas);
+
+ // At least 1 pixel should be changed.
+ EXPECT_FALSE(
+ gfx::test::AreBitmapsEqual(canvas.GetBitmap(), init.GetBitmap()));
+}
+
+TEST_F(SeparatorTest, ImageScaleBelowOne) {
+ // Vertical line with 1[dp] thickness by default.
+ separator_.SetPreferredHeight(8);
+ ExpectDrawAtLeastOnePixel(0.4);
+}
+
+TEST_F(SeparatorTest, ImageScaleBelowOne_HorizontalLine) {
+ const int kThickness = 1;
+ // Use Separator as a horizontal line with 1[dp] thickness.
+ separator_.SetBounds(4, 5, 8, kThickness);
+ ExpectDrawAtLeastOnePixel(0.4);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 1f2d6fbcd4e..2c12e6e77ef 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -82,6 +82,16 @@ int HorizontalAdjustment(int used_width,
} // namespace
+// StyledLabel::TestApi ------------------------------------------------
+
+StyledLabel::TestApi::TestApi(StyledLabel* view) : view_(view) {}
+
+StyledLabel::TestApi::~TestApi() = default;
+
+const std::map<View*, gfx::Range>& StyledLabel::TestApi::link_targets() {
+ return view_->link_targets_;
+}
+
// StyledLabel::RangeStyleInfo ------------------------------------------------
StyledLabel::RangeStyleInfo::RangeStyleInfo() = default;
diff --git a/chromium/ui/views/controls/styled_label.h b/chromium/ui/views/controls/styled_label.h
index ae5bac5511a..43544ef691b 100644
--- a/chromium/ui/views/controls/styled_label.h
+++ b/chromium/ui/views/controls/styled_label.h
@@ -37,6 +37,20 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// Internal class name.
static const char kViewClassName[];
+ // TestApi is used for tests to get internal implementation details.
+ class VIEWS_EXPORT TestApi {
+ public:
+ explicit TestApi(StyledLabel* view);
+ ~TestApi();
+
+ const std::map<View*, gfx::Range>& link_targets();
+
+ private:
+ StyledLabel* const view_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestApi);
+ };
+
// Parameters that define label style for a styled label's text range.
struct VIEWS_EXPORT RangeStyleInfo {
RangeStyleInfo();
diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc
index a71c62d657a..e79fadddb32 100644
--- a/chromium/ui/views/controls/styled_label_unittest.cc
+++ b/chromium/ui/views/controls/styled_label_unittest.cc
@@ -9,15 +9,14 @@
#include <memory>
#include <string>
+#include "base/command_line.h"
#include "base/i18n/base_i18n_switches.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
-#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/font_list.h"
#include "ui/views/border.h"
@@ -32,15 +31,6 @@
using base::ASCIIToUTF16;
namespace views {
-namespace {
-
-enum class SecondaryUiMode { NON_MD, MD };
-
-std::string SecondaryUiModeToString(
- const ::testing::TestParamInfo<SecondaryUiMode>& info) {
- return info.param == SecondaryUiMode::MD ? "MD" : "NonMD";
-}
-} // namespace
class StyledLabelTest : public ViewsTestBase, public StyledLabelListener {
public:
@@ -70,39 +60,6 @@ class StyledLabelTest : public ViewsTestBase, public StyledLabelListener {
DISALLOW_COPY_AND_ASSIGN(StyledLabelTest);
};
-// StyledLabelTest harness that runs both with and without secondary UI set to
-// MD.
-class MDStyledLabelTest
- : public StyledLabelTest,
- public ::testing::WithParamInterface<SecondaryUiMode> {
- public:
- MDStyledLabelTest() {}
-
- // StyledLabelTest:
- void SetUp() override {
- if (GetParam() == SecondaryUiMode::NON_MD) {
- // Force Refresh UI to be off, since that mode implies MD secondary UI.
- // Must be done before ViewsTestBase::SetUp().
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kTopChromeMD, switches::kTopChromeMDMaterial);
- }
- // This works while StyledLabelTest has no SetUp() of its own. Otherwise the
- // mode should be set after ViewsTestBase::SetUp(), but before the rest of
- // StyledLabelTest::SetUp(), so that StyledLabelTest::SetUp() obeys the MD
- // setting.
- StyledLabelTest::SetUp();
- if (GetParam() == SecondaryUiMode::MD)
- scoped_feature_list_.InitAndEnableFeature(features::kSecondaryUiMd);
- else
- scoped_feature_list_.InitAndDisableFeature(features::kSecondaryUiMd);
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-
- DISALLOW_COPY_AND_ASSIGN(MDStyledLabelTest);
-};
-
TEST_F(StyledLabelTest, NoWrapping) {
const std::string text("This is a test block of text");
InitStyledLabel(text);
@@ -255,7 +212,7 @@ TEST_F(StyledLabelTest, WrapLongWords) {
static_cast<Label*>(styled()->child_at(1))->text());
}
-TEST_P(MDStyledLabelTest, CreateLinks) {
+TEST_F(StyledLabelTest, CreateLinks) {
const std::string text("This is a test block of text.");
InitStyledLabel(text);
@@ -272,14 +229,9 @@ TEST_P(MDStyledLabelTest, CreateLinks) {
styled()->AddStyleRange(gfx::Range(12, 13),
StyledLabel::RangeStyleInfo::CreateForLink());
- if (GetParam() == SecondaryUiMode::MD) {
- // Insets shouldn't change under MD when links are added, since the links
- // indicate focus by adding an underline instead.
- EXPECT_TRUE(styled()->GetInsets().IsEmpty());
- } else {
- // Now there should be a focus border because there are non-empty Links.
- EXPECT_FALSE(styled()->GetInsets().IsEmpty());
- }
+ // Insets shouldn't change when links are added, since the links indicate
+ // focus by adding an underline instead.
+ EXPECT_TRUE(styled()->GetInsets().IsEmpty());
// Verify layout creates the right number of children.
styled()->SetBounds(0, 0, 1000, 1000);
@@ -287,7 +239,7 @@ TEST_P(MDStyledLabelTest, CreateLinks) {
EXPECT_EQ(7, styled()->child_count());
}
-TEST_P(MDStyledLabelTest, DontBreakLinks) {
+TEST_F(StyledLabelTest, DontBreakLinks) {
const std::string text("This is a test block of text, ");
const std::string link_text("and this should be a link");
InitStyledLabel(text + link_text);
@@ -305,16 +257,9 @@ TEST_P(MDStyledLabelTest, DontBreakLinks) {
styled()->Layout();
ASSERT_EQ(2, styled()->child_count());
- if (GetParam() == SecondaryUiMode::MD) {
- // No additional insets should be added under MD.
- EXPECT_EQ(0, styled()->child_at(0)->x());
- } else {
- // The label has no focus border while, when non-MD, the link (and thus
- // overall styled label) does, so the label should be inset by the width of
- // the focus border.
- EXPECT_EQ(Link::kFocusBorderPadding, styled()->child_at(0)->x());
- }
- // The Link shouldn't be offset (it grows in size under non-MD instead).
+ // No additional insets should be added.
+ EXPECT_EQ(0, styled()->child_at(0)->x());
+ // The Link shouldn't be offset.
EXPECT_EQ(0, styled()->child_at(1)->x());
}
@@ -488,7 +433,7 @@ TEST_F(StyledLabelTest, Color) {
widget->CloseNow();
}
-TEST_P(MDStyledLabelTest, StyledRangeWithTooltip) {
+TEST_F(StyledLabelTest, StyledRangeWithTooltip) {
const std::string text("This is a test block of text, ");
const std::string tooltip_text("this should have a tooltip,");
const std::string normal_text(" this should not have a tooltip, ");
@@ -522,17 +467,9 @@ TEST_P(MDStyledLabelTest, StyledRangeWithTooltip) {
ASSERT_EQ(5, styled()->child_count());
- if (GetParam() == SecondaryUiMode::MD) {
- // In MD, the labels shouldn't be offset to cater for focus rings.
- EXPECT_EQ(0, styled()->child_at(0)->x());
- EXPECT_EQ(0, styled()->child_at(2)->x());
- } else {
- // The labels have no focus border while the link (and thus overall styled
- // label) does, so the labels should be inset by the width of the focus
- // border.
- EXPECT_EQ(Link::kFocusBorderPadding, styled()->child_at(0)->x());
- EXPECT_EQ(Link::kFocusBorderPadding, styled()->child_at(2)->x());
- }
+ // The labels shouldn't be offset to cater for focus rings.
+ EXPECT_EQ(0, styled()->child_at(0)->x());
+ EXPECT_EQ(0, styled()->child_at(2)->x());
EXPECT_EQ(styled()->child_at(0)->bounds().right(),
styled()->child_at(1)->x());
@@ -776,7 +713,7 @@ TEST_F(StyledLabelTest, AlignmentInRTL) {
styled()->child_at(0)->bounds().x());
}
-TEST_P(MDStyledLabelTest, ViewsCenteredWithLinkAndCustomView) {
+TEST_F(StyledLabelTest, ViewsCenteredWithLinkAndCustomView) {
const std::string text("This is a test block of text, ");
const std::string link_text("and this should be a link");
const std::string custom_view_text("And this is a custom view");
@@ -810,10 +747,4 @@ TEST_P(MDStyledLabelTest, ViewsCenteredWithLinkAndCustomView) {
styled()->child_at(2)->bounds().y());
}
-INSTANTIATE_TEST_CASE_P(,
- MDStyledLabelTest,
- ::testing::Values(SecondaryUiMode::MD,
- SecondaryUiMode::NON_MD),
- &SecondaryUiModeToString);
-
} // namespace views
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 4cd621b05c5..04e572c25d0 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -12,7 +12,6 @@
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_node_data.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/animation/animation_delegate.h"
@@ -667,9 +666,7 @@ TabbedPane::TabbedPane(TabbedPane::Orientation orientation,
: listener_(NULL), contents_(new View()) {
DCHECK(orientation != TabbedPane::Orientation::kHorizontal ||
style != TabbedPane::TabStripStyle::kHighlight);
- tab_strip_ = ui::MaterialDesignController::IsSecondaryUiMaterial()
- ? new MdTabStrip(orientation, style)
- : new TabStrip(orientation, style);
+ tab_strip_ = new MdTabStrip(orientation, style);
AddChildView(tab_strip_);
AddChildView(contents_);
}
@@ -695,11 +692,7 @@ void TabbedPane::AddTabAtIndex(int index,
DCHECK(index >= 0 && index <= GetTabCount());
contents->SetVisible(false);
- tab_strip_->AddChildViewAt(
- ui::MaterialDesignController::IsSecondaryUiMaterial()
- ? new MdTab(this, title, contents)
- : new Tab(this, title, contents),
- index);
+ tab_strip_->AddChildViewAt(new MdTab(this, title, contents), index);
contents_->AddChildViewAt(contents, index);
if (!GetSelectedTab())
SelectTabAt(index);
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index c9a96b43788..752c642e2da 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -21,7 +21,6 @@
#include "ui/base/dragdrop/drag_drop_types.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.h"
#include "ui/base/ui_base_switches_util.h"
@@ -93,9 +92,6 @@ const gfx::SelectionBehavior kMoveParagraphSelectionBehavior =
gfx::SELECTION_RETAIN;
#endif
-// Default placeholder text color.
-const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
-
// Get the default command for a given key |event|.
ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) {
if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
@@ -279,7 +275,7 @@ Textfield::Textfield()
selection_controller_(this),
drag_start_display_offset_(0),
touch_handles_hidden_due_to_scroll_(false),
- use_focus_ring_(ui::MaterialDesignController::IsSecondaryUiMaterial()),
+ use_focus_ring_(true),
weak_ptr_factory_(this) {
set_context_menu_controller(this);
set_drag_controller(this);
@@ -666,7 +662,9 @@ bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
(event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())) {
if (!had_focus)
RequestFocusWithPointer(ui::EventPointerType::POINTER_TYPE_MOUSE);
+#if !defined(OS_WIN)
ShowVirtualKeyboardIfEnabled();
+#endif
}
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
@@ -743,10 +741,16 @@ bool Textfield::OnKeyReleased(const ui::KeyEvent& event) {
}
void Textfield::OnGestureEvent(ui::GestureEvent* event) {
+ bool show_virtual_keyboard = true;
+#if defined(OS_WIN)
+ show_virtual_keyboard = event->details().primary_pointer_type() ==
+ ui::EventPointerType::POINTER_TYPE_TOUCH;
+#endif
switch (event->type()) {
case ui::ET_GESTURE_TAP_DOWN:
RequestFocusWithPointer(event->details().primary_pointer_type());
- ShowVirtualKeyboardIfEnabled();
+ if (show_virtual_keyboard)
+ ShowVirtualKeyboardIfEnabled();
event->SetHandled();
break;
case ui::ET_GESTURE_TAP:
@@ -2083,13 +2087,9 @@ void Textfield::UpdateSelectionClipboard() {
void Textfield::UpdateBackgroundColor() {
const SkColor color = GetBackgroundColor();
- if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
SetBackground(
CreateBackgroundFromPainter(Painter::CreateSolidRoundRectPainter(
color, FocusableBorder::kCornerRadiusDp)));
- } else {
- SetBackground(CreateSolidBackground(color));
- }
// Disable subpixel rendering when the background color is not opaque because
// it draws incorrect colors around the glyphs in that case.
// See crbug.com/115198
@@ -2165,10 +2165,7 @@ void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) {
GetPlaceholderText(),
placeholder_font_list_.has_value() ? placeholder_font_list_.value()
: GetFontList(),
- placeholder_text_color_.value_or(
- ui::MaterialDesignController::IsSecondaryUiMaterial()
- ? SkColorSetA(GetTextColor(), 0x83)
- : kDefaultPlaceholderTextColor),
+ placeholder_text_color_.value_or(SkColorSetA(GetTextColor(), 0x83)),
render_text->display_rect(), placeholder_text_draw_flags);
}
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index 6ccde824c4d..f8a8292c501 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -39,6 +39,7 @@
#include "ui/events/event.h"
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/test/keyboard_layout.h"
@@ -565,7 +566,7 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
// keyboard. So they are dispatched directly to the input method. But on
// Mac, key events don't pass through InputMethod. Hence they are
// dispatched regularly.
- ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, flags);
+ ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::DomCode::NONE, flags);
#if defined(OS_MACOSX)
event_generator_->Dispatch(&event);
#else
@@ -574,6 +575,15 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
}
}
+ // Send a key to trigger MockInputMethod::DispatchKeyEvent(). Note the
+ // specific VKEY isn't used (MockInputMethod will mock a ui::VKEY_PROCESSKEY
+ // whenever it has a test composition). However, on Mac, it can't be a letter
+ // (e.g. VKEY_A) since all native character events on Mac are unicode events
+ // and don't have a meaningful ui::KeyEvent that would trigger
+ // DispatchKeyEvent(). It also can't be VKEY_ENTER, since those key events may
+ // need to be suppressed when interacting with real system IME.
+ void DispatchMockInputMethodKeyEvent() { SendKeyEvent(ui::VKEY_INSERT); }
+
// Sends a platform-specific move (and select) to the logical start of line.
// Eg. this should move (and select) to the right end of line for RTL text.
void SendHomeEvent(bool shift) {
@@ -1708,7 +1718,7 @@ TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) {
EXPECT_EQ(ui::OSExchangeData::STRING, formats);
EXPECT_TRUE(format_types.empty());
EXPECT_TRUE(textfield_->CanDrop(data));
- gfx::Point drop_point(GetCursorPositionX(6), 0);
+ gfx::PointF drop_point(GetCursorPositionX(6), 0);
ui::DropTargetEvent drop(data, drop_point, drop_point,
ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE);
EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
@@ -1802,7 +1812,7 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheRight) {
EXPECT_TRUE(format_types.empty());
// Drop "ello" after "w".
- const gfx::Point kDropPoint(GetCursorPositionX(7), cursor_y);
+ const gfx::PointF kDropPoint(GetCursorPositionX(7), cursor_y);
EXPECT_TRUE(textfield_->CanDrop(data));
ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations);
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
@@ -1854,7 +1864,7 @@ TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) {
// Drop " worl" after "h".
EXPECT_TRUE(textfield_->CanDrop(data));
- gfx::Point drop_point(GetCursorPositionX(1), cursor_y);
+ gfx::PointF drop_point(GetCursorPositionX(1), cursor_y);
ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations);
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a));
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a));
@@ -1890,7 +1900,7 @@ TEST_F(TextfieldTest, DragAndDrop_Canceled) {
textfield_->WriteDragDataForView(nullptr, point, &data);
EXPECT_TRUE(textfield_->CanDrop(data));
// Drag the text over somewhere valid, outside the current selection.
- gfx::Point drop_point(GetCursorPositionX(2), cursor_y);
+ gfx::PointF drop_point(GetCursorPositionX(2), cursor_y);
ui::DropTargetEvent drop(data, drop_point, drop_point,
ui::DragDropTypes::DRAG_MOVE);
EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop));
@@ -2000,14 +2010,7 @@ TEST_F(TextfieldTest, TextInputClientTest) {
textfield_->clear();
on_before_user_action_ = on_after_user_action_ = 0;
-
- // Send a key to trigger MockInputMethod::DispatchKeyEvent(). Note the
- // specific VKEY isn't used (MockInputMethod will mock a ui::VKEY_PROCESSKEY
- // whenever it has a test composition). However, on Mac, it can't be a letter
- // (e.g. VKEY_A) since all native character events on Mac are unicode events
- // and don't have a meaningful ui::KeyEvent that would trigger
- // DispatchKeyEvent().
- SendKeyEvent(ui::VKEY_RETURN);
+ DispatchMockInputMethodKeyEvent();
EXPECT_TRUE(textfield_->key_received());
EXPECT_FALSE(textfield_->key_handled());
@@ -2021,7 +2024,7 @@ TEST_F(TextfieldTest, TextInputClientTest) {
input_method_->SetResultTextForNextKey(UTF8ToUTF16("123"));
on_before_user_action_ = on_after_user_action_ = 0;
textfield_->clear();
- SendKeyEvent(ui::VKEY_RETURN);
+ DispatchMockInputMethodKeyEvent();
EXPECT_TRUE(textfield_->key_received());
EXPECT_FALSE(textfield_->key_handled());
EXPECT_FALSE(client->HasCompositionText());
@@ -2033,7 +2036,7 @@ TEST_F(TextfieldTest, TextInputClientTest) {
input_method_->Clear();
input_method_->SetCompositionTextForNextKey(composition);
textfield_->clear();
- SendKeyEvent(ui::VKEY_RETURN);
+ DispatchMockInputMethodKeyEvent();
EXPECT_TRUE(client->HasCompositionText());
EXPECT_STR_EQ("0123321456789", textfield_->text());
diff --git a/chromium/ui/views/controls/webview/web_contents_set_background_color.cc b/chromium/ui/views/controls/webview/web_contents_set_background_color.cc
index e5de0e42b34..cfdf3e6b6b1 100644
--- a/chromium/ui/views/controls/webview/web_contents_set_background_color.cc
+++ b/chromium/ui/views/controls/webview/web_contents_set_background_color.cc
@@ -9,8 +9,6 @@
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(views::WebContentsSetBackgroundColor);
-
namespace views {
// static
diff --git a/chromium/ui/views/corewm/tooltip_aura.cc b/chromium/ui/views/corewm/tooltip_aura.cc
index 80237a0abcf..c36fdd45c43 100644
--- a/chromium/ui/views/corewm/tooltip_aura.cc
+++ b/chromium/ui/views/corewm/tooltip_aura.cc
@@ -42,7 +42,8 @@ bool CanUseTranslucentTooltipWidget() {
}
// Creates a widget of type TYPE_TOOLTIP
-views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
+views::Widget* CreateTooltipWidget(aura::Window* tooltip_window,
+ const gfx::Rect& bounds) {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params;
// For aura, since we set the type to TYPE_TOOLTIP, the widget will get
@@ -52,6 +53,7 @@ views::Widget* CreateTooltipWidget(aura::Window* tooltip_window) {
DCHECK(params.context);
params.keep_on_top = true;
params.accept_events = false;
+ params.bounds = bounds;
if (CanUseTranslucentTooltipWidget())
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
@@ -166,8 +168,8 @@ gfx::RenderText* TooltipAura::GetRenderTextForTest() {
return tooltip_view_->render_text_for_test();
}
-void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
- const gfx::Size& tooltip_size) {
+gfx::Rect TooltipAura::GetTooltipBounds(const gfx::Point& mouse_pos,
+ const gfx::Size& tooltip_size) {
gfx::Rect tooltip_rect(mouse_pos, tooltip_size);
tooltip_rect.Offset(kCursorOffsetX, kCursorOffsetY);
display::Screen* screen = display::Screen::GetScreen();
@@ -186,7 +188,7 @@ void TooltipAura::SetTooltipBounds(const gfx::Point& mouse_pos,
tooltip_rect.set_y(mouse_pos.y() - tooltip_size.height());
tooltip_rect.AdjustToFit(display_bounds);
- widget_->SetBounds(tooltip_rect);
+ return tooltip_rect;
}
void TooltipAura::DestroyWidget() {
@@ -210,14 +212,17 @@ void TooltipAura::SetText(aura::Window* window,
tooltip_view_->SetMaxWidth(GetMaxWidth(location));
tooltip_view_->SetText(tooltip_text);
+ const gfx::Rect adjusted_bounds =
+ GetTooltipBounds(location, tooltip_view_->GetPreferredSize());
+
if (!widget_) {
- widget_ = CreateTooltipWidget(tooltip_window_);
+ widget_ = CreateTooltipWidget(tooltip_window_, adjusted_bounds);
widget_->SetContentsView(tooltip_view_.get());
widget_->AddObserver(this);
+ } else {
+ widget_->SetBounds(adjusted_bounds);
}
- SetTooltipBounds(location, tooltip_view_->GetPreferredSize());
-
ui::NativeTheme* native_theme = widget_->GetNativeTheme();
tooltip_view_->SetBackgroundColor(native_theme->GetSystemColor(
ui::NativeTheme::kColorId_TooltipBackground));
diff --git a/chromium/ui/views/corewm/tooltip_aura.h b/chromium/ui/views/corewm/tooltip_aura.h
index 4540c3638ab..02b81ccd257 100644
--- a/chromium/ui/views/corewm/tooltip_aura.h
+++ b/chromium/ui/views/corewm/tooltip_aura.h
@@ -38,9 +38,9 @@ class VIEWS_EXPORT TooltipAura : public Tooltip, public WidgetObserver {
gfx::RenderText* GetRenderTextForTest();
// Adjusts the bounds given by the arguments to fit inside the desktop
- // and applies the adjusted bounds to the label_.
- void SetTooltipBounds(const gfx::Point& mouse_pos,
- const gfx::Size& tooltip_size);
+ // and returns the adjusted bounds.
+ gfx::Rect GetTooltipBounds(const gfx::Point& mouse_pos,
+ const gfx::Size& tooltip_size);
// Destroys |widget_|.
void DestroyWidget();
diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
index 357e7a3809a..1212a6f38b1 100644
--- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
@@ -85,20 +85,18 @@ class TooltipControllerTest : public ViewsTestBase {
void SetUp() override {
ViewsTestBase::SetUp();
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
aura::Window* root_window = GetContext();
- new wm::DefaultActivationClient(root_window);
+ if (root_window)
+ new wm::DefaultActivationClient(root_window);
#if defined(OS_CHROMEOS)
- tooltip_aura_ = new views::corewm::TooltipAura();
- controller_.reset(new TooltipController(
- std::unique_ptr<views::corewm::Tooltip>(tooltip_aura_)));
- root_window->AddPreTargetHandler(controller_.get());
- SetTooltipClient(root_window, controller_.get());
+ if (root_window) {
+ tooltip_aura_ = new views::corewm::TooltipAura();
+ controller_.reset(new TooltipController(
+ std::unique_ptr<views::corewm::Tooltip>(tooltip_aura_)));
+ root_window->AddPreTargetHandler(controller_.get());
+ SetTooltipClient(root_window, controller_.get());
+ }
#endif
widget_.reset(CreateWidget(root_window));
widget_->SetContentsView(new View);
@@ -111,17 +109,17 @@ class TooltipControllerTest : public ViewsTestBase {
}
void TearDown() override {
- if (!IsMus()) {
#if defined(OS_CHROMEOS)
- aura::Window* root_window = GetContext();
+ aura::Window* root_window = GetContext();
+ if (root_window) {
root_window->RemovePreTargetHandler(controller_.get());
wm::SetTooltipClient(root_window, NULL);
controller_.reset();
-#endif
- generator_.reset();
- helper_.reset();
- widget_.reset();
}
+#endif
+ generator_.reset();
+ helper_.reset();
+ widget_.reset();
ViewsTestBase::TearDown();
}
@@ -178,11 +176,6 @@ class TooltipControllerTest : public ViewsTestBase {
};
TEST_F(TooltipControllerTest, ViewTooltip) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -206,11 +199,6 @@ TEST_F(TooltipControllerTest, ViewTooltip) {
}
TEST_F(TooltipControllerTest, HideEmptyTooltip) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -225,11 +213,6 @@ TEST_F(TooltipControllerTest, HideEmptyTooltip) {
}
TEST_F(TooltipControllerTest, DontShowTooltipOnTouch) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(nullptr, helper_->GetTooltipWindow());
@@ -253,8 +236,8 @@ TEST_F(TooltipControllerTest, DontShowTooltipOnTouch) {
#if defined(OS_CHROMEOS)
// crbug.com/664370.
TEST_F(TooltipControllerTest, MaxWidth) {
- // TODO: these tests use GetContext(). That should go away for mus client.
- // http://crbug.com/663781.
+ // This test relies on TooltipAura being created, which does not happen in
+ // this test with mus (it happens in DesktopNativeWidgetAura).
if (IsMus())
return;
@@ -276,11 +259,6 @@ TEST_F(TooltipControllerTest, MaxWidth) {
#endif
TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -314,11 +292,6 @@ TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
}
TEST_F(TooltipControllerTest, EnableOrDisableTooltips) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -341,11 +314,6 @@ TEST_F(TooltipControllerTest, EnableOrDisableTooltips) {
// Verifies tooltip isn't shown if tooltip text consists entirely of whitespace.
TEST_F(TooltipControllerTest, DontShowEmptyTooltips) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16(" "));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -355,11 +323,6 @@ TEST_F(TooltipControllerTest, DontShowEmptyTooltips) {
}
TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -404,11 +367,6 @@ TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
}
TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
EXPECT_EQ(base::string16(), helper_->GetTooltipText());
EXPECT_EQ(NULL, helper_->GetTooltipWindow());
@@ -454,11 +412,6 @@ TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
// Verifies a mouse exit event hides the tooltips.
TEST_F(TooltipControllerTest, HideOnExit) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
generator_->MoveMouseToCenterOf(GetWindow());
base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
@@ -472,11 +425,6 @@ TEST_F(TooltipControllerTest, HideOnExit) {
}
TEST_F(TooltipControllerTest, ReshowOnClickAfterEnterExit) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
// Owned by |view_|.
TooltipTestView* v1 = new TooltipTestView;
TooltipTestView* v2 = new TooltipTestView;
@@ -532,11 +480,6 @@ class TooltipControllerCaptureTest : public TooltipControllerTest {
void SetUp() override {
TooltipControllerTest::SetUp();
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
aura::client::SetScreenPositionClient(GetRootWindow(),
&screen_position_client_);
}
@@ -557,11 +500,6 @@ class TooltipControllerCaptureTest : public TooltipControllerTest {
// Verifies when capture is released the TooltipController resets state.
// Flaky on all builders. http://crbug.com/388268
TEST_F(TooltipControllerCaptureTest, DISABLED_CloseOnCaptureLost) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
- if (IsMus())
- return;
-
view_->GetWidget()->SetCapture(view_);
RunPendingMessages();
view_->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
@@ -587,9 +525,8 @@ TEST_F(TooltipControllerCaptureTest, DISABLED_CloseOnCaptureLost) {
#endif
// Verifies the correct window is found for tooltips when there is a capture.
TEST_F(TooltipControllerCaptureTest, MAYBE_Capture) {
- // Currently, capture in one test affects capture in other tests.
- // TODO: these tests use GetContext(). That should go away for mus client.
- // http://crbug.com/663781.
+ // This test doesn't make sense with mus as it creates two widgets and
+ // expects to move the mouse between them.
if (IsMus())
return;
@@ -708,6 +645,11 @@ class TooltipControllerTest2 : public aura::test::AuraTestBase {
};
TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) {
+ // This test does not have a real connection to mus (because it's using
+ // AuraTestBase, not ViewsTestBase), so it can't use EventGenerator.
+ if (ViewsTestBase::IsMus())
+ return;
+
aura::test::TestWindowDelegate test_delegate;
std::unique_ptr<aura::Window> window(
CreateNormalWindow(100, root_window(), &test_delegate));
@@ -721,6 +663,11 @@ TEST_F(TooltipControllerTest2, VerifyLeadingTrailingWhitespaceStripped) {
// Verifies that tooltip is hidden and tooltip window closed upon cancel mode.
TEST_F(TooltipControllerTest2, CloseOnCancelMode) {
+ // This test does not have a real connection to mus (because it's using
+ // AuraTestBase, not ViewsTestBase), so it can't use EventGenerator.
+ if (ViewsTestBase::IsMus())
+ return;
+
aura::test::TestWindowDelegate test_delegate;
std::unique_ptr<aura::Window> window(
CreateNormalWindow(100, root_window(), &test_delegate));
@@ -743,14 +690,14 @@ TEST_F(TooltipControllerTest2, CloseOnCancelMode) {
// Use for tests that need both views and a TestTooltip.
class TooltipControllerTest3 : public ViewsTestBase {
public:
- TooltipControllerTest3() : test_tooltip_(new TestTooltip) {}
- ~TooltipControllerTest3() override {}
+ TooltipControllerTest3() = default;
+ ~TooltipControllerTest3() override = default;
void SetUp() override {
ViewsTestBase::SetUp();
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
+ // This test assumes a hierarchy like that of Ash, which doesn't make sense
+ // with mus.
if (IsMus())
return;
@@ -764,8 +711,9 @@ class TooltipControllerTest3 : public ViewsTestBase {
view_->SetBoundsRect(widget_->GetContentsView()->GetLocalBounds());
generator_.reset(new ui::test::EventGenerator(GetRootWindow()));
- controller_.reset(new TooltipController(
- std::unique_ptr<views::corewm::Tooltip>(test_tooltip_)));
+ auto tooltip = std::make_unique<TestTooltip>();
+ test_tooltip_ = tooltip.get();
+ controller_ = std::make_unique<TooltipController>(std::move(tooltip));
GetRootWindow()->RemovePreTargetHandler(static_cast<TooltipController*>(
wm::GetTooltipClient(widget_->GetNativeWindow()->GetRootWindow())));
GetRootWindow()->AddPreTargetHandler(controller_.get());
@@ -790,7 +738,7 @@ class TooltipControllerTest3 : public ViewsTestBase {
protected:
// Owned by |controller_|.
- TestTooltip* test_tooltip_;
+ TestTooltip* test_tooltip_ = nullptr;
std::unique_ptr<TooltipControllerTestHelper> helper_;
std::unique_ptr<ui::test::EventGenerator> generator_;
std::unique_ptr<views::Widget> widget_;
@@ -809,8 +757,8 @@ class TooltipControllerTest3 : public ViewsTestBase {
};
TEST_F(TooltipControllerTest3, TooltipPositionChangesOnTwoViewsWithSameLabel) {
- // TODO: these tests use GetContext(). That should go away for aura-mus
- // client. http://crbug.com/663781.
+ // See comment in TooltipControllerTest3::SetUp() for why this does nothing in
+ // mus.
if (IsMus())
return;
diff --git a/chromium/ui/views/event_monitor.h b/chromium/ui/views/event_monitor.h
index 2867ecb14bc..d866e432a83 100644
--- a/chromium/ui/views/event_monitor.h
+++ b/chromium/ui/views/event_monitor.h
@@ -25,9 +25,11 @@ class VIEWS_EXPORT EventMonitor {
// Create an instance for monitoring application events.
// Events will be forwarded to |event_handler| before they are dispatched to
- // the application.
+ // the application. |context| is used to determine where to observer events
+ // from. |context| may be destroyed before the EventMonitor.
static std::unique_ptr<EventMonitor> CreateApplicationMonitor(
- ui::EventHandler* event_handler);
+ ui::EventHandler* event_handler,
+ gfx::NativeWindow context);
// Create an instance for monitoring events on a specific window.
// Events will be forwarded to |event_handler| before they are dispatched to
@@ -39,7 +41,7 @@ class VIEWS_EXPORT EventMonitor {
// Returns the last mouse location seen in a mouse event in screen
// coordinates.
- static gfx::Point GetLastMouseLocation();
+ virtual gfx::Point GetLastMouseLocation() = 0;
};
} // namespace views
diff --git a/chromium/ui/views/event_monitor_aura.cc b/chromium/ui/views/event_monitor_aura.cc
index 6c52620b157..5afde17f3dc 100644
--- a/chromium/ui/views/event_monitor_aura.cc
+++ b/chromium/ui/views/event_monitor_aura.cc
@@ -14,26 +14,25 @@ namespace views {
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor(
- ui::EventHandler* event_handler) {
- return base::WrapUnique(
- new EventMonitorAura(event_handler, aura::Env::GetInstance()));
+ ui::EventHandler* event_handler,
+ gfx::NativeWindow context) {
+ aura::Env* env = context->env();
+ return std::make_unique<EventMonitorAura>(env, event_handler, env);
}
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateWindowMonitor(
ui::EventHandler* event_handler,
gfx::NativeWindow target_window) {
- return base::WrapUnique(new EventMonitorAura(event_handler, target_window));
-}
-
-// static
-gfx::Point EventMonitor::GetLastMouseLocation() {
- return aura::Env::GetInstance()->last_mouse_location();
+ return std::make_unique<EventMonitorAura>(target_window->env(), event_handler,
+ target_window);
}
-EventMonitorAura::EventMonitorAura(ui::EventHandler* event_handler,
+EventMonitorAura::EventMonitorAura(aura::Env* env,
+ ui::EventHandler* event_handler,
ui::EventTarget* event_target)
- : event_handler_(event_handler), event_target_(event_target) {
+ : env_(env), event_handler_(event_handler), event_target_(event_target) {
+ DCHECK(env_);
DCHECK(event_handler_);
DCHECK(event_target_);
event_target_->AddPreTargetHandler(event_handler_);
@@ -43,4 +42,8 @@ EventMonitorAura::~EventMonitorAura() {
event_target_->RemovePreTargetHandler(event_handler_);
}
+gfx::Point EventMonitorAura::GetLastMouseLocation() {
+ return env_->last_mouse_location();
+}
+
} // namespace views
diff --git a/chromium/ui/views/event_monitor_aura.h b/chromium/ui/views/event_monitor_aura.h
index 64f1c48c890..68c633b655a 100644
--- a/chromium/ui/views/event_monitor_aura.h
+++ b/chromium/ui/views/event_monitor_aura.h
@@ -8,6 +8,10 @@
#include "base/macros.h"
#include "ui/views/event_monitor.h"
+namespace aura {
+class Env;
+}
+
namespace ui {
class EventTarget;
}
@@ -16,11 +20,16 @@ namespace views {
class EventMonitorAura : public EventMonitor {
public:
- EventMonitorAura(ui::EventHandler* event_handler,
+ EventMonitorAura(aura::Env* env,
+ ui::EventHandler* event_handler,
ui::EventTarget* event_target);
~EventMonitorAura() override;
+ // EventMonitor:
+ gfx::Point GetLastMouseLocation() override;
+
private:
+ aura::Env* env_; // Weak.
ui::EventHandler* event_handler_; // Weak. Owned by our owner.
ui::EventTarget* event_target_; // Weak.
diff --git a/chromium/ui/views/event_monitor_mac.h b/chromium/ui/views/event_monitor_mac.h
index 3d8fa11b9e5..5cc56a5fef1 100644
--- a/chromium/ui/views/event_monitor_mac.h
+++ b/chromium/ui/views/event_monitor_mac.h
@@ -18,6 +18,9 @@ class EventMonitorMac : public EventMonitor {
gfx::NativeWindow target_window);
~EventMonitorMac() override;
+ // EventMonitor:
+ gfx::Point GetLastMouseLocation() override;
+
private:
id monitor_;
ui::WeakPtrNSObjectFactory<EventMonitorMac> factory_;
diff --git a/chromium/ui/views/event_monitor_mac.mm b/chromium/ui/views/event_monitor_mac.mm
index 85113473e98..46562a63972 100644
--- a/chromium/ui/views/event_monitor_mac.mm
+++ b/chromium/ui/views/event_monitor_mac.mm
@@ -17,7 +17,9 @@ namespace views {
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor(
- ui::EventHandler* event_handler) {
+ ui::EventHandler* event_handler,
+ gfx::NativeWindow context) {
+ // |context| is not needed on Mac.
return base::WrapUnique(new EventMonitorMac(event_handler, nullptr));
}
@@ -28,11 +30,6 @@ std::unique_ptr<EventMonitor> EventMonitor::CreateWindowMonitor(
return base::WrapUnique(new EventMonitorMac(event_handler, target_window));
}
-// static
-gfx::Point EventMonitor::GetLastMouseLocation() {
- return display::Screen::GetScreen()->GetCursorScreenPoint();
-}
-
EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler,
gfx::NativeWindow target_window)
: factory_(this) {
@@ -48,8 +45,13 @@ EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler,
if (!target_window || [event window] == target_window) {
std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event);
- if (ui_event)
+ if (ui_event) {
event_handler->OnEvent(ui_event.get());
+ // If an event is handled, swallow it by returning nil so the event
+ // never proceeds to the normal event handling machinery.
+ if (ui_event->handled())
+ return nil;
+ }
}
return event;
};
@@ -62,4 +64,8 @@ EventMonitorMac::~EventMonitorMac() {
[NSEvent removeMonitor:monitor_];
}
+gfx::Point EventMonitorMac::GetLastMouseLocation() {
+ return display::Screen::GetScreen()->GetCursorScreenPoint();
+}
+
} // namespace views
diff --git a/chromium/ui/views/event_monitor_unittest.cc b/chromium/ui/views/event_monitor_unittest.cc
index fe1f5e0e544..178ef70b56b 100644
--- a/chromium/ui/views/event_monitor_unittest.cc
+++ b/chromium/ui/views/event_monitor_unittest.cc
@@ -46,8 +46,8 @@ class EventMonitorTest : public WidgetTest {
};
TEST_F(EventMonitorTest, ShouldReceiveAppEventsWhileInstalled) {
- std::unique_ptr<EventMonitor> monitor(
- EventMonitor::CreateApplicationMonitor(&handler_));
+ std::unique_ptr<EventMonitor> monitor(EventMonitor::CreateApplicationMonitor(
+ &handler_, widget_->GetNativeWindow()));
generator_->ClickLeftButton();
EXPECT_EQ(2, handler_.num_mouse_events());
@@ -84,8 +84,8 @@ TEST_F(EventMonitorTest, ShouldNotReceiveEventsFromOtherWindow) {
namespace {
class DeleteOtherOnEventHandler : public ui::EventHandler {
public:
- DeleteOtherOnEventHandler() {
- monitor_ = EventMonitor::CreateApplicationMonitor(this);
+ explicit DeleteOtherOnEventHandler(gfx::NativeWindow context) {
+ monitor_ = EventMonitor::CreateApplicationMonitor(this, context);
}
bool DidDelete() const { return !handler_to_delete_; }
@@ -111,16 +111,20 @@ class DeleteOtherOnEventHandler : public ui::EventHandler {
// Ensure correct behavior when an event monitor is removed while iterating
// over the OS-controlled observer list.
TEST_F(EventMonitorTest, TwoMonitors) {
- auto deleter = std::make_unique<DeleteOtherOnEventHandler>();
- deleter->set_monitor_to_delete(std::make_unique<DeleteOtherOnEventHandler>());
+ auto deleter =
+ std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow());
+ deleter->set_monitor_to_delete(
+ std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow()));
EXPECT_FALSE(deleter->DidDelete());
generator_->PressLeftButton();
EXPECT_TRUE(deleter->DidDelete());
// Now try setting up observers in the alternate order.
- auto deletee = std::make_unique<DeleteOtherOnEventHandler>();
- deleter = std::make_unique<DeleteOtherOnEventHandler>();
+ auto deletee =
+ std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow());
+ deleter =
+ std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow());
deleter->set_monitor_to_delete(std::move(deletee));
EXPECT_FALSE(deleter->DidDelete());
diff --git a/chromium/ui/views/examples/bubble_example.cc b/chromium/ui/views/examples/bubble_example.cc
index 026a1032636..a93f6c402a5 100644
--- a/chromium/ui/views/examples/bubble_example.cc
+++ b/chromium/ui/views/examples/bubble_example.cc
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/geometry/insets.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
@@ -89,8 +89,6 @@ void BubbleExample::CreateExampleView(View* container) {
container->AddChildView(small_shadow_);
no_assets_ = new LabelButton(this, ASCIIToUTF16("No Assets"));
container->AddChildView(no_assets_);
- align_to_edge_ = new LabelButton(this, ASCIIToUTF16("Align To Edge"));
- container->AddChildView(align_to_edge_);
persistent_ = new LabelButton(this, ASCIIToUTF16("Persistent"));
container->AddChildView(persistent_);
}
@@ -123,8 +121,6 @@ void BubbleExample::ButtonPressed(Button* sender, const ui::Event& event) {
bubble->set_close_on_deactivate(false);
BubbleDialogDelegateView::CreateBubble(bubble);
- if (sender == align_to_edge_)
- bubble->SetAlignment(BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
bubble->GetWidget()->Show();
}
diff --git a/chromium/ui/views/examples/bubble_example.h b/chromium/ui/views/examples/bubble_example.h
index 91e514db089..6d5717f07aa 100644
--- a/chromium/ui/views/examples/bubble_example.h
+++ b/chromium/ui/views/examples/bubble_example.h
@@ -31,7 +31,6 @@ class VIEWS_EXAMPLES_EXPORT BubbleExample : public ExampleBase,
Button* big_shadow_;
Button* small_shadow_;
Button* no_assets_;
- Button* align_to_edge_;
Button* persistent_;
DISALLOW_COPY_AND_ASSIGN(BubbleExample);
diff --git a/chromium/ui/views/examples/button_sticker_sheet.cc b/chromium/ui/views/examples/button_sticker_sheet.cc
index f1d0099ec9e..1de3940d1af 100644
--- a/chromium/ui/views/examples/button_sticker_sheet.cc
+++ b/chromium/ui/views/examples/button_sticker_sheet.cc
@@ -5,7 +5,6 @@
#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"
@@ -91,13 +90,6 @@ ButtonStickerSheet::~ButtonStickerSheet() {}
void ButtonStickerSheet::CreateExampleView(View* container) {
GridLayout* layout = MakeStretchyGridLayout(container, 3);
- 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(),
diff --git a/chromium/ui/views/examples/dialog_example.cc b/chromium/ui/views/examples/dialog_example.cc
index e10f2fadd5b..7b5ce6b74a5 100644
--- a/chromium/ui/views/examples/dialog_example.cc
+++ b/chromium/ui/views/examples/dialog_example.cc
@@ -6,7 +6,7 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.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"
diff --git a/chromium/ui/views/features.gni b/chromium/ui/views/features.gni
index e5222f85d37..16b8660ad2e 100644
--- a/chromium/ui/views/features.gni
+++ b/chromium/ui/views/features.gni
@@ -2,12 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/config/linux/gtk/gtk.gni")
import("//build/config/ui.gni")
declare_args() {
# Whether we should draw the minimize, maximize/restore, and close
- # buttons using the system theme. Only used on Linux with GTK3.
- enable_native_window_nav_buttons =
- use_aura && !use_ozone && is_desktop_linux && use_gtk3
+ # buttons using the system theme. Only used on Linux.
+ enable_native_window_nav_buttons = use_aura && !use_ozone && is_desktop_linux
}
diff --git a/chromium/ui/views/focus/focus_manager.h b/chromium/ui/views/focus/focus_manager.h
index c5fb037312d..d36ac497473 100644
--- a/chromium/ui/views/focus/focus_manager.h
+++ b/chromium/ui/views/focus/focus_manager.h
@@ -359,7 +359,8 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
FocusChangeReason focus_change_reason_ = kReasonDirectFocusChange;
// The list of registered FocusChange listeners.
- base::ObserverList<FocusChangeListener, true> focus_change_listeners_;
+ base::ObserverList<FocusChangeListener, true>::Unchecked
+ focus_change_listeners_;
// This is true if full keyboard accessibility is needed. This causes
// IsAccessibilityFocusable() to be checked rather than IsFocusable(). This
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index 5e7c7a6778e..ed29e91704b 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -17,7 +17,7 @@
#include "ui/base/accelerators/test_accelerator_target.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/accessible_pane_view.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/focus/focus_manager_delegate.h"
#include "ui/views/focus/focus_manager_factory.h"
#include "ui/views/focus/widget_focus_manager.h"
diff --git a/chromium/ui/views/focus/focus_search.cc b/chromium/ui/views/focus/focus_search.cc
index 4c33f0b266e..c0e33176e20 100644
--- a/chromium/ui/views/focus/focus_search.cc
+++ b/chromium/ui/views/focus/focus_search.cc
@@ -5,7 +5,7 @@
#include "ui/views/focus/focus_search.h"
#include "base/logging.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h"
#include "ui/views/view_properties.h"
diff --git a/chromium/ui/views/focus/widget_focus_manager.h b/chromium/ui/views/focus/widget_focus_manager.h
index deaaab447ce..068a4825b46 100644
--- a/chromium/ui/views/focus/widget_focus_manager.h
+++ b/chromium/ui/views/focus/widget_focus_manager.h
@@ -55,7 +55,8 @@ class VIEWS_EXPORT WidgetFocusManager {
WidgetFocusManager();
~WidgetFocusManager();
- base::ObserverList<WidgetFocusChangeListener> focus_change_listeners_;
+ base::ObserverList<WidgetFocusChangeListener>::Unchecked
+ focus_change_listeners_;
bool enabled_;
diff --git a/chromium/ui/views/layout/box_layout.cc b/chromium/ui/views/layout/box_layout.cc
index d0d5624bf24..f9c1b6dc485 100644
--- a/chromium/ui/views/layout/box_layout.cc
+++ b/chromium/ui/views/layout/box_layout.cc
@@ -165,19 +165,19 @@ void BoxLayout::Layout(View* host) {
total_main_axis_size -= between_child_spacing_;
// Free space can be negative indicating that the views want to overflow.
int main_free_space = MainAxisSize(child_area) - total_main_axis_size;
+ int main_position = MainAxisPosition(child_area);
{
- int position = MainAxisPosition(child_area);
int size = MainAxisSize(child_area);
if (!flex_sum) {
switch (main_axis_alignment_) {
case MAIN_AXIS_ALIGNMENT_START:
break;
case MAIN_AXIS_ALIGNMENT_CENTER:
- position += main_free_space / 2;
+ main_position += main_free_space / 2;
size = total_main_axis_size;
break;
case MAIN_AXIS_ALIGNMENT_END:
- position += main_free_space;
+ main_position += main_free_space;
size = total_main_axis_size;
break;
default:
@@ -186,12 +186,11 @@ void BoxLayout::Layout(View* host) {
}
}
gfx::Rect new_child_area(child_area);
- SetMainAxisPosition(position, &new_child_area);
+ SetMainAxisPosition(main_position, &new_child_area);
SetMainAxisSize(size, &new_child_area);
child_area.Intersect(new_child_area);
}
- int main_position = MainAxisPosition(child_area);
int total_padding = 0;
int current_flex = 0;
for (int i = 0; i < host->child_count(); ++i) {
diff --git a/chromium/ui/views/layout/box_layout.h b/chromium/ui/views/layout/box_layout.h
index 315ac561859..653d810eb9e 100644
--- a/chromium/ui/views/layout/box_layout.h
+++ b/chromium/ui/views/layout/box_layout.h
@@ -33,9 +33,10 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
kVertical,
};
- // This specifies where along the main axis the children should be laid out.
- // e.g. a horizontal layout of MAIN_AXIS_ALIGNMENT_END will result in the
- // child views being right-aligned.
+ // This specifies that the start/center/end of the collective child views is
+ // aligned with the start/center/end of the host view. e.g. a horizontal
+ // layout of MAIN_AXIS_ALIGNMENT_END will result in the child views being
+ // right-aligned.
enum MainAxisAlignment {
MAIN_AXIS_ALIGNMENT_START,
MAIN_AXIS_ALIGNMENT_CENTER,
diff --git a/chromium/ui/views/layout/box_layout_unittest.cc b/chromium/ui/views/layout/box_layout_unittest.cc
index 676109da968..b500e89c2ff 100644
--- a/chromium/ui/views/layout/box_layout_unittest.cc
+++ b/chromium/ui/views/layout/box_layout_unittest.cc
@@ -102,29 +102,30 @@ TEST_F(BoxLayoutTest, Overflow) {
host_->AddChildView(v1);
View* v2 = new StaticSizedView(gfx::Size(10, 20));
host_->AddChildView(v2);
- host_->SetBounds(0, 0, 10, 10);
+ host_->SetBounds(0, 0, 15, 10);
// Overflows by positioning views at the start and truncating anything that
// doesn't fit.
host_->Layout();
- EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 15, 10), v1->bounds());
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
- // All values of main axis alignment should overflow in the same manner.
+ // Clipping of children should occur at the opposite end(s) to the main axis
+ // alignment position.
layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
host_->Layout();
- EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 15, 10), v1->bounds());
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
host_->Layout();
- EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
- EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 13, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(13, 0, 2, 10), v2->bounds());
layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
host_->Layout();
- EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
- EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
+ EXPECT_EQ(gfx::Rect(0, 0, 5, 10), v1->bounds());
+ EXPECT_EQ(gfx::Rect(5, 0, 10, 10), v2->bounds());
}
TEST_F(BoxLayoutTest, NoSpace) {
diff --git a/chromium/ui/views/layout/layout_provider.cc b/chromium/ui/views/layout/layout_provider.cc
index caba8a5228e..310d695c175 100644
--- a/chromium/ui/views/layout/layout_provider.cc
+++ b/chromium/ui/views/layout/layout_provider.cc
@@ -166,8 +166,9 @@ int LayoutProvider::GetShadowElevationMetric(
return 3;
}
-gfx::ShadowValues LayoutProvider::MakeShadowValues(int elevation) const {
- return gfx::ShadowValue::MakeMdShadowValues(elevation);
+gfx::ShadowValues LayoutProvider::MakeShadowValues(int elevation,
+ SkColor color) const {
+ return gfx::ShadowValue::MakeMdShadowValues(elevation, color);
}
} // namespace views
diff --git a/chromium/ui/views/layout/layout_provider.h b/chromium/ui/views/layout/layout_provider.h
index cf92ab718c9..c7f194643de 100644
--- a/chromium/ui/views/layout/layout_provider.h
+++ b/chromium/ui/views/layout/layout_provider.h
@@ -175,7 +175,8 @@ class VIEWS_EXPORT LayoutProvider {
// Creates shadows for the given elevation. Use GetShadowElevationMetric for
// the appropriate elevation.
- virtual gfx::ShadowValues MakeShadowValues(int elevation) const;
+ virtual gfx::ShadowValues MakeShadowValues(int elevation,
+ SkColor color) const;
private:
DefaultTypographyProvider typography_provider_;
diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h
index c1f14d5c65a..86a3c0a78cb 100644
--- a/chromium/ui/views/linux_ui/linux_ui.h
+++ b/chromium/ui/views/linux_ui/linux_ui.h
@@ -57,11 +57,6 @@ class NavButtonProvider;
// Adapter class with targets to render like different toolkits. Set by any
// project that wants to do linux desktop native rendering.
-//
-// TODO(erg): We're hardcoding GTK2, when we'll need to have backends for (at
-// minimum) GTK2 and GTK3. LinuxUI::instance() should actually be a very
-// complex method that pokes around with dlopen against a libuigtk2.so, a
-// liuigtk3.so, etc.
class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
public gfx::LinuxFontDelegate,
public ui::ShellDialogLinux,
diff --git a/chromium/ui/views/mouse_watcher.cc b/chromium/ui/views/mouse_watcher.cc
index e0c1a3bb44b..5a91062a11b 100644
--- a/chromium/ui/views/mouse_watcher.cc
+++ b/chromium/ui/views/mouse_watcher.cc
@@ -26,11 +26,10 @@ const int kNotifyListenerTimeMs = 300;
class MouseWatcher::Observer : public ui::EventHandler {
public:
- explicit Observer(MouseWatcher* mouse_watcher)
+ Observer(MouseWatcher* mouse_watcher, gfx::NativeWindow window)
: mouse_watcher_(mouse_watcher),
- event_monitor_(EventMonitor::CreateApplicationMonitor(this)),
- notify_listener_factory_(this) {
- }
+ event_monitor_(EventMonitor::CreateApplicationMonitor(this, window)),
+ notify_listener_factory_(this) {}
// ui::EventHandler implementation:
void OnMouseEvent(ui::MouseEvent* event) override {
@@ -57,7 +56,7 @@ class MouseWatcher::Observer : public ui::EventHandler {
void HandleMouseEvent(MouseWatcherHost::MouseEventType event_type) {
// It's safe to use last_mouse_location() here as this function is invoked
// during event dispatching.
- if (!host()->Contains(EventMonitor::GetLastMouseLocation(), event_type)) {
+ if (!host()->Contains(event_monitor_->GetLastMouseLocation(), event_type)) {
if (event_type == MouseWatcherHost::MOUSE_PRESS) {
NotifyListener();
} else if (!notify_listener_factory_.HasWeakPtrs()) {
@@ -109,9 +108,9 @@ MouseWatcher::MouseWatcher(std::unique_ptr<MouseWatcherHost> host,
MouseWatcher::~MouseWatcher() {
}
-void MouseWatcher::Start() {
+void MouseWatcher::Start(gfx::NativeWindow window) {
if (!is_observing())
- observer_ = std::make_unique<Observer>(this);
+ observer_ = std::make_unique<Observer>(this, window);
}
void MouseWatcher::Stop() {
diff --git a/chromium/ui/views/mouse_watcher.h b/chromium/ui/views/mouse_watcher.h
index c9edf322030..d27dc0928e9 100644
--- a/chromium/ui/views/mouse_watcher.h
+++ b/chromium/ui/views/mouse_watcher.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/time/time.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -65,8 +66,10 @@ class VIEWS_EXPORT MouseWatcher {
// Starts watching mouse movements. When the mouse moves outside the bounds of
// the host the listener is notified. |Start| may be invoked any number of
// times. If the mouse moves outside the bounds of the host the listener is
- // notified and watcher stops watching events.
- void Start();
+ // notified and watcher stops watching events. |window| must be a window in
+ // the hierarchy related to the host. |window| is used to setup initial state,
+ // and may be deleted before MouseWatcher.
+ void Start(gfx::NativeWindow window);
// Stops watching mouse events.
void Stop();
diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn
index 0c9092d362b..883a69b8bbb 100644
--- a/chromium/ui/views/mus/BUILD.gn
+++ b/chromium/ui/views/mus/BUILD.gn
@@ -45,7 +45,7 @@ jumbo_component("mus") {
public_deps = [
":resources",
- "//services/ui/public/cpp",
+ "//services/ws/public/cpp",
"//ui/aura",
]
deps = [
@@ -59,9 +59,9 @@ jumbo_component("mus") {
"//services/catalog/public/mojom:constants",
"//services/service_manager/public/cpp",
"//services/service_manager/public/mojom",
- "//services/ui/public/cpp",
- "//services/ui/public/cpp/input_devices",
- "//services/ui/public/interfaces",
+ "//services/ws/public/cpp",
+ "//services/ws/public/cpp/input_devices",
+ "//services/ws/public/mojom",
"//skia",
"//third_party/icu",
"//ui/accessibility",
@@ -126,7 +126,7 @@ jumbo_static_library("test_support") {
"//services/catalog:lib",
"//services/service_manager/background:lib",
"//services/service_manager/public/cpp",
- "//services/ui/common:mus_common",
+ "//services/ws/common",
"//testing/gtest",
"//ui/aura",
"//ui/aura:test_support",
@@ -144,7 +144,7 @@ jumbo_static_library("test_support") {
data_deps = [
":views_mus_tests_catalog",
- "//services/ui/ime/test_ime_driver",
+ "//services/ws/ime/test_ime_driver",
"//ui/resources:ui_test_pak_data",
]
}
@@ -171,7 +171,7 @@ test("views_mus_unittests") {
"//base/test:test_support",
"//cc",
"//net",
- "//services/ui/public/interfaces",
+ "//services/ws/public/mojom",
"//skia",
"//testing/gtest",
"//third_party/icu",
@@ -202,8 +202,8 @@ test("views_mus_unittests") {
data_deps = [
":views_mus_tests_catalog_copy",
- "//services/ui/ime/test_ime_driver",
- "//services/ui/test_ws",
+ "//services/ws/ime/test_ime_driver",
+ "//services/ws/test_ws",
]
if (is_win) {
@@ -269,7 +269,7 @@ test("views_mus_interactive_ui_tests") {
data_deps = [
":views_mus_tests_catalog_copy",
- "//services/ui/test_ws",
+ "//services/ws/test_ws",
]
if (is_win) {
@@ -305,8 +305,8 @@ catalog("views_mus_tests_catalog") {
]
standalone_services = [
- "//services/ui/test_ws:manifest",
- "//services/ui/ime/test_ime_driver:manifest",
+ "//services/ws/test_ws:manifest",
+ "//services/ws/ime/test_ime_driver:manifest",
]
}
diff --git a/chromium/ui/views/mus/DEPS b/chromium/ui/views/mus/DEPS
index 8953b55dfbd..6c5f22db116 100644
--- a/chromium/ui/views/mus/DEPS
+++ b/chromium/ui/views/mus/DEPS
@@ -7,7 +7,7 @@ include_rules = [
"+mojo/public",
"+services/catalog",
"+services/service_manager/public",
- "+services/ui",
+ "+services/ws",
"+skia",
"+ui/aura",
"+ui/base",
diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc
index 56b6c3c0a1f..c6c4966ef68 100644
--- a/chromium/ui/views/mus/aura_init.cc
+++ b/chromium/ui/views/mus/aura_init.cc
@@ -46,19 +46,13 @@ std::unique_ptr<AuraInit> AuraInit::Create(const InitParams& params) {
bool AuraInit::Init(const InitParams& params) {
env_ = aura::Env::CreateInstance(aura::Env::Mode::MUS);
- if (params.mode == Mode::AURA_MUS || params.mode == Mode::AURA_MUS2) {
- MusClient::InitParams mus_params;
- mus_params.connector = params.connector;
- mus_params.identity = params.identity;
- mus_params.io_task_runner = params.io_task_runner;
- mus_params.wtc_config =
- params.mode == Mode::AURA_MUS2
- ? aura::WindowTreeClient::Config::kMus2
- : aura::WindowTreeClient::Config::kMashDeprecated;
- mus_params.create_wm_state = true;
- mus_params.use_accessibility_host = params.use_accessibility_host;
- mus_client_ = std::make_unique<MusClient>(mus_params);
- }
+ MusClient::InitParams mus_params;
+ mus_params.connector = params.connector;
+ mus_params.identity = params.identity;
+ mus_params.io_task_runner = params.io_task_runner;
+ mus_params.create_wm_state = true;
+ mus_params.use_accessibility_host = params.use_accessibility_host;
+ mus_client_ = std::make_unique<MusClient>(mus_params);
// MaterialDesignController may have initialized already (such as happens
// in the utility process).
if (!ui::MaterialDesignController::is_mode_initialized())
diff --git a/chromium/ui/views/mus/aura_init.h b/chromium/ui/views/mus/aura_init.h
index c821deae031..dad4d1f42c9 100644
--- a/chromium/ui/views/mus/aura_init.h
+++ b/chromium/ui/views/mus/aura_init.h
@@ -33,20 +33,6 @@ class ViewsDelegate;
// |resource_file| is the path to the apk file containing the resources.
class VIEWS_MUS_EXPORT AuraInit {
public:
- // TODO(sky): remove Mode. https://crbug.com/842365.
- enum class Mode {
- // Indicates AuraInit should target using aura with mus. This is deprecated.
- AURA_MUS,
-
- // Indicates AuraInit should target using aura with mus, for a Window
- // Manager client. This is deprecated.
- AURA_MUS_WINDOW_MANAGER,
-
- // Targets ws2. Mode will eventually be removed entirely and this will be
- // the default.
- AURA_MUS2,
- };
-
~AuraInit();
struct VIEWS_MUS_EXPORT InitParams {
@@ -59,7 +45,6 @@ class VIEWS_MUS_EXPORT AuraInit {
// File for 2x icons. Can be empty.
std::string resource_file_200;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = nullptr;
- Mode mode = Mode::AURA_MUS;
bool register_path_provider = true;
// When true the client application will connect to the accessibility host
// in the browser to supply AX node trees and handle AX actions (e.g. to
@@ -72,7 +57,6 @@ class VIEWS_MUS_EXPORT AuraInit {
// unusable state, and calling services should shutdown.
static std::unique_ptr<AuraInit> Create(const InitParams& params);
- // Only valid if Mode::AURA_MUS was passed to constructor.
MusClient* mus_client() { return mus_client_.get(); }
private:
diff --git a/chromium/ui/views/mus/ax_remote_host.cc b/chromium/ui/views/mus/ax_remote_host.cc
index bc1d4edb33e..0affab635ac 100644
--- a/chromium/ui/views/mus/ax_remote_host.cc
+++ b/chromium/ui/views/mus/ax_remote_host.cc
@@ -11,7 +11,10 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_event.h"
#include "ui/accessibility/platform/ax_unique_id.h"
+#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/mus/ax_tree_source_mus.h"
#include "ui/views/mus/mus_client.h"
@@ -19,6 +22,9 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
+using display::Display;
+using display::Screen;
+
namespace views {
// For external linkage.
@@ -51,7 +57,8 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
// Check if we're already tracking a widget.
// TODO(jamescook): Support multiple widgets.
if (widget_)
- return;
+ StopMonitoringWidget();
+
widget_ = widget;
widget_->AddObserver(this);
@@ -67,12 +74,17 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
tree_source_ = std::make_unique<AXTreeSourceMus>(contents_wrapper);
tree_serializer_ = std::make_unique<AuraAXTreeSerializer>(tree_source_.get());
+ // Inform the serializer of the display device scale factor.
+ UpdateDeviceScaleFactor();
+ Screen::GetScreen()->AddObserver(this);
+
SendEvent(contents_wrapper, ax::mojom::Event::kLoadComplete);
}
void AXRemoteHost::StopMonitoringWidget() {
DCHECK(widget_);
DCHECK(widget_->HasObserver(this));
+ Screen::GetScreen()->RemoveObserver(this);
widget_->RemoveObserver(this);
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
cache->OnRootWindowObjDestroyed(widget_->GetNativeWindow());
@@ -100,20 +112,47 @@ void AXRemoteHost::OnAutomationEnabled(bool enabled) {
Disable();
}
-void AXRemoteHost::PerformAction(const ui::AXActionData& action) {
- // TODO(jamescook): Support ax::mojom::Action::kHitTest.
- tree_source_->HandleAccessibleAction(action);
+void AXRemoteHost::PerformAction(const ui::AXActionData& action_data) {
+ if (!enabled_)
+ return;
+
+ // A hit test requires determining the node to perform the action on first.
+ if (action_data.action == ax::mojom::Action::kHitTest) {
+ PerformHitTest(action_data);
+ return;
+ }
+
+ tree_source_->HandleAccessibleAction(action_data);
+}
+
+void AXRemoteHost::OnWidgetClosing(Widget* widget) {
+ // In the typical case, clean up early during widget close. Waiting until
+ // widget destroy can sometimes lead to crashes due to AX window visibility
+ // events being triggered during close. https://crbug.com/869608
+ DCHECK_EQ(widget_, widget);
+ StopMonitoringWidget();
}
void AXRemoteHost::OnWidgetDestroying(Widget* widget) {
+ // Widgets can be deleted without being closed, which is common in tests
+ // and possible in production.
DCHECK_EQ(widget_, widget);
StopMonitoringWidget();
}
+void AXRemoteHost::OnDisplayMetricsChanged(const Display& display,
+ uint32_t metrics) {
+ if (metrics & display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR) {
+ UpdateDeviceScaleFactor();
+ SendEvent(tree_source_->GetRoot(), ax::mojom::Event::kLocationChanged);
+ }
+}
+
void AXRemoteHost::OnChildWindowRemoved(AXAuraObjWrapper* parent) {
- if (!enabled_)
+ if (!enabled_ || !widget_)
return;
+ DCHECK(tree_source_);
if (!parent)
parent = tree_source_->GetRoot();
@@ -136,24 +175,25 @@ void AXRemoteHost::BindAndSetRemote() {
}
void AXRemoteHost::Enable() {
- // Extensions can send multiple enable events.
- if (enabled_)
- return;
+ // Don't early-exit if already enabled. AXRemoteHost can start up in the
+ // "enabled" state even if ChromeVox is on at the moment the app launches.
+ // Turning on ChromeVox later will generate another OnAutomationEnabled()
+ // call and we need to serialize the node tree again. This is similar to
+ // AutomationManagerAura's behavior. https://crbug.com/876407
enabled_ = true;
std::set<aura::Window*> roots =
MusClient::Get()->window_tree_client()->GetRoots();
- if (roots.empty()) {
- // Client hasn't opened any widgets yet.
- return;
+ for (aura::Window* root : roots) {
+ Widget* widget = Widget::GetWidgetForNativeWindow(root);
+ // Typically it's only tests that create Windows (the WindowTreeHost
+ // backing the root Window) in such a way that there is no associated
+ // widget.
+ if (widget) {
+ // TODO(jamescook): Support multiple roots.
+ StartMonitoringWidget(widget);
+ }
}
-
- // TODO(jamescook): Support multiple roots.
- aura::Window* root_window = *roots.begin();
- DCHECK(root_window);
- Widget* root_widget = Widget::GetWidgetForNativeWindow(root_window);
- DCHECK(root_widget);
- StartMonitoringWidget(root_widget);
}
void AXRemoteHost::Disable() {
@@ -165,9 +205,13 @@ void AXRemoteHost::Disable() {
void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
ax::mojom::Event event_type) {
- if (!enabled_ || !tree_serializer_)
+ DCHECK(aura_obj);
+ if (!enabled_ || !widget_)
return;
+ DCHECK(tree_source_);
+ DCHECK(tree_serializer_);
+
ui::AXTreeUpdate update;
if (!tree_serializer_->SerializeChanges(aura_obj, &update)) {
LOG(ERROR) << "Unable to serialize accessibility tree.";
@@ -193,4 +237,28 @@ void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
ax_host_ptr_->HandleAccessibilityEvent(kRemoteAXTreeID, updates, event);
}
+void AXRemoteHost::PerformHitTest(const ui::AXActionData& action) {
+ DCHECK(enabled_);
+ DCHECK_EQ(action.action, ax::mojom::Action::kHitTest);
+
+ // If the widget isn't open yet there's nothing to hit.
+ if (!widget_)
+ return;
+
+ views::View* hit_view =
+ widget_->GetRootView()->GetEventHandlerForPoint(action.target_point);
+ if (hit_view)
+ hit_view->NotifyAccessibilityEvent(action.hit_test_event_to_fire, true);
+}
+
+void AXRemoteHost::UpdateDeviceScaleFactor() {
+ DCHECK(widget_);
+ DCHECK(tree_source_);
+
+ // Use the scale factor for the widget's window's current display.
+ Display display =
+ Screen::GetScreen()->GetDisplayNearestWindow(widget_->GetNativeWindow());
+ tree_source_->set_device_scale_factor(display.device_scale_factor());
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/ax_remote_host.h b/chromium/ui/views/mus/ax_remote_host.h
index f213060ab95..7e506159487 100644
--- a/chromium/ui/views/mus/ax_remote_host.h
+++ b/chromium/ui/views/mus/ax_remote_host.h
@@ -12,6 +12,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/mojom/ax_host.mojom.h"
+#include "ui/display/display_observer.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/widget/widget_observer.h"
@@ -37,6 +38,7 @@ class Widget;
// (e.g. the keyboard shortcut viewer app).
class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
public WidgetObserver,
+ public display::DisplayObserver,
public AXAuraObjCache::Delegate {
public:
// Well-known tree ID for the remote client.
@@ -65,14 +67,20 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void PerformAction(const ui::AXActionData& action) override;
// WidgetObserver:
+ void OnWidgetClosing(Widget* widget) override;
void OnWidgetDestroying(Widget* widget) override;
+ // display::DisplayObserver:
+ void OnDisplayMetricsChanged(const display::Display& display,
+ uint32_t changed_metrics) override;
+
// AXAuraObjCache::Delegate:
void OnChildWindowRemoved(AXAuraObjWrapper* parent) override;
void OnEvent(AXAuraObjWrapper* aura_obj,
ax::mojom::Event event_type) override;
void FlushForTesting();
+ Widget* widget_for_testing() { return widget_; }
private:
// Registers this object as a remote host for the parent AXHost.
@@ -84,6 +92,11 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
// Sends an event to the host.
void SendEvent(AXAuraObjWrapper* aura_obj, ax::mojom::Event event_type);
+ void PerformHitTest(const ui::AXActionData& action);
+
+ // Updates the display device scale factor used when serializing nodes.
+ void UpdateDeviceScaleFactor();
+
// Accessibility host service in the browser.
ax::mojom::AXHostPtr ax_host_ptr_;
diff --git a/chromium/ui/views/mus/ax_remote_host_unittest.cc b/chromium/ui/views/mus/ax_remote_host_unittest.cc
index cf93bb3d11e..fd187350140 100644
--- a/chromium/ui/views/mus/ax_remote_host_unittest.cc
+++ b/chromium/ui/views/mus/ax_remote_host_unittest.cc
@@ -5,10 +5,15 @@
#include "ui/views/mus/ax_remote_host.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/mojom/ax_host.mojom.h"
+#include "ui/display/display.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/mus/mus_client_test_api.h"
+#include "ui/views/mus/screen_mus.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -29,6 +34,14 @@ class TestAXHostService : public ax::mojom::AXHost {
return ptr;
}
+ void ResetCounts() {
+ add_client_count_ = 0;
+ event_count_ = 0;
+ last_tree_id_ = 0;
+ last_updates_.clear();
+ last_event_ = ui::AXEvent();
+ }
+
// ax::mojom::AXHost:
void SetRemoteHost(ax::mojom::AXRemoteHostPtr client) override {
++add_client_count_;
@@ -40,6 +53,7 @@ class TestAXHostService : public ax::mojom::AXHost {
const ui::AXEvent& event) override {
++event_count_;
last_tree_id_ = tree_id;
+ last_updates_ = updates;
last_event_ = event;
}
@@ -48,6 +62,7 @@ class TestAXHostService : public ax::mojom::AXHost {
int add_client_count_ = 0;
int event_count_ = 0;
int last_tree_id_ = 0;
+ std::vector<ui::AXTreeUpdate> last_updates_;
ui::AXEvent last_event_;
private:
@@ -57,18 +72,31 @@ class TestAXHostService : public ax::mojom::AXHost {
// TestView senses accessibility actions.
class TestView : public View {
public:
- TestView() = default;
+ TestView() { set_owned_by_client(); }
~TestView() override = default;
+ void ResetCounts() {
+ action_count_ = 0;
+ last_action_ = {};
+ event_count_ = 0;
+ last_event_type_ = ax::mojom::Event::kNone;
+ }
+
// View:
bool HandleAccessibleAction(const ui::AXActionData& action) override {
++action_count_;
last_action_ = action;
return true;
}
+ void OnAccessibilityEvent(ax::mojom::Event event_type) override {
+ ++event_count_;
+ last_event_type_ = event_type;
+ }
int action_count_ = 0;
ui::AXActionData last_action_;
+ int event_count_ = 0;
+ ax::mojom::Event last_event_type_ = ax::mojom::Event::kNone;
private:
DISALLOW_COPY_AND_ASSIGN(TestView);
@@ -115,6 +143,28 @@ TEST_F(AXRemoteHostTest, AutomationEnabled) {
service.last_event_.id);
}
+// Regression test for https://crbug.com/876407
+TEST_F(AXRemoteHostTest, AutomationEnabledTwice) {
+ // If ChromeVox has ever been open during the user session then the remote app
+ // can see automation enabled at startup.
+ TestAXHostService service(true /*automation_enabled*/);
+ AXRemoteHost* remote = CreateRemote(&service);
+ std::unique_ptr<Widget> widget = CreateTestWidget();
+ remote->FlushForTesting();
+
+ // Remote host sent load complete.
+ EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type);
+ service.ResetCounts();
+
+ // Simulate host service asking to enable again. This happens if ChromeVox is
+ // re-enabled after the remote app is open.
+ remote->OnAutomationEnabled(true);
+ remote->FlushForTesting();
+
+ // Load complete was sent again after the second enable.
+ EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type);
+}
+
// Views can trigger accessibility events during Widget construction before the
// AXRemoteHost starts monitoring the widget. This happens with the material
// design focus ring on text fields. Verify we don't crash in this case.
@@ -127,6 +177,34 @@ TEST_F(AXRemoteHostTest, SendEventBeforeWidgetCreated) {
// No crash.
}
+// Verifies that the AXRemoteHost stops monitoring widgets that are closed
+// asynchronously, like when ash requests close via DesktopWindowTreeHostMus.
+// https://crbug.com/869608
+TEST_F(AXRemoteHostTest, AsyncWidgetClose) {
+ TestAXHostService service(true /*automation_enabled*/);
+ AXRemoteHost* remote = CreateRemote(&service);
+ remote->FlushForTesting();
+
+ Widget* widget = new Widget(); // Owned by native widget.
+ Widget::InitParams params;
+ params.bounds = gfx::Rect(1, 2, 333, 444);
+ widget->Init(params);
+ widget->Show();
+
+ // AXRemoteHost is tracking the widget.
+ EXPECT_TRUE(remote->widget_for_testing());
+
+ // Asynchronously close the widget using Close() instead of CloseNow().
+ widget->Close();
+
+ // AXRemoteHost stops tracking the widget, even though it isn't destroyed yet.
+ EXPECT_FALSE(remote->widget_for_testing());
+
+ // Widget finishes closing.
+ base::RunLoop().RunUntilIdle();
+ // No crash.
+}
+
TEST_F(AXRemoteHostTest, CreateWidgetThenEnableAutomation) {
TestAXHostService service(false /*automation_enabled*/);
AXRemoteHost* remote = CreateRemote(&service);
@@ -165,5 +243,60 @@ TEST_F(AXRemoteHostTest, PerformAction) {
EXPECT_EQ(ax::mojom::Action::kScrollDown, view.last_action_.action);
}
+TEST_F(AXRemoteHostTest, PerformHitTest) {
+ TestAXHostService service(true /*automation_enabled*/);
+ AXRemoteHost* remote = CreateRemote(&service);
+
+ // Create a view to sense the action.
+ TestView view;
+ view.SetBounds(0, 0, 100, 100);
+ std::unique_ptr<Widget> widget = CreateTestWidget();
+ widget->GetRootView()->AddChildView(&view);
+
+ // Clear event counts triggered by view creation and bounds set.
+ view.ResetCounts();
+
+ // Request a hit test.
+ ui::AXActionData action;
+ action.action = ax::mojom::Action::kHitTest;
+ action.hit_test_event_to_fire = ax::mojom::Event::kHitTestResult;
+ action.target_point = gfx::Point(5, 5);
+ remote->PerformAction(action);
+
+ // View sensed a hit.
+ EXPECT_EQ(1, view.event_count_);
+ EXPECT_EQ(ax::mojom::Event::kHitTestResult, view.last_event_type_);
+ view.ResetCounts();
+
+ // Try to hit a point outside the view.
+ action.target_point = gfx::Point(101, 101);
+ remote->PerformAction(action);
+
+ // View wasn't hit.
+ EXPECT_EQ(0, view.event_count_);
+ EXPECT_EQ(ax::mojom::Event::kNone, view.last_event_type_);
+}
+
+TEST_F(AXRemoteHostTest, ScaleFactor) {
+ // Set the primary display to high DPI.
+ ScreenMus* screen = static_cast<ScreenMus*>(display::Screen::GetScreen());
+ display::Display display = screen->GetPrimaryDisplay();
+ display.set_device_scale_factor(2.f);
+ screen->display_list().UpdateDisplay(display);
+
+ // Create a widget.
+ TestAXHostService service(true /*automation_enabled*/);
+ AXRemoteHost* remote = CreateRemote(&service);
+ std::unique_ptr<Widget> widget = CreateTestWidget();
+ remote->FlushForTesting();
+
+ // Widget transform is scaled by a factor of 2.
+ ASSERT_FALSE(service.last_updates_.empty());
+ gfx::Transform* transform = service.last_updates_[0].nodes[0].transform.get();
+ ASSERT_TRUE(transform);
+ EXPECT_TRUE(transform->IsScale2d());
+ EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), transform->Scale2d());
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.cc b/chromium/ui/views/mus/ax_tree_source_mus.cc
index 6acef96a413..7f767c443f6 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus.cc
@@ -34,7 +34,15 @@ void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node,
// However, the contents view in the host (browser) already has an offset
// from its Widget, so the root should start at (0,0).
out_data->location.set_origin(gfx::PointF());
- out_data->transform.reset();
+
+ // Adjust for display device scale factor.
+ if (device_scale_factor_ == 1.f) {
+ // The AX system represents the identity transform with null.
+ out_data->transform.reset();
+ } else {
+ out_data->transform = std::make_unique<gfx::Transform>();
+ out_data->transform->Scale(device_scale_factor_, device_scale_factor_);
+ }
return;
}
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.h b/chromium/ui/views/mus/ax_tree_source_mus.h
index 340f14271d9..6e3681e0773 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.h
+++ b/chromium/ui/views/mus/ax_tree_source_mus.h
@@ -23,6 +23,8 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
explicit AXTreeSourceMus(AXAuraObjWrapper* root);
~AXTreeSourceMus() override;
+ void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
+
// AXTreeSource:
bool GetTreeData(ui::AXTreeData* data) const override;
AXAuraObjWrapper* GetRoot() const override;
@@ -33,6 +35,9 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
// The top-level object to use for the AX tree.
AXAuraObjWrapper* root_;
+ // The display device scale factor to use while serializing this update.
+ float device_scale_factor_ = 1.f;
+
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMus);
};
diff --git a/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc b/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
index d652b04712e..2f7bc9a6299 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
@@ -12,6 +12,8 @@
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/controls/label.h"
@@ -86,5 +88,23 @@ TEST_F(AXTreeSourceMusTest, Serialize) {
EXPECT_EQ(root->GetUniqueId().Get(), node_data.offset_container_id);
}
+TEST_F(AXTreeSourceMusTest, ScaleFactor) {
+ AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
+ AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
+
+ // Simulate serializing a widget on a high-dpi display.
+ AXTreeSourceMus tree(root);
+ tree.set_device_scale_factor(2.f);
+
+ // Serialize the root.
+ ui::AXNodeData node_data;
+ tree.SerializeNode(root, &node_data);
+
+ // Transform is scaled.
+ ASSERT_TRUE(node_data.transform);
+ EXPECT_TRUE(node_data.transform->IsScale2d());
+ EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), node_data.transform->Scale2d());
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
index 67be4ae4d87..93d30122d2a 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -44,13 +44,16 @@ namespace {
// As the window manager renderers the non-client decorations this class does
// very little but honor the client area insets from the window manager.
-class ClientSideNonClientFrameView : public NonClientFrameView {
+class ClientSideNonClientFrameView : public NonClientFrameView,
+ public aura::WindowObserver {
public:
explicit ClientSideNonClientFrameView(views::Widget* widget)
: widget_(widget) {
// Not part of the accessibility node hierarchy because the window frame is
// provided by the window manager.
GetViewAccessibility().set_is_ignored(true);
+
+ observed_.Add(widget_->GetNativeWindow()->GetRootWindow());
}
~ClientSideNonClientFrameView() override {}
@@ -125,7 +128,30 @@ class ClientSideNonClientFrameView : public NonClientFrameView {
max_size.height() == 0 ? 0 : converted_size.height());
}
+ // aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override {
+ observed_.Remove(window);
+ }
+
+ void OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) override {
+ // Do a re-layout on state changes which affect GetBoundsForClientView().
+ // The associated bounds change would also cause a re-layout, but there may
+ // not be a bounds change or it may come from the server before the state is
+ // updated.
+ if (key == aura::client::kShowStateKey) {
+ if (GetBoundsForClientView() != widget_->client_view()->bounds() &&
+ window->GetProperty(aura::client::kShowStateKey) !=
+ ui::SHOW_STATE_MINIMIZED) {
+ InvalidateLayout();
+ widget_->GetRootView()->Layout();
+ }
+ }
+ }
+
views::Widget* widget_;
+ ScopedObserver<aura::Window, aura::WindowObserver> observed_{this};
DISALLOW_COPY_AND_ASSIGN(ClientSideNonClientFrameView);
};
@@ -290,8 +316,11 @@ float DesktopWindowTreeHostMus::GetScaleFactor() const {
}
void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
- SetBoundsInPixels(gfx::ConvertRectToPixel(GetScaleFactor(), bounds_in_dip),
- viz::LocalSurfaceId());
+ // Do not use ConvertRectToPixel, enclosing rects cause problems.
+ const gfx::Rect rect(
+ gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), GetScaleFactor()),
+ gfx::ScaleToCeiledSize(bounds_in_dip.size(), GetScaleFactor()));
+ SetBoundsInPixels(rect, viz::LocalSurfaceId());
}
bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
@@ -361,7 +390,7 @@ void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
}
if (!params.accept_events)
- window()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::NONE);
+ window()->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::NONE);
else
aura::WindowPortMus::Get(content_window())->SetCanAcceptDrops(true);
}
@@ -470,17 +499,36 @@ aura::WindowTreeHost* DesktopWindowTreeHostMus::AsWindowTreeHost() {
return this;
}
-void DesktopWindowTreeHostMus::ShowWindowWithState(ui::WindowShowState state) {
- if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN)
- window()->SetProperty(aura::client::kShowStateKey, state);
+void DesktopWindowTreeHostMus::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
+ native_widget_delegate_->OnNativeWidgetVisibilityChanging(true);
+
+ if (show_state == ui::SHOW_STATE_MAXIMIZED && !restore_bounds.IsEmpty()) {
+ window()->SetProperty(aura::client::kRestoreBoundsKey,
+ new gfx::Rect(restore_bounds));
+ }
+ if (show_state == ui::SHOW_STATE_MAXIMIZED ||
+ show_state == ui::SHOW_STATE_FULLSCREEN) {
+ window()->SetProperty(aura::client::kShowStateKey, show_state);
+ }
+ // DesktopWindowTreeHostMus is unique in that it calls window()->Show() here.
+ // All other implementations call window()->Show() from the constructor. This
+ // is necessary as window()'s visibility is mirrored in the server, on other
+ // platforms it's the visibility of the AcceleratedWidget that matters and
+ // dictates what is actually drawn on screen.
window()->Show();
if (compositor())
compositor()->SetVisible(true);
+ // |content_window_| is the Window that will be focused by way of Activate().
+ // Ensure |content_window_| is visible before the call to Activate(),
+ // otherwise focus goes to window().
+ content_window()->Show();
+
native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
if (native_widget_delegate_->CanActivate()) {
- if (state != ui::SHOW_STATE_INACTIVE)
+ if (show_state != ui::SHOW_STATE_INACTIVE)
Activate();
// SetInitialFocus() should be always be called, even for
@@ -490,17 +538,10 @@ void DesktopWindowTreeHostMus::ShowWindowWithState(ui::WindowShowState state) {
// should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial
// focused view from getting focused. See crbug.com/515594 for example.
native_widget_delegate_->SetInitialFocus(
- IsActive() ? state : ui::SHOW_STATE_INACTIVE);
+ IsActive() ? show_state : ui::SHOW_STATE_INACTIVE);
}
}
-void DesktopWindowTreeHostMus::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- window()->SetProperty(aura::client::kRestoreBoundsKey,
- new gfx::Rect(restored_bounds));
- ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
-}
-
bool DesktopWindowTreeHostMus::IsVisible() const {
// Go through the DesktopNativeWidgetAura::IsVisible() for checking
// visibility of the parent as it has additional checks beyond checking the
@@ -513,7 +554,7 @@ bool DesktopWindowTreeHostMus::IsVisible() const {
}
void DesktopWindowTreeHostMus::SetSize(const gfx::Size& size) {
- // Use GetBounds() as the origin of window() is always at 0, 0.
+ // Use GetBoundsInPixels(), as the origin of window() is always at (0, 0).
gfx::Rect screen_bounds =
gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
screen_bounds.set_size(size);
@@ -562,11 +603,7 @@ void DesktopWindowTreeHostMus::GetWindowPlacement(
}
gfx::Rect DesktopWindowTreeHostMus::GetWindowBoundsInScreen() const {
- gfx::Point display_origin = GetDisplay().bounds().origin();
- gfx::Rect bounds_in_dip =
- gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
- bounds_in_dip.Offset(display_origin.x(), display_origin.y());
- return bounds_in_dip;
+ return gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
}
gfx::Rect DesktopWindowTreeHostMus::GetClientAreaBoundsInScreen() const {
@@ -596,10 +633,7 @@ std::string DesktopWindowTreeHostMus::GetWorkspace() const {
}
gfx::Rect DesktopWindowTreeHostMus::GetWorkAreaBoundsInScreen() const {
- // TODO(sky): GetDisplayNearestWindow() should take a const aura::Window*.
- return display::Screen::GetScreen()
- ->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
- .work_area();
+ return GetDisplay().work_area();
}
void DesktopWindowTreeHostMus::SetShape(
@@ -647,6 +681,7 @@ bool DesktopWindowTreeHostMus::IsActive() const {
void DesktopWindowTreeHostMus::Maximize() {
window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
}
+
void DesktopWindowTreeHostMus::Minimize() {
window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
}
@@ -716,10 +751,10 @@ Widget::MoveLoopResult DesktopWindowTreeHostMus::RunMoveLoop(
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
- ui::mojom::MoveLoopSource mus_source =
+ ws::mojom::MoveLoopSource mus_source =
source == Widget::MOVE_LOOP_SOURCE_MOUSE
- ? ui::mojom::MoveLoopSource::MOUSE
- : ui::mojom::MoveLoopSource::TOUCH;
+ ? ws::mojom::MoveLoopSource::MOUSE
+ : ws::mojom::MoveLoopSource::TOUCH;
bool success = false;
gfx::Point cursor_location =
@@ -746,7 +781,10 @@ NonClientFrameView* DesktopWindowTreeHostMus::CreateNonClientFrameView() {
if (!ShouldSendClientAreaToServer())
return nullptr;
- return new ClientSideNonClientFrameView(native_widget_delegate_->AsWidget());
+ auto* frame =
+ new ClientSideNonClientFrameView(native_widget_delegate_->AsWidget());
+ observed_frame_.Add(frame);
+ return frame;
}
bool DesktopWindowTreeHostMus::ShouldUseNativeFrame() const {
@@ -772,6 +810,7 @@ bool DesktopWindowTreeHostMus::IsFullscreen() const {
return window()->GetProperty(aura::client::kShowStateKey) ==
ui::SHOW_STATE_FULLSCREEN;
}
+
void DesktopWindowTreeHostMus::SetOpacity(float opacity) {
WindowTreeHostMus::SetOpacity(opacity);
}
@@ -801,7 +840,7 @@ bool DesktopWindowTreeHostMus::IsTranslucentWindowOpacitySupported() const {
}
void DesktopWindowTreeHostMus::SizeConstraintsChanged() {
- int32_t behavior = ui::mojom::kResizeBehaviorNone;
+ int32_t behavior = ws::mojom::kResizeBehaviorNone;
Widget* widget = native_widget_delegate_->AsWidget();
if (widget->widget_delegate())
behavior = widget->widget_delegate()->GetResizeBehavior();
@@ -864,11 +903,7 @@ void DesktopWindowTreeHostMus::OnWindowPropertyChanged(aura::Window* window,
}
void DesktopWindowTreeHostMus::ShowImpl() {
- native_widget_delegate_->OnNativeWidgetVisibilityChanging(true);
- // Using ui::SHOW_STATE_NORMAL matches that of DesktopWindowTreeHostX11.
- ShowWindowWithState(ui::SHOW_STATE_NORMAL);
- WindowTreeHostMus::ShowImpl();
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
+ Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
}
void DesktopWindowTreeHostMus::HideImpl() {
@@ -884,7 +919,6 @@ void DesktopWindowTreeHostMus::HideImpl() {
native_widget_delegate_->OnNativeWidgetVisibilityChanging(false);
WindowTreeHostMus::HideImpl();
- window()->Hide();
native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
}
@@ -902,13 +936,21 @@ void DesktopWindowTreeHostMus::SetBoundsInPixels(
size.SetToMin(max_size_in_pixels);
final_bounds_in_pixels.set_size(size);
}
- const gfx::Rect old_bounds_in_pixels = GetBoundsInPixels();
WindowTreeHostMus::SetBoundsInPixels(final_bounds_in_pixels,
local_surface_id);
- if (old_bounds_in_pixels.size() != final_bounds_in_pixels.size()) {
- SendClientAreaToServer();
- SendHitTestMaskToServer();
- }
+}
+
+void DesktopWindowTreeHostMus::OnViewBoundsChanged(views::View* observed_view) {
+ DCHECK_EQ(
+ observed_view,
+ native_widget_delegate_->AsWidget()->non_client_view()->frame_view());
+
+ SendClientAreaToServer();
+ SendHitTestMaskToServer();
+}
+
+void DesktopWindowTreeHostMus::OnViewIsDeleting(View* observed_view) {
+ observed_frame_.Remove(observed_view);
}
aura::Window* DesktopWindowTreeHostMus::content_window() {
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.h b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
index 92d4e468695..a93e0c297ed 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.h
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
@@ -8,11 +8,13 @@
#include <memory>
#include <set>
+#include "base/scoped_observer.h"
#include "base/macros.h"
#include "ui/aura/mus/focus_synchronizer_observer.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/window_observer.h"
#include "ui/views/mus/mus_client_observer.h"
+#include "ui/views/view_observer.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#include "ui/views/widget/widget.h"
@@ -28,7 +30,8 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
public MusClientObserver,
public aura::FocusSynchronizerObserver,
public aura::WindowObserver,
- public aura::WindowTreeHostMus {
+ public aura::WindowTreeHostMus,
+ public views::ViewObserver {
public:
DesktopWindowTreeHostMus(
aura::WindowTreeHostMusInitParams init_params,
@@ -71,8 +74,8 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
void Close() override;
void CloseNow() override;
aura::WindowTreeHost* AsWindowTreeHost() override;
- void ShowWindowWithState(ui::WindowShowState state) override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
bool IsVisible() const override;
void SetSize(const gfx::Size& size) override;
void StackAbove(aura::Window* window) override;
@@ -144,6 +147,10 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
void SetBoundsInPixels(const gfx::Rect& bounds_in_pixels,
const viz::LocalSurfaceId& local_surface_id) override;
+ // views::ViewObserver:
+ void OnViewBoundsChanged(views::View* observed_view) override;
+ void OnViewIsDeleting(View* observed_view) override;
+
// Accessor for DesktopNativeWidgetAura::content_window().
aura::Window* content_window();
@@ -162,6 +169,8 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
bool auto_update_client_area_ = true;
+ ScopedObserver<views::View, views::ViewObserver> observed_frame_{this};
+
// Used so that Close() isn't immediate.
base::WeakPtrFactory<DesktopWindowTreeHostMus> close_widget_factory_;
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index 79aef70d12d..85bfbad2488 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -22,7 +22,9 @@
#include "ui/events/event.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/mus/mus_client.h"
+#include "ui/views/mus/mus_client_test_api.h"
#include "ui/views/mus/screen_mus.h"
+#include "ui/views/mus/window_manager_frame_values.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -157,8 +159,7 @@ TEST_F(DesktopWindowTreeHostMusTest, Capture) {
->capture_window());
}
-// TODO(http://crbug.com/864614): Fails flakily in mus with ws2.
-TEST_F(DesktopWindowTreeHostMusTest, DISABLED_Deactivate) {
+TEST_F(DesktopWindowTreeHostMusTest, Deactivate) {
std::unique_ptr<Widget> widget1(CreateWidget());
widget1->Show();
@@ -239,6 +240,44 @@ TEST_F(DesktopWindowTreeHostMusTest, ActivateBeforeShow) {
->active_focus_client());
}
+// Tests that changes to a widget's show state will cause the client area to be
+// updated.
+TEST_F(DesktopWindowTreeHostMusTest, ServerShowStateChangeUpdatesClientArea) {
+ WindowManagerFrameValues test_frame_values;
+ test_frame_values.normal_insets = {3, 0, 0, 0};
+ test_frame_values.maximized_insets = {7, 0, 0, 0};
+ WindowManagerFrameValues::SetInstance(test_frame_values);
+
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+
+ // Simulate state changes from the server.
+ auto set_widget_state =
+ [&widget](ui::WindowShowState state) {
+ widget->GetNativeWindow()->GetRootWindow()->SetProperty(
+ aura::client::kShowStateKey, state);
+ };
+
+ // A restored window respects normal_insets (the client area is inset from the
+ // root view).
+ gfx::Rect expected_restored_bounds = widget->GetRootView()->bounds();
+ expected_restored_bounds.Inset(test_frame_values.normal_insets);
+ EXPECT_EQ(expected_restored_bounds, widget->client_view()->bounds());
+
+ // A fullscreen window has no insets.
+ EXPECT_FALSE(widget->IsFullscreen());
+ set_widget_state(ui::SHOW_STATE_FULLSCREEN);
+ EXPECT_TRUE(widget->IsFullscreen());
+ EXPECT_EQ(widget->GetRootView()->bounds(), widget->client_view()->bounds());
+
+ // A maximized window respects maximized_insets.
+ gfx::Rect expected_maximized_bounds = widget->GetRootView()->bounds();
+ expected_maximized_bounds.Inset(test_frame_values.maximized_insets);
+ set_widget_state(ui::SHOW_STATE_MAXIMIZED);
+ EXPECT_FALSE(widget->IsFullscreen());
+ EXPECT_EQ(expected_maximized_bounds, widget->client_view()->bounds());
+}
+
TEST_F(DesktopWindowTreeHostMusTest, CursorClientDuringTearDown) {
std::unique_ptr<Widget> widget(CreateWidget());
widget->Show();
@@ -279,8 +318,7 @@ TEST_F(DesktopWindowTreeHostMusTest, StackAtTopAlreadyOnTop) {
waiter.Wait();
}
-// TODO(http://crbug.com/864615): Fails consistently in mus with ws2.
-TEST_F(DesktopWindowTreeHostMusTest, DISABLED_StackAbove) {
+TEST_F(DesktopWindowTreeHostMusTest, StackAbove) {
std::unique_ptr<Widget> widget1(CreateWidget(nullptr));
widget1->Show();
@@ -365,7 +403,7 @@ TEST_F(DesktopWindowTreeHostMusTest, CreateFullscreenWidget) {
}
TEST_F(DesktopWindowTreeHostMusTest, GetWindowBoundsInScreen) {
- ScreenMus* screen = MusClient::Get()->screen();
+ ScreenMus* screen = MusClientTestApi::screen();
// Add a second display to the right of the primary.
const int64_t kSecondDisplayId = 222;
@@ -385,11 +423,12 @@ TEST_F(DesktopWindowTreeHostMusTest, GetWindowBoundsInScreen) {
Widget widget2;
Widget::InitParams params2(Widget::InitParams::TYPE_WINDOW);
params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params2.bounds = gfx::Rect(0, 0, 100, 100);
+ params2.bounds = gfx::Rect(800, 0, 100, 100);
widget2.Init(params2);
- aura::WindowTreeHostMus::ForWindow(widget2.GetNativeWindow())
- ->set_display_id(kSecondDisplayId);
EXPECT_EQ(gfx::Rect(800, 0, 100, 100), widget2.GetWindowBoundsInScreen());
+ EXPECT_EQ(kSecondDisplayId,
+ aura::WindowTreeHostMus::ForWindow(widget2.GetNativeWindow())
+ ->display_id());
}
// WidgetDelegate implementation that allows setting window-title and whether
diff --git a/chromium/ui/views/mus/drag_interactive_uitest.cc b/chromium/ui/views/mus/drag_interactive_uitest.cc
index d222948c84c..999ec9e269a 100644
--- a/chromium/ui/views/mus/drag_interactive_uitest.cc
+++ b/chromium/ui/views/mus/drag_interactive_uitest.cc
@@ -4,9 +4,12 @@
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "services/ui/public/interfaces/window_server_test.mojom.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/constants.mojom.h"
+#include "services/ws/public/mojom/event_injector.mojom.h"
+#include "services/ws/public/mojom/window_server_test.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/mus/in_flight_change.h"
+#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/test/mus/change_completion_waiter.h"
#include "ui/events/event.h"
@@ -117,36 +120,37 @@ void DragTest_Part3(int64_t display_id,
quit_closure.Run();
}
-void DragTest_Part2(int64_t display_id,
+void DragTest_Part2(ws::mojom::EventInjector* event_injector,
+ int64_t display_id,
const base::Closure& quit_closure,
bool result) {
EXPECT_TRUE(result);
if (!result)
quit_closure.Run();
- ui::mojom::EventInjector* event_injector =
- MusClient::Get()->GetTestingEventInjector();
event_injector->InjectEvent(
display_id, CreateMouseUpEvent(30, 30),
base::BindOnce(&DragTest_Part3, display_id, quit_closure));
}
-void DragTest_Part1(int64_t display_id,
+void DragTest_Part1(ws::mojom::EventInjector* event_injector,
+ int64_t display_id,
const base::Closure& quit_closure,
bool result) {
EXPECT_TRUE(result);
if (!result)
quit_closure.Run();
- ui::mojom::EventInjector* event_injector =
- MusClient::Get()->GetTestingEventInjector();
event_injector->InjectEvent(
display_id, CreateMouseMoveEvent(30, 30),
- base::BindOnce(&DragTest_Part2, display_id, quit_closure));
+ base::BindOnce(&DragTest_Part2, base::Unretained(event_injector),
+ display_id, quit_closure));
}
-// TODO(http://crbug.com/864616): Hangs indefinitely in mus with ws2.
-TEST_F(DragTestInteractive, DISABLED_DragTest) {
+TEST_F(DragTestInteractive, DragTest) {
+ ws::mojom::EventInjectorPtr event_injector;
+ MusClient::Get()->window_tree_client()->connector()->BindInterface(
+ ws::mojom::kServiceName, &event_injector);
Widget* source_widget = CreateTopLevelFramelessPlatformWidget();
View* source_view = new DraggableView;
source_widget->SetContentsView(source_view);
@@ -176,11 +180,10 @@ TEST_F(DragTestInteractive, DISABLED_DragTest) {
{
base::RunLoop run_loop;
- ui::mojom::EventInjector* event_injector =
- MusClient::Get()->GetTestingEventInjector();
event_injector->InjectEvent(
display_id, CreateMouseDownEvent(10, 10),
- base::BindOnce(&DragTest_Part1, display_id, run_loop.QuitClosure()));
+ base::BindOnce(&DragTest_Part1, base::Unretained(event_injector.get()),
+ display_id, run_loop.QuitClosure()));
run_loop.Run();
}
diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc
index 09eb2fcd5bc..4678479162a 100644
--- a/chromium/ui/views/mus/mus_client.cc
+++ b/chromium/ui/views/mus/mus_client.cc
@@ -8,18 +8,17 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
#include "services/service_manager/public/cpp/connector.h"
-#include "services/ui/public/cpp/gpu/gpu.h"
-#include "services/ui/public/cpp/input_devices/input_device_client.h"
-#include "services/ui/public/cpp/property_type_converters.h"
-#include "services/ui/public/interfaces/constants.mojom.h"
-#include "services/ui/public/interfaces/event_matcher.mojom.h"
-#include "services/ui/public/interfaces/window_manager.mojom.h"
+#include "services/ws/public/cpp/gpu/gpu.h"
+#include "services/ws/public/cpp/input_devices/input_device_client.h"
+#include "services/ws/public/cpp/property_type_converters.h"
+#include "services/ws/public/mojom/constants.mojom.h"
+#include "services/ws/public/mojom/window_manager.mojom.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/capture_synchronizer.h"
#include "ui/aura/mus/mus_context_factory.h"
#include "ui/aura/mus/property_converter.h"
+#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/window.h"
@@ -41,11 +40,11 @@
#include "ui/base/cursor/ozone/cursor_data_factory_ozone.h"
#endif
-// Widget::InitParams::Type must match that of ui::mojom::WindowType.
+// Widget::InitParams::Type must match that of ws::mojom::WindowType.
#define WINDOW_TYPES_MATCH(NAME) \
static_assert( \
static_cast<int32_t>(views::Widget::InitParams::TYPE_##NAME) == \
- static_cast<int32_t>(ui::mojom::WindowType::NAME), \
+ static_cast<int32_t>(ws::mojom::WindowType::NAME), \
"Window type constants must match")
WINDOW_TYPES_MATCH(WINDOW);
@@ -57,7 +56,7 @@ WINDOW_TYPES_MATCH(MENU);
WINDOW_TYPES_MATCH(TOOLTIP);
WINDOW_TYPES_MATCH(BUBBLE);
WINDOW_TYPES_MATCH(DRAG);
-// ui::mojom::WindowType::UNKNOWN does not correspond to a value in
+// ws::mojom::WindowType::UNKNOWN does not correspond to a value in
// Widget::InitParams::Type.
namespace views {
@@ -85,35 +84,25 @@ MusClient::MusClient(const InitParams& params) : identity_(params.identity) {
cursor_factory_ozone_ = std::make_unique<ui::CursorDataFactoryOzone>();
#endif
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
- params.io_task_runner;
- if (!io_task_runner) {
- io_thread_ = std::make_unique<base::Thread>("IOThread");
- base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
- thread_options.priority = base::ThreadPriority::NORMAL;
- CHECK(io_thread_->StartWithOptions(thread_options));
- io_task_runner = io_thread_->task_runner();
- }
-
property_converter_ = std::make_unique<aura::PropertyConverter>();
property_converter_->RegisterPrimitiveProperty(
::wm::kShadowElevationKey,
- ui::mojom::WindowManager::kShadowElevation_Property,
+ ws::mojom::WindowManager::kShadowElevation_Property,
aura::PropertyConverter::CreateAcceptAnyValueCallback());
if (params.create_wm_state)
wm_state_ = std::make_unique<wm::WMState>();
service_manager::Connector* connector = params.connector;
- if (params.bind_test_ws_interfaces)
- connector->BindInterface(ui::mojom::kServiceName, &event_injector_);
if (!params.window_tree_client) {
- DCHECK(io_task_runner);
+ // If this process is running in the WindowService, then discardable memory
+ // should have already been created.
+ const bool create_discardable_memory = !params.running_in_ws_process;
owned_window_tree_client_ =
aura::WindowTreeClient::CreateForWindowTreeFactory(
- connector, this, true, std::move(io_task_runner),
- params.wtc_config);
+ connector, this, create_discardable_memory,
+ std::move(params.io_task_runner));
window_tree_client_ = owned_window_tree_client_.get();
aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client_);
} else {
@@ -123,20 +112,21 @@ MusClient::MusClient(const InitParams& params) : identity_(params.identity) {
pointer_watcher_event_router_ =
std::make_unique<PointerWatcherEventRouter>(window_tree_client_);
- if (connector) {
- input_device_client_ = std::make_unique<ui::InputDeviceClient>();
- ui::mojom::InputDeviceServerPtr input_device_server;
- connector->BindInterface(ui::mojom::kServiceName, &input_device_server);
+ if (connector && !params.running_in_ws_process) {
+ input_device_client_ = std::make_unique<ws::InputDeviceClient>();
+ ws::mojom::InputDeviceServerPtr input_device_server;
+ connector->BindInterface(ws::mojom::kServiceName, &input_device_server);
input_device_client_->Connect(std::move(input_device_server));
screen_ = std::make_unique<ScreenMus>(this);
- if (params.wtc_config == aura::WindowTreeClient::Config::kMashDeprecated)
- screen_->InitDeprecated(connector);
- else
- window_tree_client_->WaitForDisplays();
+ display::Screen::SetScreenInstance(screen_.get());
+
+ // NOTE: this deadlocks if |running_in_ws_process| is true (because the main
+ // thread is running the WindowService).
+ window_tree_client_->WaitForDisplays();
ui::mojom::ClipboardHostPtr clipboard_host_ptr;
- connector->BindInterface(ui::mojom::kServiceName, &clipboard_host_ptr);
+ connector->BindInterface(ws::mojom::kServiceName, &clipboard_host_ptr);
ui::Clipboard::SetClipboardForCurrentThread(
std::make_unique<ui::ClipboardClient>(std::move(clipboard_host_ptr)));
@@ -153,6 +143,10 @@ MusClient::MusClient(const InitParams& params) : identity_(params.identity) {
}
MusClient::~MusClient() {
+ // Tear down accessibility before WindowTreeClient to ensure window tree
+ // cleanup doesn't trigger accessibility events.
+ ax_remote_host_.reset();
+
// ~WindowTreeClient calls back to us (we're its delegate), destroy it while
// we are still valid.
owned_window_tree_client_.reset();
@@ -167,6 +161,11 @@ MusClient::~MusClient() {
ViewsDelegate::DesktopWindowTreeHostFactory());
}
+ if (screen_) {
+ display::Screen::SetScreenInstance(nullptr);
+ screen_.reset();
+ }
+
DCHECK_EQ(instance_, this);
instance_ = nullptr;
DCHECK(aura::Env::GetInstance());
@@ -175,6 +174,19 @@ MusClient::~MusClient() {
// static
bool MusClient::ShouldCreateDesktopNativeWidgetAura(
const Widget::InitParams& init_params) {
+ const bool from_window_service =
+ (init_params.context &&
+ init_params.context->env()->mode() == aura::Env::Mode::LOCAL) ||
+ (init_params.parent &&
+ init_params.parent->env()->mode() == aura::Env::Mode::LOCAL);
+ // |from_window_service| is true if the aura::Env has a mode of LOCAL. If
+ // the mode is LOCAL there are two envs, one used by the window service
+ // (LOCAL), and the other for non-window-service code. Windows created with
+ // LOCAL should use NativeWidgetAura (which happens if false is returned
+ // here).
+ if (from_window_service)
+ return false;
+
// TYPE_CONTROL and child widgets require a NativeWidgetAura.
return init_params.type != Widget::InitParams::TYPE_CONTROL &&
!init_params.child;
@@ -195,12 +207,12 @@ std::map<std::string, std::vector<uint8_t>>
MusClient::ConfigurePropertiesFromParams(
const Widget::InitParams& init_params) {
using PrimitiveType = aura::PropertyConverter::PrimitiveType;
- using WindowManager = ui::mojom::WindowManager;
+ using WindowManager = ws::mojom::WindowManager;
using TransportType = std::vector<uint8_t>;
std::map<std::string, TransportType> properties = init_params.mus_properties;
- // Widget::InitParams::Type matches ui::mojom::WindowType.
+ // Widget::InitParams::Type matches ws::mojom::WindowType.
properties[WindowManager::kWindowType_InitProperty] =
mojo::ConvertTo<TransportType>(static_cast<int32_t>(init_params.type));
@@ -337,11 +349,6 @@ void MusClient::CloseAllWidgets() {
}
}
-ui::mojom::EventInjector* MusClient::GetTestingEventInjector() const {
- CHECK(event_injector_);
- return event_injector_.get();
-}
-
std::unique_ptr<DesktopWindowTreeHost> MusClient::CreateDesktopWindowTreeHost(
const Widget::InitParams& init_params,
internal::NativeWidgetDelegate* delegate,
@@ -370,18 +377,21 @@ void MusClient::OnEmbedRootDestroyed(
}
void MusClient::OnPointerEventObserved(const ui::PointerEvent& event,
- int64_t display_id,
+ const gfx::Point& location_in_screen,
aura::Window* target) {
- pointer_watcher_event_router_->OnPointerEventObserved(event, display_id,
- target);
+ pointer_watcher_event_router_->OnPointerEventObserved(
+ event, location_in_screen, target);
}
void MusClient::OnDisplaysChanged(
- std::vector<ui::mojom::WsDisplayPtr> ws_displays,
+ std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
- int64_t internal_display_id) {
- screen_->OnDisplaysChanged(std::move(ws_displays), primary_display_id,
- internal_display_id);
+ int64_t internal_display_id,
+ int64_t display_id_for_new_windows) {
+ if (screen_) {
+ screen_->OnDisplaysChanged(std::move(ws_displays), primary_display_id,
+ internal_display_id, display_id_for_new_windows);
+ }
}
void MusClient::OnWindowManagerFrameValuesChanged() {
diff --git a/chromium/ui/views/mus/mus_client.h b/chromium/ui/views/mus/mus_client.h
index cb3d6b6cef5..0cd4f65bc06 100644
--- a/chromium/ui/views/mus/mus_client.h
+++ b/chromium/ui/views/mus/mus_client.h
@@ -13,9 +13,7 @@
#include "base/macros.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "ui/aura/client/capture_client.h"
-#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_client_delegate.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/mus/screen_mus_delegate.h"
@@ -29,7 +27,6 @@ class WindowTreeClient;
namespace base {
class SingleThreadTaskRunner;
-class Thread;
}
namespace service_manager {
@@ -38,13 +35,16 @@ class Connector;
namespace ui {
class CursorDataFactoryOzone;
-class InputDeviceClient;
}
namespace wm {
class WMState;
}
+namespace ws {
+class InputDeviceClient;
+}
+
namespace views {
class AXRemoteHost;
@@ -68,15 +68,13 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
InitParams();
~InitParams();
- // Production code should provide |connector|, |identity|, |wtc_config|
- // and an |io_task_runner| if the process already has one. Test code may
- // skip these parameters (e.g. a unit test that does not need to connect
- // to the window service does not need to provide a connector).
+ // Production code should provide |connector|, |identity|, and an
+ // |io_task_runner| if the process already has one. Test code may skip these
+ // parameters (e.g. a unit test that does not need to connect to the window
+ // service does not need to provide a connector).
service_manager::Connector* connector = nullptr;
service_manager::Identity identity;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = nullptr;
- aura::WindowTreeClient::Config wtc_config =
- aura::WindowTreeClient::Config::kMashDeprecated;
// Create a wm::WMState. Some processes (e.g. the browser) may already
// have one.
@@ -84,7 +82,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// Tests may need to control objects owned by MusClient.
bool create_cursor_factory = true;
- bool bind_test_ws_interfaces = false;
// If provided, MusClient will not create the WindowTreeClient. Not owned.
// Must outlive MusClient.
@@ -93,6 +90,10 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// Connect to the accessibility host service in the browser (e.g. to support
// ChromeVox).
bool use_accessibility_host = false;
+
+ // Set to true if the WindowService is running in the same process and on
+ // the same thread as MusClient.
+ bool running_in_ws_process = false;
};
// Most clients should use AuraInit, which creates a MusClient.
@@ -116,6 +117,10 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
static std::map<std::string, std::vector<uint8_t>>
ConfigurePropertiesFromParams(const Widget::InitParams& init_params);
+ aura::PropertyConverter* property_converter() {
+ return property_converter_.get();
+ }
+
aura::WindowTreeClient* window_tree_client() { return window_tree_client_; }
PointerWatcherEventRouter* pointer_watcher_event_router() {
@@ -124,9 +129,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
AXRemoteHost* ax_remote_host() { return ax_remote_host_.get(); }
- // Getter for type safety. Most code can use display::Screen::GetScreen().
- ScreenMus* screen() { return screen_.get(); }
-
// Creates DesktopNativeWidgetAura with DesktopWindowTreeHostMus. This is
// set as the factory function used for creating NativeWidgets when a
// NativeWidget has not been explicitly set.
@@ -153,10 +155,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// Close all widgets this client knows.
void CloseAllWidgets();
- // Returns an interface to inject events into the Window Service. Only
- // available when created with MusClientTestingState::CREATE_TESTING_STATE.
- ui::mojom::EventInjector* GetTestingEventInjector() const;
-
private:
friend class AuraInit;
friend class MusClientTestApi;
@@ -175,12 +173,13 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
void OnLostConnection(aura::WindowTreeClient* client) override;
void OnEmbedRootDestroyed(aura::WindowTreeHostMus* window_tree_host) override;
void OnPointerEventObserved(const ui::PointerEvent& event,
- int64_t display_id,
+ const gfx::Point& location_in_screen,
aura::Window* target) override;
aura::PropertyConverter* GetPropertyConverter() override;
- void OnDisplaysChanged(std::vector<ui::mojom::WsDisplayPtr> ws_displays,
+ void OnDisplaysChanged(std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
- int64_t internal_display_id) override;
+ int64_t internal_display_id,
+ int64_t display_id_for_new_windows) override;
// ScreenMusDelegate:
void OnWindowManagerFrameValuesChanged() override;
@@ -190,9 +189,7 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
service_manager::Identity identity_;
- std::unique_ptr<base::Thread> io_thread_;
-
- base::ObserverList<MusClientObserver> observer_list_;
+ base::ObserverList<MusClientObserver>::Unchecked observer_list_;
#if defined(USE_OZONE)
std::unique_ptr<ui::CursorDataFactoryOzone> cursor_factory_ozone_;
@@ -216,15 +213,13 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
std::unique_ptr<PointerWatcherEventRouter> pointer_watcher_event_router_;
// Gives services transparent remote access the InputDeviceManager.
- std::unique_ptr<ui::InputDeviceClient> input_device_client_;
+ std::unique_ptr<ws::InputDeviceClient> input_device_client_;
// Forwards accessibility events to extensions in the browser. Can be null for
// apps that do not need accessibility support and for the browser itself
// under OopAsh.
std::unique_ptr<AXRemoteHost> ax_remote_host_;
- ui::mojom::EventInjectorPtr event_injector_;
-
DISALLOW_COPY_AND_ASSIGN(MusClient);
};
diff --git a/chromium/ui/views/mus/mus_client_test_api.h b/chromium/ui/views/mus/mus_client_test_api.h
index e3052276ce8..bdf20dccb51 100644
--- a/chromium/ui/views/mus/mus_client_test_api.h
+++ b/chromium/ui/views/mus/mus_client_test_api.h
@@ -9,6 +9,7 @@
#include <utility>
#include "base/macros.h"
+#include "ui/views/mus/ax_remote_host.h"
#include "ui/views/mus/mus_client.h"
namespace views {
@@ -21,6 +22,8 @@ class MusClientTestApi {
MusClient::Get()->ax_remote_host_ = std::move(client);
}
+ static ScreenMus* screen() { return MusClient::Get()->screen_.get(); }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MusClientTestApi);
};
diff --git a/chromium/ui/views/mus/mus_views_delegate.cc b/chromium/ui/views/mus/mus_views_delegate.cc
index 927c065ee5f..e383ac00d69 100644
--- a/chromium/ui/views/mus/mus_views_delegate.cc
+++ b/chromium/ui/views/mus/mus_views_delegate.cc
@@ -15,8 +15,7 @@ MusViewsDelegate::~MusViewsDelegate() = default;
void MusViewsDelegate::NotifyAccessibilityEvent(View* view,
ax::mojom::Event event_type) {
- // Null in AuraInit::Mode::AURA_MUS_WINDOW_MANAGER which is used in mash.
- if (MusClient::Get() && MusClient::Get()->ax_remote_host())
+ if (MusClient::Get()->ax_remote_host())
MusClient::Get()->ax_remote_host()->HandleEvent(view, event_type);
}
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router.cc b/chromium/ui/views/mus/pointer_watcher_event_router.cc
index beed6b538c9..07a1a7e7b02 100644
--- a/chromium/ui/views/mus/pointer_watcher_event_router.cc
+++ b/chromium/ui/views/mus/pointer_watcher_event_router.cc
@@ -5,23 +5,20 @@
#include "ui/views/mus/pointer_watcher_event_router.h"
#include "ui/aura/client/capture_client.h"
+#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h"
-#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/views/pointer_watcher.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-using display::Display;
-using display::Screen;
-
namespace views {
namespace {
bool HasPointerWatcher(
- base::ObserverList<views::PointerWatcher, true>* observer_list) {
+ base::ObserverList<views::PointerWatcher, true>::Unchecked* observer_list) {
return observer_list->begin() != observer_list->end();
}
@@ -89,7 +86,7 @@ void PointerWatcherEventRouter::RemovePointerWatcher(PointerWatcher* watcher) {
void PointerWatcherEventRouter::OnPointerEventObserved(
const ui::PointerEvent& event,
- int64_t display_id,
+ const gfx::Point& location_in_screen,
aura::Window* target) {
Widget* target_widget = nullptr;
ui::PointerEvent updated_event(event);
@@ -118,13 +115,6 @@ void PointerWatcherEventRouter::OnPointerEventObserved(
}
}
- // Compute screen coordinates via |display_id| because there may not be a
- // |target| that can be used to find a ScreenPositionClient.
- gfx::Point location_in_screen = event.location();
- Display display;
- if (Screen::GetScreen()->GetDisplayWithDisplayId(display_id, &display))
- location_in_screen.Offset(display.bounds().x(), display.bounds().y());
-
for (PointerWatcher& observer : move_watchers_) {
observer.OnPointerEventObserved(
updated_event, location_in_screen,
@@ -165,7 +155,8 @@ void PointerWatcherEventRouter::OnCaptureChanged(aura::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 = Screen::GetScreen()->GetCursorScreenPoint();
+ gfx::Point location_in_screen =
+ display::Screen::GetScreen()->GetCursorScreenPoint();
for (PointerWatcher& observer : move_watchers_)
observer.OnPointerEventObserved(event, location_in_screen, nullptr);
for (PointerWatcher& observer : non_move_watchers_)
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router.h b/chromium/ui/views/mus/pointer_watcher_event_router.h
index 2c9dd56e081..48cfa96930e 100644
--- a/chromium/ui/views/mus/pointer_watcher_event_router.h
+++ b/chromium/ui/views/mus/pointer_watcher_event_router.h
@@ -21,6 +21,10 @@ class CaptureClient;
}
}
+namespace gfx {
+class Point;
+}
+
namespace ui {
class PointerEvent;
}
@@ -59,7 +63,7 @@ class VIEWS_MUS_EXPORT PointerWatcherEventRouter
// Called by WindowTreeClientDelegate to notify PointerWatchers appropriately.
void OnPointerEventObserved(const ui::PointerEvent& event,
- int64_t display_id,
+ const gfx::Point& location_in_screen,
aura::Window* target);
// Called when the |capture_client| has been set or will be unset.
@@ -84,8 +88,8 @@ class VIEWS_MUS_EXPORT PointerWatcherEventRouter
// 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_;
+ base::ObserverList<views::PointerWatcher, true>::Unchecked non_move_watchers_;
+ base::ObserverList<views::PointerWatcher, true>::Unchecked move_watchers_;
EventTypes event_types_ = EventTypes::NONE;
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
index 821cefdcf38..0f6143e0c43 100644
--- a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
+++ b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
@@ -7,13 +7,11 @@
#include <memory>
#include "base/test/scoped_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/mus/window_tree_client_private.h"
#include "ui/events/event.h"
#include "ui/views/mus/mus_client.h"
-#include "ui/views/mus/screen_mus.h"
#include "ui/views/pointer_watcher.h"
-#include "ui/views/test/scoped_views_test_helper.h"
+#include "ui/views/test/views_test_base.h"
namespace views {
namespace {
@@ -48,15 +46,14 @@ class TestPointerWatcher : public PointerWatcher {
} // namespace
-class PointerWatcherEventRouterTest : public testing::Test {
+class PointerWatcherEventRouterTest : public views::ViewsTestBase {
public:
PointerWatcherEventRouterTest() = default;
~PointerWatcherEventRouterTest() override = default;
- void OnPointerEventObserved(const ui::PointerEvent& event,
- int64_t display_id = 0) {
+ void OnPointerEventObserved(const ui::PointerEvent& event) {
MusClient::Get()->pointer_watcher_event_router()->OnPointerEventObserved(
- event, display_id, nullptr);
+ event, event.root_location(), nullptr);
}
PointerWatcherEventRouter::EventTypes event_types() const {
@@ -64,10 +61,6 @@ class PointerWatcherEventRouterTest : public testing::Test {
}
private:
- base::test::ScopedTaskEnvironment scoped_task_environment_{
- base::test::ScopedTaskEnvironment::MainThreadType::UI};
- ScopedViewsTestHelper helper_;
-
DISALLOW_COPY_AND_ASSIGN(PointerWatcherEventRouterTest);
};
@@ -244,36 +237,4 @@ TEST_F(PointerWatcherEventRouterTest, PointerWatcherMove) {
EXPECT_FALSE(watcher2.last_event_observed());
}
-TEST_F(PointerWatcherEventRouterTest, SecondaryDisplay) {
- PointerWatcherEventRouter* pointer_watcher_event_router =
- MusClient::Get()->pointer_watcher_event_router();
- TestPointerWatcher watcher;
- pointer_watcher_event_router->AddPointerWatcher(&watcher, false);
-
- ScreenMus* screen = MusClient::Get()->screen();
- const uint64_t kFirstDisplayId = screen->GetPrimaryDisplay().id();
-
- // The first display is at 0,0.
- ASSERT_TRUE(screen->GetPrimaryDisplay().bounds().origin().IsOrigin());
-
- // Add a secondary display to the right of the primary.
- const uint64_t kSecondDisplayId = 222;
- screen->display_list().AddDisplay(
- display::Display(kSecondDisplayId, gfx::Rect(800, 0, 640, 480)),
- display::DisplayList::Type::NOT_PRIMARY);
-
- ui::PointerEvent tap_event(
- ui::ET_POINTER_DOWN, gfx::Point(1, 1), gfx::Point(1, 1), ui::EF_NONE, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks());
-
- OnPointerEventObserved(tap_event, kFirstDisplayId);
- EXPECT_EQ(gfx::Point(1, 1), watcher.last_location_in_screen());
-
- OnPointerEventObserved(tap_event, kSecondDisplayId);
- EXPECT_EQ(gfx::Point(801, 1), watcher.last_location_in_screen());
-
- pointer_watcher_event_router->RemovePointerWatcher(&watcher);
-}
-
} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host.cc b/chromium/ui/views/mus/remote_view/remote_view_host.cc
index c5f9e577de0..a203d2b14fd 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_host.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.cc
@@ -22,7 +22,7 @@ void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
int embed_flags,
EmbedCallback callback) {
// Only works with mus.
- DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstanceDontCreate()->mode());
+ DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstance()->mode());
embed_token_ = embed_token;
embed_flags_ = embed_flags;
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
index f87a3202ebc..f396829094d 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
@@ -14,6 +14,7 @@
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tracker.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/mus/remote_view/remote_view_provider_test_api.h"
@@ -101,7 +102,7 @@ class RemoteViewProviderTest : public aura::test::AuraTestBase {
base::BindRepeating([](base::RunLoop* run_loop) { run_loop->Quit(); },
&run_loop));
- const ui::Id embedder_window_id =
+ const ws::Id embedder_window_id =
aura::WindowMus::Get(embedder)->server_id();
window_tree()->RemoveEmbedderWindow(embedder_window_id);
run_loop.Run();
@@ -159,11 +160,15 @@ TEST_F(RemoteViewProviderTest, EmbedAgain) {
aura::Window* embedder = SimulateEmbed();
ASSERT_TRUE(embedder);
+ aura::WindowTracker window_tracker;
+ window_tracker.Add(embedder);
SimulateEmbedderClose(embedder);
+ // SimulateEmbedderClose() should delete |embedder|.
+ EXPECT_TRUE(window_tracker.windows().empty());
aura::Window* new_embedder = SimulateEmbed();
+ // SimulateEmbed() should create a new window.
ASSERT_TRUE(new_embedder);
- EXPECT_NE(new_embedder, embedder);
}
} // namespace views
diff --git a/chromium/ui/views/mus/screen_mus.cc b/chromium/ui/views/mus/screen_mus.cc
index 1238f81aefe..b4c9a2668bd 100644
--- a/chromium/ui/views/mus/screen_mus.cc
+++ b/chromium/ui/views/mus/screen_mus.cc
@@ -5,8 +5,6 @@
#include "ui/views/mus/screen_mus.h"
#include "base/stl_util.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/ui/public/interfaces/constants.mojom.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/window.h"
@@ -19,9 +17,9 @@ namespace mojo {
template <>
struct TypeConverter<views::WindowManagerFrameValues,
- ui::mojom::FrameDecorationValuesPtr> {
+ ws::mojom::FrameDecorationValuesPtr> {
static views::WindowManagerFrameValues Convert(
- const ui::mojom::FrameDecorationValuesPtr& input) {
+ const ws::mojom::FrameDecorationValuesPtr& input) {
views::WindowManagerFrameValues result;
result.normal_insets = input->normal_client_area_insets;
result.maximized_insets = input->maximized_client_area_insets;
@@ -36,46 +34,17 @@ namespace views {
using Type = display::DisplayList::Type;
-ScreenMus::ScreenMus(ScreenMusDelegate* delegate)
- : delegate_(delegate), screen_provider_observer_binding_(this) {
+ScreenMus::ScreenMus(ScreenMusDelegate* delegate) : delegate_(delegate) {
DCHECK(delegate);
- display::Screen::SetScreenInstance(this);
}
-ScreenMus::~ScreenMus() {
- DCHECK_EQ(this, display::Screen::GetScreen());
- display::Screen::SetScreenInstance(nullptr);
-}
-
-void ScreenMus::InitDeprecated(service_manager::Connector* connector) {
- connector->BindInterface(ui::mojom::kServiceName, &screen_provider_);
-
- ui::mojom::ScreenProviderObserverPtr observer;
- screen_provider_observer_binding_.Bind(mojo::MakeRequest(&observer));
- screen_provider_->AddObserver(std::move(observer));
-
- // We need the set of displays before we can continue. Wait for it.
- //
- // TODO(rockot): Do something better here. This should not have to block tasks
- // from running on the calling thread. http://crbug.com/594852.
- bool success = screen_provider_observer_binding_.WaitForIncomingMethodCall();
-
- // 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()) {
- DCHECK(screen_provider_.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::Display(0xFFFFFFFF, gfx::Rect(0, 0, 801, 802)), Type::PRIMARY);
- }
-}
+ScreenMus::~ScreenMus() = default;
void ScreenMus::OnDisplaysChanged(
- std::vector<ui::mojom::WsDisplayPtr> ws_displays,
+ std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
- int64_t internal_display_id) {
+ int64_t internal_display_id,
+ int64_t display_id_for_new_windows) {
const bool primary_changed = primary_display_id != GetPrimaryDisplay().id();
int64_t handled_display_id = display::kInvalidDisplayId;
const WindowManagerFrameValues initial_frame_values =
@@ -88,7 +57,6 @@ void ScreenMus::OnDisplaysChanged(
handled_display_id = primary_display_id;
for (auto& ws_display_ptr : ws_displays) {
if (ws_display_ptr->display.id() == primary_display_id) {
- // TODO(sky): Make WindowManagerFrameValues per display.
WindowManagerFrameValues frame_values =
ws_display_ptr->frame_decoration_values
.To<WindowManagerFrameValues>();
@@ -130,6 +98,8 @@ void ScreenMus::OnDisplaysChanged(
initial_frame_values != WindowManagerFrameValues::instance()) {
delegate_->OnWindowManagerFrameValuesChanged();
}
+
+ SetDisplayForNewWindows(display_id_for_new_windows);
}
display::Display ScreenMus::GetDisplayNearestWindow(
diff --git a/chromium/ui/views/mus/screen_mus.h b/chromium/ui/views/mus/screen_mus.h
index ad94f9f1090..36bb1909ced 100644
--- a/chromium/ui/views/mus/screen_mus.h
+++ b/chromium/ui/views/mus/screen_mus.h
@@ -5,36 +5,29 @@
#ifndef UI_VIEWS_MUS_SCREEN_MUS_H_
#define UI_VIEWS_MUS_SCREEN_MUS_H_
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/ui/public/interfaces/screen_provider.mojom.h"
+#include "services/ws/public/mojom/screen_provider_observer.mojom.h"
#include "ui/display/screen_base.h"
#include "ui/views/mus/mus_export.h"
-namespace service_manager {
-class Connector;
-}
-
namespace views {
class ScreenMusDelegate;
-// Screen implementation backed by ui::mojom::ScreenProvider.
+// Screen implementation that gets information from
+// ws::mojom::ScreenProviderObserver.
+//
+// NOTE: this is not necessarily installed as the Screen implementation.
class VIEWS_MUS_EXPORT ScreenMus : public display::ScreenBase,
- public ui::mojom::ScreenProviderObserver {
+ public ws::mojom::ScreenProviderObserver {
public:
explicit ScreenMus(ScreenMusDelegate* delegate);
~ScreenMus() override;
- // TODO(sky): not used with ws2. Remove. https://crbug.com/842365.
- void InitDeprecated(service_manager::Connector* connector);
-
- // ui::mojom::ScreenProviderObserver:
- void OnDisplaysChanged(std::vector<ui::mojom::WsDisplayPtr> ws_displays,
+ // ws::mojom::ScreenProviderObserver:
+ void OnDisplaysChanged(std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
- int64_t internal_display_id) override;
-
- private:
- friend class ScreenMusTestApi;
+ int64_t internal_display_id,
+ int64_t display_id_for_new_windows) override;
// display::Screen:
display::Display GetDisplayNearestWindow(
@@ -43,10 +36,8 @@ class VIEWS_MUS_EXPORT ScreenMus : public display::ScreenBase,
bool IsWindowUnderCursor(gfx::NativeWindow window) override;
aura::Window* GetWindowAtScreenPoint(const gfx::Point& point) override;
+ private:
ScreenMusDelegate* delegate_;
- ui::mojom::ScreenProviderPtr screen_provider_;
- mojo::Binding<ui::mojom::ScreenProviderObserver>
- screen_provider_observer_binding_;
DISALLOW_COPY_AND_ASSIGN(ScreenMus);
};
diff --git a/chromium/ui/views/mus/screen_mus_unittest.cc b/chromium/ui/views/mus/screen_mus_unittest.cc
index 6a5e8755414..e27751a1494 100644
--- a/chromium/ui/views/mus/screen_mus_unittest.cc
+++ b/chromium/ui/views/mus/screen_mus_unittest.cc
@@ -6,46 +6,31 @@
#include "base/command_line.h"
#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
#include "ui/views/test/scoped_views_test_helper.h"
-#include "ui/views/test/views_test_base.h"
namespace views {
-
-class ScreenMusTestApi {
- public:
- static void CallOnDisplaysChanged(
- ScreenMus* screen,
- std::vector<ui::mojom::WsDisplayPtr> ws_displays,
- int64_t primary_display_id,
- int64_t internal_display_id) {
- screen->OnDisplaysChanged(std::move(ws_displays), primary_display_id,
- internal_display_id);
- }
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ScreenMusTestApi);
-};
-
namespace {
-std::vector<ui::mojom::WsDisplayPtr> ConvertDisplayToWsDisplays(
+std::vector<ws::mojom::WsDisplayPtr> ConvertDisplayToWsDisplays(
const std::vector<display::Display>& displays) {
- std::vector<ui::mojom::WsDisplayPtr> results;
+ std::vector<ws::mojom::WsDisplayPtr> results;
for (const auto& display : displays) {
- ui::mojom::WsDisplayPtr display_ptr = ui::mojom::WsDisplay::New();
+ ws::mojom::WsDisplayPtr display_ptr = ws::mojom::WsDisplay::New();
display_ptr->display = display;
display_ptr->frame_decoration_values =
- ui::mojom::FrameDecorationValues::New();
+ ws::mojom::FrameDecorationValues::New();
results.push_back(std::move(display_ptr));
}
return results;
}
-TEST(ScreenMusTest, ConsistentDisplayInHighDPI) {
+TEST(ScreenMusScaleFactorTest, ConsistentDisplayInHighDPI) {
base::test::ScopedTaskEnvironment task_environment(
base::test::ScopedTaskEnvironment::MainThreadType::UI);
+ // Must be set before |test_helper| is constructed.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kForceDeviceScaleFactor, "2");
ScopedViewsTestHelper test_helper;
@@ -58,10 +43,20 @@ TEST(ScreenMusTest, ConsistentDisplayInHighDPI) {
}
}
-TEST(ScreenMusTest, PrimaryChangedToExisting) {
- base::test::ScopedTaskEnvironment task_environment(
- base::test::ScopedTaskEnvironment::MainThreadType::UI);
- ScopedViewsTestHelper test_helper;
+class ScreenMusTest : public testing::Test {
+ public:
+ ScreenMusTest() = default;
+ ~ScreenMusTest() override = default;
+
+ private:
+ base::test::ScopedTaskEnvironment task_environment_{
+ base::test::ScopedTaskEnvironment::MainThreadType::UI};
+ ScopedViewsTestHelper test_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenMusTest);
+};
+
+TEST_F(ScreenMusTest, PrimaryChangedToExisting) {
ScreenMus* screen = static_cast<ScreenMus*>(display::Screen::GetScreen());
std::vector<display::Display> displays = screen->GetAllDisplays();
ASSERT_FALSE(displays.empty());
@@ -69,17 +64,14 @@ TEST(ScreenMusTest, PrimaryChangedToExisting) {
// Convert to a single display with a different primary id.
displays.resize(1);
displays[0].set_id(displays[0].id() + 1);
- ScreenMusTestApi::CallOnDisplaysChanged(
- screen, ConvertDisplayToWsDisplays(displays), displays[0].id(), 0);
+ screen->OnDisplaysChanged(ConvertDisplayToWsDisplays(displays),
+ displays[0].id(), 0, 0);
ASSERT_EQ(1u, screen->GetAllDisplays().size());
EXPECT_EQ(displays[0].id(), screen->GetAllDisplays()[0].id());
EXPECT_EQ(displays[0].id(), screen->GetPrimaryDisplay().id());
}
-TEST(ScreenMusTest, AddAndUpdate) {
- base::test::ScopedTaskEnvironment task_environment(
- base::test::ScopedTaskEnvironment::MainThreadType::UI);
- ScopedViewsTestHelper test_helper;
+TEST_F(ScreenMusTest, AddAndUpdate) {
ScreenMus* screen = static_cast<ScreenMus*>(display::Screen::GetScreen());
std::vector<display::Display> displays = screen->GetAllDisplays();
ASSERT_FALSE(displays.empty());
@@ -91,8 +83,8 @@ TEST(ScreenMusTest, AddAndUpdate) {
displays[0].set_bounds(new_bounds);
displays.push_back(displays[0]);
displays[1].set_id(displays[0].id() + 1);
- ScreenMusTestApi::CallOnDisplaysChanged(
- screen, ConvertDisplayToWsDisplays(displays), displays[1].id(), 0);
+ screen->OnDisplaysChanged(ConvertDisplayToWsDisplays(displays),
+ displays[1].id(), 0, 0);
ASSERT_EQ(2u, screen->GetAllDisplays().size());
ASSERT_TRUE(screen->display_list().FindDisplayById(displays[0].id()) !=
screen->display_list().displays().end());
@@ -105,5 +97,31 @@ TEST(ScreenMusTest, AddAndUpdate) {
EXPECT_EQ(displays[1].id(), screen->GetPrimaryDisplay().id());
}
+TEST_F(ScreenMusTest, SetDisplayForNewWindows) {
+ ScreenMus* screen = static_cast<ScreenMus*>(display::Screen::GetScreen());
+
+ // Set up 2 displays with display 1 as the display for new windows.
+ constexpr int64_t kDisplayId1 = 111;
+ constexpr int64_t kDisplayId2 = 222;
+ std::vector<display::Display> displays = {display::Display(kDisplayId1),
+ display::Display(kDisplayId2)};
+ screen->OnDisplaysChanged(ConvertDisplayToWsDisplays(displays), kDisplayId1,
+ kDisplayId1,
+ kDisplayId1 /* display_id_for_new_windows */);
+ EXPECT_EQ(kDisplayId1, screen->GetDisplayForNewWindows().id());
+
+ // Set display 2 as the display for new windows.
+ screen->OnDisplaysChanged(ConvertDisplayToWsDisplays(displays), kDisplayId1,
+ kDisplayId1,
+ kDisplayId2 /* display_id_for_new_windows */);
+ EXPECT_EQ(kDisplayId2, screen->GetDisplayForNewWindows().id());
+
+ // Set a bad display as the display for new windows. ScreenMus should fall
+ // back to the primary display.
+ screen->OnDisplaysChanged(ConvertDisplayToWsDisplays(displays), kDisplayId1,
+ kDisplayId1, 666 /* display_id_for_new_windows */);
+ EXPECT_EQ(kDisplayId1, screen->GetDisplayForNewWindows().id());
+}
+
} // namespace
} // namespace views
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
index 959f5ad7ede..40dafe4c9db 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ b/chromium/ui/views/mus/views_mus_test_suite.cc
@@ -22,7 +22,7 @@
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
-#include "services/ui/common/switches.h"
+#include "services/ws/common/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/window_tree_host_mus.h"
@@ -103,8 +103,6 @@ class ServiceManagerConnection {
MusClient::InitParams params;
params.connector = GetConnector();
params.identity = service_manager_identity_;
- params.bind_test_ws_interfaces = true;
- params.wtc_config = aura::WindowTreeClient::Config::kMus2;
return std::make_unique<MusClient>(params);
}
@@ -237,7 +235,7 @@ void ViewsMusTestSuite::Initialize() {
// Let other services 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(ui::switches::kUseTestConfig);
+ EnsureCommandLineSwitch(ws::switches::kUseTestConfig);
EnsureCommandLineSwitch(switches::kOverrideUseSoftwareGLForTests);
diff --git a/chromium/ui/views/mus/window_manager_constants_converters.cc b/chromium/ui/views/mus/window_manager_constants_converters.cc
index 90ee4793112..08d927dc013 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
-ui::mojom::WindowType
-TypeConverter<ui::mojom::WindowType, views::Widget::InitParams::Type>::Convert(
+ws::mojom::WindowType
+TypeConverter<ws::mojom::WindowType, views::Widget::InitParams::Type>::Convert(
views::Widget::InitParams::Type type) {
switch (type) {
case views::Widget::InitParams::TYPE_WINDOW:
- return ui::mojom::WindowType::WINDOW;
+ return ws::mojom::WindowType::WINDOW;
case views::Widget::InitParams::TYPE_PANEL:
- return ui::mojom::WindowType::PANEL;
+ return ws::mojom::WindowType::PANEL;
case views::Widget::InitParams::TYPE_WINDOW_FRAMELESS:
- return ui::mojom::WindowType::WINDOW_FRAMELESS;
+ return ws::mojom::WindowType::WINDOW_FRAMELESS;
case views::Widget::InitParams::TYPE_CONTROL:
- return ui::mojom::WindowType::CONTROL;
+ return ws::mojom::WindowType::CONTROL;
case views::Widget::InitParams::TYPE_POPUP:
- return ui::mojom::WindowType::POPUP;
+ return ws::mojom::WindowType::POPUP;
case views::Widget::InitParams::TYPE_MENU:
- return ui::mojom::WindowType::MENU;
+ return ws::mojom::WindowType::MENU;
case views::Widget::InitParams::TYPE_TOOLTIP:
- return ui::mojom::WindowType::TOOLTIP;
+ return ws::mojom::WindowType::TOOLTIP;
case views::Widget::InitParams::TYPE_BUBBLE:
- return ui::mojom::WindowType::BUBBLE;
+ return ws::mojom::WindowType::BUBBLE;
case views::Widget::InitParams::TYPE_DRAG:
- return ui::mojom::WindowType::DRAG;
+ return ws::mojom::WindowType::DRAG;
}
- return ui::mojom::WindowType::POPUP;
+ return ws::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 e9493eb6c84..c24deec94e3 100644
--- a/chromium/ui/views/mus/window_manager_constants_converters.h
+++ b/chromium/ui/views/mus/window_manager_constants_converters.h
@@ -5,7 +5,7 @@
#ifndef UI_VIEWS_MUS_WINDOW_MANAGER_CONSTANTS_CONVERTERS_H_
#define UI_VIEWS_MUS_WINDOW_MANAGER_CONSTANTS_CONVERTERS_H_
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/widget/widget.h"
@@ -13,8 +13,8 @@ namespace mojo {
template <>
struct VIEWS_MUS_EXPORT
- TypeConverter<ui::mojom::WindowType, views::Widget::InitParams::Type> {
- static ui::mojom::WindowType Convert(views::Widget::InitParams::Type type);
+ TypeConverter<ws::mojom::WindowType, views::Widget::InitParams::Type> {
+ static ws::mojom::WindowType Convert(views::Widget::InitParams::Type type);
};
} // namespace mojo
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_bottom.png b/chromium/ui/views/resources/default_100_percent/bubble_bottom.png
deleted file mode 100644
index 03dde937b12..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_bottom_left.png b/chromium/ui/views/resources/default_100_percent/bubble_bottom_left.png
deleted file mode 100644
index 2e6b2482f36..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_bottom_right.png b/chromium/ui/views/resources/default_100_percent/bubble_bottom_right.png
deleted file mode 100644
index 286449ec616..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_left.png b/chromium/ui/views/resources/default_100_percent/bubble_left.png
deleted file mode 100644
index 341df39e3db..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_pointer_bottom.png b/chromium/ui/views/resources/default_100_percent/bubble_pointer_bottom.png
deleted file mode 100644
index 4744fed638b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_pointer_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_pointer_left.png b/chromium/ui/views/resources/default_100_percent/bubble_pointer_left.png
deleted file mode 100644
index 60695bd5665..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_pointer_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_pointer_right.png b/chromium/ui/views/resources/default_100_percent/bubble_pointer_right.png
deleted file mode 100644
index fd636c5cf7c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_pointer_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_pointer_top.png b/chromium/ui/views/resources/default_100_percent/bubble_pointer_top.png
deleted file mode 100644
index 1f66b21b84b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_pointer_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_right.png b/chromium/ui/views/resources/default_100_percent/bubble_right.png
deleted file mode 100644
index 1323a1cd9d7..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_top.png b/chromium/ui/views/resources/default_100_percent/bubble_top.png
deleted file mode 100644
index 50b6817f4f2..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_top_left.png b/chromium/ui/views/resources/default_100_percent/bubble_top_left.png
deleted file mode 100644
index 60a2c987a0a..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/bubble_top_right.png b/chromium/ui/views/resources/default_100_percent/bubble_top_right.png
deleted file mode 100644
index 3821309d969..00000000000
--- a/chromium/ui/views/resources/default_100_percent/bubble_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/close.png b/chromium/ui/views/resources/default_100_percent/close.png
index 75f418dcffd..6d21523a0a4 100644
--- a/chromium/ui/views/resources/default_100_percent/close.png
+++ b/chromium/ui/views/resources/default_100_percent/close.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/close_hover.png b/chromium/ui/views/resources/default_100_percent/close_hover.png
index 67e605a8618..dcc9c8ac4f1 100644
--- a/chromium/ui/views/resources/default_100_percent/close_hover.png
+++ b/chromium/ui/views/resources/default_100_percent/close_hover.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/close_pressed.png b/chromium/ui/views/resources/default_100_percent/close_pressed.png
index 5eeb8a70373..502f5e9f4c5 100644
--- a/chromium/ui/views/resources/default_100_percent/close_pressed.png
+++ b/chromium/ui/views/resources/default_100_percent/close_pressed.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png
deleted file mode 100644
index e57800c914c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png
deleted file mode 100644
index 0a51f9af4bf..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png
deleted file mode 100644
index 428b3790da4..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_left.png
deleted file mode 100644
index 4c3d9b4a2e2..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_right.png
deleted file mode 100644
index 670b8189c98..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top.png
deleted file mode 100644
index 059af22c136..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png
deleted file mode 100644
index 43ac459fbe8..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png
deleted file mode 100644
index 8198a7de9eb..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png
deleted file mode 100644
index 6f5735eda96..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png
deleted file mode 100644
index fbef5a8c4a2..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png
deleted file mode 100644
index 1949fa4a5f5..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_left.png
deleted file mode 100644
index 7a77ed6d37b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_right.png
deleted file mode 100644
index 4f5a851a68e..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top.png
deleted file mode 100644
index 4ae2fb08875..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png
deleted file mode 100644
index 27933e9d6a4..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png
deleted file mode 100644
index 99d417c1db6..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png
deleted file mode 100644
index 3fff849fe39..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png
deleted file mode 100644
index 3fdd27ee328..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png
deleted file mode 100644
index 454ec3401de..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png
deleted file mode 100644
index 4c3e68b274c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png
deleted file mode 100644
index 6a67514b6ae..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png
deleted file mode 100644
index 0ba6a51dd75..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png
deleted file mode 100644
index d5cf1518da3..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png b/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png
deleted file mode 100644
index 2c1a022393a..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/maximize_hover.png b/chromium/ui/views/resources/default_100_percent/maximize_hover.png
index d17a2642be3..4eb77665b0d 100644
--- a/chromium/ui/views/resources/default_100_percent/maximize_hover.png
+++ b/chromium/ui/views/resources/default_100_percent/maximize_hover.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/maximize_pressed.png b/chromium/ui/views/resources/default_100_percent/maximize_pressed.png
index b5f66ad21db..f130060779e 100644
--- a/chromium/ui/views/resources/default_100_percent/maximize_pressed.png
+++ b/chromium/ui/views/resources/default_100_percent/maximize_pressed.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/restore_hover.png b/chromium/ui/views/resources/default_100_percent/restore_hover.png
index 88e93a3920c..eda294a64a6 100644
--- a/chromium/ui/views/resources/default_100_percent/restore_hover.png
+++ b/chromium/ui/views/resources/default_100_percent/restore_hover.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/restore_pressed.png b/chromium/ui/views/resources/default_100_percent/restore_pressed.png
index 88e93a3920c..eda294a64a6 100644
--- a/chromium/ui/views/resources/default_100_percent/restore_pressed.png
+++ b/chromium/ui/views/resources/default_100_percent/restore_pressed.png
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_bottom.png b/chromium/ui/views/resources/default_200_percent/bubble_bottom.png
deleted file mode 100644
index e89a6811968..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_bottom_left.png b/chromium/ui/views/resources/default_200_percent/bubble_bottom_left.png
deleted file mode 100644
index 207f7af34cc..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_bottom_right.png b/chromium/ui/views/resources/default_200_percent/bubble_bottom_right.png
deleted file mode 100644
index d955a43915a..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_left.png b/chromium/ui/views/resources/default_200_percent/bubble_left.png
deleted file mode 100644
index 69844562e02..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_pointer_bottom.png b/chromium/ui/views/resources/default_200_percent/bubble_pointer_bottom.png
deleted file mode 100644
index e2ef165f821..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_pointer_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_pointer_left.png b/chromium/ui/views/resources/default_200_percent/bubble_pointer_left.png
deleted file mode 100644
index 94f49fb7b0d..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_pointer_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_pointer_right.png b/chromium/ui/views/resources/default_200_percent/bubble_pointer_right.png
deleted file mode 100644
index b72e34c3a9b..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_pointer_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_pointer_top.png b/chromium/ui/views/resources/default_200_percent/bubble_pointer_top.png
deleted file mode 100644
index 59714dabd4b..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_pointer_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_right.png b/chromium/ui/views/resources/default_200_percent/bubble_right.png
deleted file mode 100644
index d82631a0380..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_top.png b/chromium/ui/views/resources/default_200_percent/bubble_top.png
deleted file mode 100644
index 004f5655948..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_top_left.png b/chromium/ui/views/resources/default_200_percent/bubble_top_left.png
deleted file mode 100644
index bd25b50e94d..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/bubble_top_right.png b/chromium/ui/views/resources/default_200_percent/bubble_top_right.png
deleted file mode 100644
index f5feea6afc9..00000000000
--- a/chromium/ui/views/resources/default_200_percent/bubble_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png
deleted file mode 100644
index bc8b1950e2c..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png
deleted file mode 100644
index f7bef138581..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png
deleted file mode 100644
index c5b1fc2e7a4..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_left.png
deleted file mode 100644
index 4a4ce5ff918..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_right.png
deleted file mode 100644
index 8a502c80b51..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top.png
deleted file mode 100644
index 9a85702fb4b..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png
deleted file mode 100644
index 9046e454fae..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png
deleted file mode 100644
index 82e788dd6b5..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png
deleted file mode 100644
index 5239c4644d9..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png
deleted file mode 100644
index e958b6ffc8e..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png
deleted file mode 100644
index 21504462080..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_left.png
deleted file mode 100644
index 30d93bd269a..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_right.png
deleted file mode 100644
index 35999b1e7de..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top.png
deleted file mode 100644
index 022e48f44ba..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png
deleted file mode 100644
index 9a8823f5a65..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png
deleted file mode 100644
index fb1d21b61a4..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png
deleted file mode 100644
index 93461aa0b72..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png
deleted file mode 100644
index 286bcb910bb..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png
deleted file mode 100644
index ed64369766f..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png
deleted file mode 100644
index 7048347cbb5..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png
deleted file mode 100644
index e1008843e94..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png
deleted file mode 100644
index f187da42423..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png
deleted file mode 100644
index 4bda3e604fb..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png b/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png
deleted file mode 100644
index ad5fa498e3b..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.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 112662e690b..9b6b99641ba 100644
--- a/chromium/ui/views/resources/views_resources.grd
+++ b/chromium/ui/views/resources/views_resources.grd
@@ -15,18 +15,6 @@
<structure type="chrome_scaled_image" name="IDR_APP_TOP_CENTER" file="app_top_center.png" />
<structure type="chrome_scaled_image" name="IDR_APP_TOP_LEFT" file="app_top_left.png" />
<structure type="chrome_scaled_image" name="IDR_APP_TOP_RIGHT" file="app_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_B" file="bubble_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_BL" file="bubble_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_BR" file="bubble_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_B_ARROW" file="bubble_pointer_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_L" file="bubble_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_L_ARROW" file="bubble_pointer_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_R" file="bubble_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_R_ARROW" file="bubble_pointer_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_T" file="bubble_top.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_TL" file="bubble_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_TR" file="bubble_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_BUBBLE_T_ARROW" file="bubble_pointer_top.png" />
<structure type="chrome_scaled_image" name="IDR_BUTTON_DISABLED" file="common/button_inactive.png" />
<structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_HOVER" file="common/button_focused_hover.png" />
<structure type="chrome_scaled_image" name="IDR_BUTTON_FOCUSED_NORMAL" file="common/button_focused.png" />
@@ -216,30 +204,6 @@
<structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_CENTER" file="common/window_top_center.png" />
<structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_LEFT_CORNER" file="common/window_top_left_corner.png" />
<structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_RIGHT_CORNER" file="common/window_top_right_corner.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM" file="common/window_bubble_shadow_big_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT" file="common/window_bubble_shadow_big_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT" file="common/window_bubble_shadow_big_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT" file="common/window_bubble_shadow_big_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT" file="common/window_bubble_shadow_big_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP" file="common/window_bubble_shadow_big_top.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT" file="common/window_bubble_shadow_big_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT" file="common/window_bubble_shadow_big_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM" file="common/window_bubble_shadow_spike_big_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT" file="common/window_bubble_shadow_spike_big_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT" file="common/window_bubble_shadow_spike_big_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP" file="common/window_bubble_shadow_spike_big_top.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM" file="common/window_bubble_shadow_small_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT" file="common/window_bubble_shadow_small_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT" file="common/window_bubble_shadow_small_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT" file="common/window_bubble_shadow_small_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT" file="common/window_bubble_shadow_small_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP" file="common/window_bubble_shadow_small_top.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT" file="common/window_bubble_shadow_small_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT" file="common/window_bubble_shadow_small_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM" file="common/window_bubble_shadow_spike_small_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT" file="common/window_bubble_shadow_spike_small_left.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT" file="common/window_bubble_shadow_spike_small_right.png" />
- <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP" file="common/window_bubble_shadow_spike_small_top.png" />
</structures>
</release>
</grit>
diff --git a/chromium/ui/views/selection_controller.cc b/chromium/ui/views/selection_controller.cc
index 61d83ff3750..b04a99300b4 100644
--- a/chromium/ui/views/selection_controller.cc
+++ b/chromium/ui/views/selection_controller.cc
@@ -75,7 +75,8 @@ bool SelectionController::OnMousePressed(
initial_focus_state == InitialFocusStateOnMousePress::UNFOCUSED) {
SelectAll();
} else if (PlatformStyle::kSelectWordOnRightClick &&
- !render_text->IsPointInSelection(event.location())) {
+ !render_text->IsPointInSelection(event.location()) &&
+ IsInsideText(event.location())) {
SelectWord(event.location());
}
}
@@ -223,4 +224,16 @@ void SelectionController::SelectThroughLastDragLocation() {
delegate_->OnAfterPointerAction(false, true);
}
+bool SelectionController::IsInsideText(const gfx::Point& point) {
+ gfx::RenderText* render_text = GetRenderText();
+ std::vector<gfx::Rect> bounds_rects = render_text->GetSubstringBounds(
+ gfx::Range(0, render_text->text().length()));
+
+ for (const auto& bounds : bounds_rects)
+ if (bounds.Contains(point))
+ return true;
+
+ return false;
+}
+
} // namespace views
diff --git a/chromium/ui/views/selection_controller.h b/chromium/ui/views/selection_controller.h
index 46ec0607d11..c4382f1bf89 100644
--- a/chromium/ui/views/selection_controller.h
+++ b/chromium/ui/views/selection_controller.h
@@ -82,6 +82,9 @@ class VIEWS_EXPORT SelectionController {
// |last_drag_location_|. Can be called asynchronously, through a timer.
void SelectThroughLastDragLocation();
+ // Returns whether |point| is inside any substring of the text.
+ bool IsInsideText(const gfx::Point& point);
+
// A timer and point used to modify the selection when dragging.
base::RepeatingTimer drag_selection_timer_;
gfx::Point last_drag_location_;
diff --git a/chromium/ui/views/selection_controller_unittest.cc b/chromium/ui/views/selection_controller_unittest.cc
new file mode 100644
index 00000000000..e28d5302029
--- /dev/null
+++ b/chromium/ui/views/selection_controller_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2018 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/selection_controller.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/gfx/render_text.h"
+#include "ui/views/metrics.h"
+#include "ui/views/selection_controller_delegate.h"
+#include "ui/views/style/platform_style.h"
+
+namespace views {
+namespace {
+
+const gfx::Point CenterLeft(const gfx::Rect& rect) {
+ return gfx::Point(rect.x(), rect.CenterPoint().y());
+}
+
+const gfx::Point CenterRight(const gfx::Rect& rect) {
+ return gfx::Point(rect.right(), rect.CenterPoint().y());
+}
+
+class TestSelectionControllerDelegate : public SelectionControllerDelegate {
+ public:
+ TestSelectionControllerDelegate(gfx::RenderText* render_text)
+ : render_text_(render_text) {}
+ ~TestSelectionControllerDelegate() override = default;
+
+ gfx::RenderText* GetRenderTextForSelectionController() override {
+ return render_text_;
+ }
+
+ bool IsReadOnly() const override { return true; }
+ bool SupportsDrag() const override { return true; }
+ bool HasTextBeingDragged() const override { return false; }
+ void SetTextBeingDragged(bool value) override {}
+ int GetViewHeight() const override {
+ return render_text_->GetStringSize().height();
+ }
+ int GetViewWidth() const override {
+ return render_text_->GetStringSize().width();
+ }
+ int GetDragSelectionDelay() const override { return 0; }
+ void OnBeforePointerAction() override {}
+ void OnAfterPointerAction(bool text_changed,
+ bool selection_changed) override {}
+ bool PasteSelectionClipboard() override { return false; }
+ void UpdateSelectionClipboard() override {}
+
+ private:
+ gfx::RenderText* render_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSelectionControllerDelegate);
+};
+
+class SelectionControllerTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ render_text_ = gfx::RenderText::CreateHarfBuzzInstance();
+ delegate_ =
+ std::make_unique<TestSelectionControllerDelegate>(render_text_.get());
+ controller_ = std::make_unique<SelectionController>(delegate_.get());
+ }
+
+ SelectionControllerTest() = default;
+ ~SelectionControllerTest() override = default;
+
+ void SetText(const std::string& text) {
+ render_text_->SetText(base::ASCIIToUTF16(text));
+ }
+
+ std::string GetSelectedText() {
+ return base::UTF16ToASCII(
+ render_text_->GetTextFromRange(render_text_->selection()));
+ }
+
+ void LeftMouseDown(const gfx::Point& location, bool focused = false) {
+ PressMouseButton(location, ui::EF_LEFT_MOUSE_BUTTON, focused);
+ }
+
+ void LeftMouseUp() { ReleaseMouseButton(ui::EF_LEFT_MOUSE_BUTTON); }
+
+ void DragMouse(const gfx::Point& location) {
+ mouse_location_ = location;
+ controller_->OnMouseDragged(ui::MouseEvent(ui::ET_MOUSE_DRAGGED, location,
+ location, last_event_time_,
+ mouse_flags_, 0));
+ }
+
+ void RightMouseDown(const gfx::Point& location, bool focused = false) {
+ PressMouseButton(location, ui::EF_RIGHT_MOUSE_BUTTON, focused);
+ }
+
+ void RightMouseUp() { ReleaseMouseButton(ui::EF_RIGHT_MOUSE_BUTTON); }
+
+ const gfx::Rect BoundsOfChar(int index) {
+ return render_text_->GetSubstringBounds(gfx::Range(index, index + 1))[0];
+ }
+
+ private:
+ void PressMouseButton(const gfx::Point& location, int button, bool focused) {
+ DCHECK(!(mouse_flags_ & button));
+ mouse_flags_ |= button;
+ mouse_location_ = location;
+ // Ensure that mouse presses are spaced apart by at least the double-click
+ // interval to avoid triggering a double-click.
+ last_event_time_ +=
+ base::TimeDelta::FromMilliseconds(views::GetDoubleClickInterval() + 1);
+ controller_->OnMousePressed(
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, location, location,
+ last_event_time_, mouse_flags_, button),
+ false,
+ focused ? SelectionController::FOCUSED
+ : SelectionController::UNFOCUSED);
+ }
+
+ void ReleaseMouseButton(int button) {
+ DCHECK(mouse_flags_ & button);
+ mouse_flags_ &= ~button;
+ controller_->OnMouseReleased(
+ ui::MouseEvent(ui::ET_MOUSE_RELEASED, mouse_location_, mouse_location_,
+ last_event_time_, mouse_flags_, button));
+ }
+
+ std::unique_ptr<gfx::RenderText> render_text_;
+ std::unique_ptr<TestSelectionControllerDelegate> delegate_;
+ std::unique_ptr<SelectionController> controller_;
+
+ int mouse_flags_ = 0;
+ gfx::Point mouse_location_;
+ base::TimeTicks last_event_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(SelectionControllerTest);
+};
+
+TEST_F(SelectionControllerTest, ClickAndDragToSelect) {
+ SetText("abc def");
+ EXPECT_EQ("", GetSelectedText());
+
+ LeftMouseDown(CenterLeft(BoundsOfChar(0)));
+ DragMouse(CenterRight(BoundsOfChar(0)));
+ EXPECT_EQ("a", GetSelectedText());
+
+ DragMouse(CenterRight(BoundsOfChar(2)));
+ EXPECT_EQ("abc", GetSelectedText());
+
+ LeftMouseUp();
+ EXPECT_EQ("abc", GetSelectedText());
+
+ LeftMouseDown(CenterRight(BoundsOfChar(3)));
+ EXPECT_EQ("", GetSelectedText());
+
+ DragMouse(CenterRight(BoundsOfChar(4)));
+ EXPECT_EQ("d", GetSelectedText());
+}
+
+TEST_F(SelectionControllerTest, RightClickWhenUnfocused) {
+ SetText("abc def");
+
+ RightMouseDown(CenterRight(BoundsOfChar(0)));
+ if (PlatformStyle::kSelectAllOnRightClickWhenUnfocused)
+ EXPECT_EQ("abc def", GetSelectedText());
+ else
+ EXPECT_EQ("", GetSelectedText());
+}
+
+TEST_F(SelectionControllerTest, RightClickSelectsWord) {
+ SetText("abc def");
+ RightMouseDown(CenterRight(BoundsOfChar(5)), true);
+ if (PlatformStyle::kSelectWordOnRightClick)
+ EXPECT_EQ("def", GetSelectedText());
+ else
+ EXPECT_EQ("", GetSelectedText());
+}
+
+// Regression test for https://crbug.com/856609
+TEST_F(SelectionControllerTest, RightClickPastEndDoesntSelectLastWord) {
+ SetText("abc def");
+
+ RightMouseDown(CenterRight(BoundsOfChar(6)), true);
+ EXPECT_EQ("", GetSelectedText());
+}
+
+} // namespace
+} // 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 6e5d1816bff..ae97f1994e4 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -9,6 +9,7 @@
#include "base/time/time.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
+#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#include "ui/base/resource/resource_bundle.h"
@@ -129,10 +130,11 @@ gfx::Image* GetHandleImage(gfx::SelectionBound::Type bound_type) {
}
// Calculates the bounds of the widget containing the selection handle based
-// on the SelectionBound's type and location
+// on the SelectionBound's type and location.
gfx::Rect GetSelectionWidgetBounds(const gfx::SelectionBound& bound) {
gfx::Size image_size = GetHandleImage(bound.type())->Size();
int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding;
+ // Extend the widget height to handle touch events below the painted image.
int widget_height = bound.GetHeight() + image_size.height() +
kSelectionHandleVerticalVisualOffset +
kSelectionHandleVertPadding;
@@ -200,21 +202,40 @@ gfx::Rect BoundToRect(const gfx::SelectionBound& bound) {
bound.edge_bottom_rounded());
}
-} // namespace
-
-namespace views {
-
-typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView;
-
-// A WindowTargeter that shifts the hit-test target down - away from the text
-// cursor and expanding the hit-test area just below the visible drag handle.
+// A WindowTargeter that insets the top of the touch handle's hit-test region.
+// This ensures that the client receives touch events above the painted image.
+// The widget extends its height to handle touch events below the painted image.
class TouchHandleWindowTargeter : public aura::WindowTargeter {
public:
- void SetHitTestOffset(int offset) {
- SetInsets(gfx::Insets(offset, 0, -offset, 0));
+ explicit TouchHandleWindowTargeter(aura::Window* window) : window_(window) {}
+ ~TouchHandleWindowTargeter() override = default;
+
+ void SetTopInset(int inset) { SetInsets(gfx::Insets(inset, 0, 0, 0)); }
+
+ // aura::WindowTargeter:
+ void OnSetInsets(const gfx::Insets& last_mouse_extend,
+ const gfx::Insets& last_touch_extend) override {
+ // Send the targeter insets to the window service if this is a mus client.
+ // This helps the window service send events directly to the text window.
+ // OnSetInsets is generally only called when the insets actually change.
+ if (window_->env()->mode() == aura::Env::Mode::MUS) {
+ gfx::Rect mask(window_->bounds().size());
+ mask.Inset(touch_extend());
+ aura::WindowPortMus::Get(window_->GetRootWindow())->SetHitTestMask(mask);
+ }
}
+
+ private:
+ aura::Window* window_;
+ DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter);
};
+} // namespace
+
+namespace views {
+
+using EditingHandleView = TouchSelectionControllerImpl::EditingHandleView;
+
// A View that displays the text selection handle.
class TouchSelectionControllerImpl::EditingHandleView
: public views::WidgetDelegateView {
@@ -230,8 +251,8 @@ class TouchSelectionControllerImpl::EditingHandleView
widget_.reset(CreateTouchSelectionPopupWidget(context, this));
aura::Window* window = widget_->GetNativeWindow();
- targeter_ = new TouchHandleWindowTargeter();
- window->SetEventTargeter(std::unique_ptr<ui::EventTargeter>(targeter_));
+ targeter_ = new TouchHandleWindowTargeter(window);
+ window->SetEventTargeter(std::unique_ptr<aura::WindowTargeter>(targeter_));
// We are owned by the TouchSelectionControllerImpl.
set_owned_by_client();
@@ -357,8 +378,9 @@ class TouchSelectionControllerImpl::EditingHandleView
wm::ConvertPointFromScreen(window, &edge_bottom);
selection_bound_.SetEdge(gfx::PointF(edge_top), gfx::PointF(edge_bottom));
}
- targeter_->SetHitTestOffset(selection_bound_.GetHeight() +
- kSelectionHandleVerticalVisualOffset);
+
+ targeter_->SetTopInset(selection_bound_.GetHeight() +
+ kSelectionHandleVerticalVisualOffset);
}
void SetDrawInvisible(bool draw_invisible) {
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 df2048dfd10..7a99a8f697c 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
+++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
@@ -18,7 +18,7 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/text_utils.h"
#include "ui/strings/grit/ui_strings.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/layout/box_layout.h"
diff --git a/chromium/ui/views/vector_icons/ic_close.icon b/chromium/ui/views/vector_icons/ic_close.icon
index 686da72bcda..f298b77712b 100644
--- a/chromium/ui/views/vector_icons/ic_close.icon
+++ b/chromium/ui/views/vector_icons/ic_close.icon
@@ -31,3 +31,18 @@ LINE_TO, 17.59f, 19,
LINE_TO, 19, 17.59f,
LINE_TO, 13.41f, 12,
CLOSE
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 16, 5.41f,
+LINE_TO, 14.59f, 4,
+LINE_TO, 10, 8.59f,
+LINE_TO, 5.41f, 4,
+LINE_TO, 4, 5.41f,
+LINE_TO, 8.59f, 10,
+LINE_TO, 4, 14.59f,
+LINE_TO, 5.41f, 16,
+LINE_TO, 10, 11.41f,
+LINE_TO, 14.59f, 16,
+LINE_TO, 16, 14.59f,
+LINE_TO, 11.41f, 10,
+CLOSE
diff --git a/chromium/ui/views/vector_icons/menu_drop_arrow.icon b/chromium/ui/views/vector_icons/menu_drop_arrow.icon
new file mode 100644
index 00000000000..5f9587aa6ee
--- /dev/null
+++ b/chromium/ui/views/vector_icons/menu_drop_arrow.icon
@@ -0,0 +1,9 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 11,
+MOVE_TO, 1, 3,
+R_H_LINE_TO, 10,
+R_LINE_TO, -5, 6,
+CLOSE
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index c53f79d424e..d238fad21fd 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -419,6 +419,10 @@ gfx::Rect View::GetBoundsInScreen() const {
return gfx::Rect(origin, size());
}
+gfx::Rect View::GetAnchorBoundsInScreen() const {
+ return GetBoundsInScreen();
+}
+
gfx::Size View::GetPreferredSize() const {
if (preferred_size_)
return *preferred_size_;
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index cbc9e1866b4..4248609dd3c 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -363,6 +363,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Return the bounds of the View in screen coordinate system.
gfx::Rect GetBoundsInScreen() const;
+ // Return the bounds that an anchored widget should anchor to. These can be
+ // different from |GetBoundsInScreen()| when a view is larger than its visible
+ // size, for instance to provide a larger hittable area.
+ virtual gfx::Rect GetAnchorBoundsInScreen() const;
+
// Returns the baseline of this view, or -1 if this view has no baseline. The
// return value is relative to the preferred height.
virtual int GetBaseline() const;
@@ -1827,7 +1832,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Observers -------------------------------------------------------------
- base::ObserverList<ViewObserver> observers_;
+ base::ObserverList<ViewObserver>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(View);
};
diff --git a/chromium/ui/views/view_properties.cc b/chromium/ui/views/view_properties.cc
index d579a16c8cb..e55acc0ca94 100644
--- a/chromium/ui/views/view_properties.cc
+++ b/chromium/ui/views/view_properties.cc
@@ -4,12 +4,15 @@
#include "ui/views/view_properties.h"
+#include "ui/base/hit_test.h"
#include "ui/gfx/geometry/insets.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#if !defined(USE_AURA)
-// aura_constants.cc also declared the bool ClassProperty type.
+// aura_constants.cc also declared the bool and int[32_t]
+// ClassProperty type.
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, bool);
+DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, int);
#endif
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, gfx::Insets*);
@@ -19,6 +22,7 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT,
namespace views {
+DEFINE_UI_CLASS_PROPERTY_KEY(int, kHitTestComponentKey, HTNOWHERE);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kMarginsKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(views::BubbleDialogDelegateView*,
kAnchoredDialogKey,
diff --git a/chromium/ui/views/view_properties.h b/chromium/ui/views/view_properties.h
index 4e706ec7a02..2896ee94512 100644
--- a/chromium/ui/views/view_properties.h
+++ b/chromium/ui/views/view_properties.h
@@ -16,6 +16,10 @@ namespace views {
class BubbleDialogDelegateView;
+// The hit test component (e.g. HTCLIENT) for a View in a window frame. Defaults
+// to HTNOWHERE.
+VIEWS_EXPORT extern const ui::ClassProperty<int>* const kHitTestComponentKey;
+
// A property to store margins around the outer perimeter of the view. Margins
// are outside the bounds of the view. This is used by various layout managers
// to position views with the proper spacing between them.
diff --git a/chromium/ui/views/view_targeter_unittest.cc b/chromium/ui/views/view_targeter_unittest.cc
index 1427abd4782..9998b3b0d24 100644
--- a/chromium/ui/views/view_targeter_unittest.cc
+++ b/chromium/ui/views/view_targeter_unittest.cc
@@ -8,6 +8,7 @@
#include "base/memory/ptr_util.h"
#include "ui/events/event_targeter.h"
#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/gfx/path.h"
#include "ui/views/masked_targeter_delegate.h"
#include "ui/views/test/views_test_base.h"
@@ -141,7 +142,7 @@ TEST_F(ViewTargeterTest, ViewTargeterForKeyEvents) {
static_cast<internal::RootView*>(widget.GetRootView());
ui::EventTargeter* targeter = root_view->targeter();
- ui::KeyEvent key_event('a', ui::VKEY_A, ui::EF_NONE);
+ ui::KeyEvent key_event('a', ui::VKEY_A, ui::DomCode::NONE, ui::EF_NONE);
// The focused view should be the initial target of the event.
ui::EventTarget* current_target = targeter->FindTargetForEvent(root_view,
diff --git a/chromium/ui/views/views_test_suite.cc b/chromium/ui/views/views_test_suite.cc
index bd46fca6a32..e579a7d0503 100644
--- a/chromium/ui/views/views_test_suite.cc
+++ b/chromium/ui/views/views_test_suite.cc
@@ -45,10 +45,6 @@ void ViewsTestSuite::Initialize() {
base::TestSuite::Initialize();
gl::GLSurfaceTestSupport::InitializeOneOff();
-#if defined(OS_MACOSX)
- gpu::ImageTransportSurface::SetAllowOSMesaForTesting(true);
-#endif
-
ui::RegisterPathProvider();
base::FilePath ui_test_pak_path;
diff --git a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
index 7e79906a819..aceec981589 100644
--- a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
@@ -349,9 +349,10 @@ TEST_F(AXNativeWidgetMacTest, ChildrenAttribute) {
TEST_F(AXNativeWidgetMacTest, ParentAttribute) {
Textfield* child = AddChildTextfield(widget()->GetContentsView()->size());
- // Views with Widget parents will have a NSWindow parent.
+ // Views with Widget parents will have a NSAccessibilityGroupRole parent.
+ // See https://crbug.com/875843 for more information.
EXPECT_NSEQ(
- NSAccessibilityWindowRole,
+ NSAccessibilityGroupRole,
[AXParent() accessibilityAttributeValue:NSAccessibilityRoleAttribute]);
// Views with non-Widget parents will have the role of the parent view.
@@ -367,7 +368,7 @@ TEST_F(AXNativeWidgetMacTest, ParentAttribute) {
// Test an ignored role parent is skipped in favor of the grandparent.
parent->set_role(ax::mojom::Role::kIgnored);
EXPECT_NSEQ(
- NSAccessibilityWindowRole,
+ NSAccessibilityGroupRole,
[AXParent() accessibilityAttributeValue:NSAccessibilityRoleAttribute]);
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
index c434a9fcfbc..86578b995a2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
@@ -5,6 +5,7 @@
#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
#include "ui/aura/client/capture_client_observer.h"
+#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tracker.h"
@@ -58,7 +59,8 @@ void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) {
// committing |capture_window_|.
aura::WindowTracker tracker;
tracker.Add(new_capture_window);
- ui::GestureRecognizer::Get()->CancelActiveTouchesExcept(new_capture_window);
+ new_capture_window->env()->gesture_recognizer()->CancelActiveTouchesExcept(
+ new_capture_window);
if (!tracker.Contains(new_capture_window))
new_capture_window = nullptr;
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h
index 1f19ec64fa5..8c0811bc2ec 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.h
@@ -58,7 +58,7 @@ class VIEWS_EXPORT DesktopCaptureClient : public aura::client::CaptureClient {
// Set of DesktopCaptureClients.
static CaptureClients* capture_clients_;
- base::ObserverList<aura::client::CaptureClientObserver> observers_;
+ base::ObserverList<aura::client::CaptureClientObserver>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(DesktopCaptureClient);
};
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 f1e8c4eff5a..00073d3d3bf 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
@@ -700,8 +700,8 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
xwindow_, target_current_context_->fetched_targets()));
ui::DropTargetEvent event(data,
- target_window_location_,
- target_window_root_location_,
+ gfx::PointF(target_window_location_),
+ gfx::PointF(target_window_root_location_),
target_current_context_->GetDragOperation());
if (target_current_context_->source_client()) {
event.set_flags(target_current_context_->source_client()
@@ -1095,8 +1095,8 @@ void DesktopDragDropClientAuraX11::DragTranslate(
event->reset(new ui::DropTargetEvent(
*(data->get()),
- location,
- root_location,
+ gfx::PointF(location),
+ gfx::PointF(root_location),
drag_op));
if (target_current_context_->source_client()) {
(*event)->set_flags(
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 3a7edcd000f..99c525f3219 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
@@ -149,8 +149,8 @@ void DesktopDropTargetWin::Translate(
aura::Window::ConvertPointToTarget(root_window_, target_window_, &location);
event->reset(new ui::DropTargetEvent(
*(data->get()),
- location,
- root_location,
+ gfx::PointF(location),
+ gfx::PointF(root_location),
ui::DragDropTypes::DropEffectToDragOperation(effect)));
(*event)->set_flags(ConvertKeyStateToAuraEventFlags(key_state));
if (target_window_changed)
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 b482b7781c4..01a429a67e3 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
@@ -8,12 +8,13 @@
#include "base/macros.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/window_parenting_client.h"
+#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_occlusion_tracker.h"
@@ -320,8 +321,12 @@ void DesktopNativeWidgetAura::OnHostClosed() {
desktop_window_tree_host_ = NULL;
content_window_ = NULL;
+ // |OnNativeWidgetDestroyed| may delete |this| if the object does not own
+ // itself.
+ bool should_delete_this =
+ (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET);
native_widget_delegate_->OnNativeWidgetDestroyed();
- if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ if (should_delete_this)
delete this;
}
@@ -746,11 +751,11 @@ void DesktopNativeWidgetAura::CloseNow() {
desktop_window_tree_host_->CloseNow();
}
-void DesktopNativeWidgetAura::Show() {
+void DesktopNativeWidgetAura::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
if (!content_window_)
return;
- desktop_window_tree_host_->AsWindowTreeHost()->Show();
- content_window_->Show();
+ desktop_window_tree_host_->Show(show_state, restore_bounds);
}
void DesktopNativeWidgetAura::Hide() {
@@ -760,23 +765,6 @@ void DesktopNativeWidgetAura::Hide() {
content_window_->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);
- content_window_->Show();
-}
-
-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);
- content_window_->Show();
-}
-
bool DesktopNativeWidgetAura::IsVisible() const {
// The objects checked here should be the same objects changed in
// ShowWithWindowState and ShowMaximizedWithBounds. For example, MS Windows
@@ -912,6 +900,11 @@ bool DesktopNativeWidgetAura::IsMouseEventsEnabled() const {
return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
}
+bool DesktopNativeWidgetAura::IsMouseButtonDown() const {
+ return content_window_ ? content_window_->env()->IsMouseButtonDown()
+ : aura::Env::GetInstance()->IsMouseButtonDown();
+}
+
void DesktopNativeWidgetAura::ClearNativeFocus() {
desktop_window_tree_host_->ClearNativeFocus();
@@ -977,8 +970,12 @@ bool DesktopNativeWidgetAura::IsTranslucentWindowOpacitySupported() const {
desktop_window_tree_host_->IsTranslucentWindowOpacitySupported();
}
+ui::GestureRecognizer* DesktopNativeWidgetAura::GetGestureRecognizer() {
+ return content_window_->env()->gesture_recognizer();
+}
+
void DesktopNativeWidgetAura::OnSizeConstraintsChanged() {
- int32_t behavior = ui::mojom::kResizeBehaviorNone;
+ int32_t behavior = ws::mojom::kResizeBehaviorNone;
if (GetWidget()->widget_delegate())
behavior = GetWidget()->widget_delegate()->GetResizeBehavior();
content_window_->SetProperty(aura::client::kResizeBehaviorKey, behavior);
@@ -1113,7 +1110,7 @@ bool DesktopNativeWidgetAura::ShouldActivate() const {
}
////////////////////////////////////////////////////////////////////////////////
-// DesktopNativeWidgetAura, wmActivationChangeObserver implementation:
+// DesktopNativeWidgetAura, wm::ActivationChangeObserver implementation:
void DesktopNativeWidgetAura::OnWindowActivated(
wm::ActivationChangeObserver::ActivationReason reason,
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 40d5b1bfb7e..be95f3ad684 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
@@ -144,10 +144,9 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void SetShape(std::unique_ptr<Widget::ShapeRects> shape) override;
void Close() override;
void CloseNow() override;
- void Show() override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
void Hide() override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
- void ShowWithWindowState(ui::WindowShowState state) override;
bool IsVisible() const override;
void Activate() override;
void Deactivate() override;
@@ -174,6 +173,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void SchedulePaintInRect(const gfx::Rect& rect) override;
void SetCursor(gfx::NativeCursor cursor) override;
bool IsMouseEventsEnabled() const override;
+ bool IsMouseButtonDown() const override;
void ClearNativeFocus() override;
gfx::Rect GetWorkAreaBoundsInScreen() const override;
Widget::MoveLoopResult RunMoveLoop(
@@ -186,6 +186,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) override;
bool IsTranslucentWindowOpacitySupported() const override;
+ ui::GestureRecognizer* GetGestureRecognizer() override;
void OnSizeConstraintsChanged() override;
void RepostNativeEvent(gfx::NativeEvent native_event) override;
std::string GetName() const override;
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 1e7210e7601..9d4d564ee7a 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
@@ -33,6 +33,8 @@
#include "ui/views/window/dialog_delegate.h"
#if defined(OS_WIN)
+#include <windows.h>
+
#include "ui/base/view_prop.h"
#include "ui/base/win/window_event_target.h"
#include "ui/views/win/hwnd_util.h"
@@ -122,6 +124,7 @@ TEST_F(DesktopNativeWidgetAuraTest, NativeViewNoActivate) {
->GetFocusedWindow());
}
+#if defined(OS_WIN)
// 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) {
@@ -131,11 +134,11 @@ TEST_F(DesktopNativeWidgetAuraTest, WidgetNotVisibleOnlyWindowTreeHostShown) {
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();
+ ShowWindow(widget.GetNativeView()->GetHost()->GetAcceleratedWidget(),
+ SW_SHOWNORMAL);
EXPECT_FALSE(widget.IsVisible());
}
+#endif
TEST_F(DesktopNativeWidgetAuraTest, DesktopAuraWindowShowFrameless) {
Widget widget;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
index 546411eaf7e..08eadbeedc7 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
@@ -9,7 +9,7 @@
#include <memory>
#include "base/macros.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
@@ -315,7 +315,7 @@ TEST_F(DesktopScreenX11Test, DoubleClickHeaderMaximizes) {
aura::Window* window = widget->GetNativeWindow();
window->SetProperty(aura::client::kResizeBehaviorKey,
- ui::mojom::kResizeBehaviorCanMaximize);
+ ws::mojom::kResizeBehaviorCanMaximize);
// Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
DesktopWindowTreeHost* rwh =
@@ -341,7 +341,7 @@ TEST_F(DesktopScreenX11Test, DoubleClickTwoDifferentTargetsDoesntMaximizes) {
aura::Window* window = widget->GetNativeWindow();
window->SetProperty(aura::client::kResizeBehaviorKey,
- ui::mojom::kResizeBehaviorCanMaximize);
+ ws::mojom::kResizeBehaviorCanMaximize);
// Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
DesktopWindowTreeHost* rwh =
@@ -371,7 +371,7 @@ TEST_F(DesktopScreenX11Test, RightClickDuringDoubleClickDoesntMaximize) {
aura::Window* window = widget->GetNativeWindow();
window->SetProperty(aura::client::kResizeBehaviorKey,
- ui::mojom::kResizeBehaviorCanMaximize);
+ ws::mojom::kResizeBehaviorCanMaximize);
// Cast to superclass as DesktopWindowTreeHostX11 hide IsMaximized
DesktopWindowTreeHost* rwh = static_cast<DesktopWindowTreeHost*>(
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 a6e2eca3abd..8a909991f7d 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
@@ -75,8 +75,24 @@ class VIEWS_EXPORT DesktopWindowTreeHost {
virtual aura::WindowTreeHost* AsWindowTreeHost() = 0;
- virtual void ShowWindowWithState(ui::WindowShowState show_state) = 0;
- virtual void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) = 0;
+ // There are two distinct ways for DesktopWindowTreeHosts's to be shown:
+ // 1. This function is called. As this function is specific to
+ // DesktopWindowTreeHost, it is only called from DesktopNativeWidgetAura.
+ // 2. Calling Show() directly on the WindowTreeHost associated with this
+ // DesktopWindowTreeHost. This is very rare. In general, calls go through
+ // Widget, which ends up in (1).
+ //
+ // Implementations must deal with these two code paths. In general, this is
+ // done by having the WindowTreeHost subclass override ShowImpl() to call this
+ // function: Show(ui::SHOW_STATE_NORMAL, gfx::Rect()). A subtle
+ // ramification is the implementation of this function can *not* call
+ // WindowTreeHost::Show(), and the implementation of this must perform the
+ // same work as WindowTreeHost::Show(). This means setting the visibility of
+ // the compositor, window() and DesktopNativeWidgetAura::content_window()
+ // appropriately. Some subclasses set the visibility of window() in the
+ // constructor and assume it's always true.
+ virtual void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) = 0;
virtual bool IsVisible() const = 0;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 2081478b174..dcf1d7d40c2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -135,6 +135,8 @@ void DesktopWindowTreeHostPlatform::CloseNow() {
if (!weak_ref || got_on_closed_)
return;
+ native_widget_delegate_->OnNativeWidgetDestroying();
+
got_on_closed_ = true;
desktop_native_widget_aura_->OnHostClosed();
}
@@ -143,8 +145,11 @@ aura::WindowTreeHost* DesktopWindowTreeHostPlatform::AsWindowTreeHost() {
return this;
}
-void DesktopWindowTreeHostPlatform::ShowWindowWithState(
- ui::WindowShowState show_state) {
+void DesktopWindowTreeHostPlatform::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
+ if (show_state == ui::SHOW_STATE_MAXIMIZED && !restore_bounds.IsEmpty())
+ platform_window()->SetRestoredBoundsInPixels(ToPixelRect(restore_bounds));
+
if (compositor()) {
platform_window()->Show();
compositor()->SetVisible(true);
@@ -180,12 +185,8 @@ void DesktopWindowTreeHostPlatform::ShowWindowWithState(
native_widget_delegate_->SetInitialFocus(
IsActive() ? show_state : ui::SHOW_STATE_INACTIVE);
}
-}
-void DesktopWindowTreeHostPlatform::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- // TODO: support |restored_bounds|.
- ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
+ desktop_native_widget_aura_->content_window()->Show();
}
bool DesktopWindowTreeHostPlatform::IsVisible() const {
@@ -253,8 +254,12 @@ gfx::Rect DesktopWindowTreeHostPlatform::GetClientAreaBoundsInScreen() const {
}
gfx::Rect DesktopWindowTreeHostPlatform::GetRestoredBounds() const {
- NOTIMPLEMENTED_LOG_ONCE();
- return gfx::Rect(0, 0, 640, 840);
+ gfx::Rect restored_bounds = platform_window()->GetRestoredBoundsInPixels();
+ // When window is resized, |restored bounds| is not set and empty.
+ // If |restored bounds| is empty, it returns the current window size.
+ gfx::Rect bounds =
+ !restored_bounds.IsEmpty() ? restored_bounds : GetBoundsInPixels();
+ return ToDIPRect(bounds);
}
std::string DesktopWindowTreeHostPlatform::GetWorkspace() const {
@@ -470,10 +475,6 @@ void DesktopWindowTreeHostPlatform::OnCloseRequest() {
GetWidget()->Close();
}
-void DesktopWindowTreeHostPlatform::OnAcceleratedWidgetDestroying() {
- native_widget_delegate_->OnNativeWidgetDestroying();
-}
-
void DesktopWindowTreeHostPlatform::OnActivationChanged(bool active) {
is_active_ = active;
aura::WindowTreeHostPlatform::OnActivationChanged(active);
@@ -495,6 +496,20 @@ Widget* DesktopWindowTreeHostPlatform::GetWidget() {
return native_widget_delegate_->AsWidget();
}
+gfx::Rect DesktopWindowTreeHostPlatform::ToDIPRect(
+ const gfx::Rect& rect_in_pixels) const {
+ gfx::RectF rect_in_dip = gfx::RectF(rect_in_pixels);
+ GetRootTransform().TransformRectReverse(&rect_in_dip);
+ return gfx::ToEnclosingRect(rect_in_dip);
+}
+
+gfx::Rect DesktopWindowTreeHostPlatform::ToPixelRect(
+ const gfx::Rect& rect_in_dip) const {
+ gfx::RectF rect_in_pixels = gfx::RectF(rect_in_dip);
+ GetRootTransform().TransformRect(&rect_in_pixels);
+ return gfx::ToEnclosingRect(rect_in_pixels);
+}
+
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHost:
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index cac4832e63a..b6219dd00a7 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -34,8 +34,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
void Close() override;
void CloseNow() override;
aura::WindowTreeHost* AsWindowTreeHost() override;
- void ShowWindowWithState(ui::WindowShowState show_state) override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
bool IsVisible() const override;
void SetSize(const gfx::Size& size) override;
void StackAbove(aura::Window* window) override;
@@ -93,7 +93,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
void OnClosed() override;
void OnWindowStateChanged(ui::PlatformWindowState new_state) override;
void OnCloseRequest() override;
- void OnAcceleratedWidgetDestroying() override;
void OnActivationChanged(bool active) override;
private:
@@ -101,6 +100,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
Widget* GetWidget();
+ gfx::Rect ToDIPRect(const gfx::Rect& rect_in_pixels) const;
+ gfx::Rect ToPixelRect(const gfx::Rect& rect_in_dip) const;
+
internal::NativeWidgetDelegate* const native_widget_delegate_;
DesktopNativeWidgetAura* const desktop_native_widget_aura_;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
new file mode 100644
index 00000000000..76a55cfb1d8
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -0,0 +1,86 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
+#include "base/run_loop.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace views {
+
+namespace {
+
+class WidgetDestroyingObserver : public WidgetObserver {
+ public:
+ explicit WidgetDestroyingObserver(Widget* widget) : widget_(widget) {
+ widget_->AddObserver(this);
+ }
+ ~WidgetDestroyingObserver() override {
+ if (widget_)
+ widget_->RemoveObserver(this);
+ }
+
+ // Returns immediately when |widget_| becomes NULL, otherwise a RunLoop is
+ // used until widget closing event is received.
+ void Wait() {
+ if (!on_widget_destroying_)
+ run_loop_.Run();
+ }
+
+ bool widget_destroying() const { return on_widget_destroying_; }
+
+ private:
+ // views::WidgetObserver override:
+ void OnWidgetDestroying(Widget* widget) override {
+ DCHECK_EQ(widget_, widget);
+ widget_->RemoveObserver(this);
+ widget_ = nullptr;
+ on_widget_destroying_ = true;
+ if (run_loop_.running())
+ run_loop_.Quit();
+ }
+
+ Widget* widget_;
+ base::RunLoop run_loop_;
+ bool on_widget_destroying_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetDestroyingObserver);
+};
+
+std::unique_ptr<Widget> CreateWidgetWithNativeWidget() {
+ std::unique_ptr<Widget> widget(new Widget);
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.delegate = nullptr;
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.remove_standard_frame = true;
+ params.native_widget = new DesktopNativeWidgetAura(widget.get());
+ params.bounds = gfx::Rect(100, 100, 100, 100);
+ widget->Init(params);
+ return widget;
+}
+
+} // namespace
+
+class DesktopWindowTreeHostPlatformTest : public ViewsTestBase {
+ public:
+ DesktopWindowTreeHostPlatformTest() {}
+ ~DesktopWindowTreeHostPlatformTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostPlatformTest);
+};
+
+TEST_F(DesktopWindowTreeHostPlatformTest, CallOnNativeWidgetDestroying) {
+ std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+
+ WidgetDestroyingObserver observer(
+ widget->native_widget_private()->GetWidget());
+ widget->CloseNow();
+
+ observer.Wait();
+ EXPECT_TRUE(observer.widget_destroying());
+}
+
+} // namespace views
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 9c6b588516f..9ab47c86390 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
@@ -199,20 +199,19 @@ aura::WindowTreeHost* DesktopWindowTreeHostWin::AsWindowTreeHost() {
return this;
}
-void DesktopWindowTreeHostWin::ShowWindowWithState(
- ui::WindowShowState show_state) {
+void DesktopWindowTreeHostWin::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
if (compositor())
compositor()->SetVisible(true);
- message_handler_->ShowWindowWithState(show_state);
-}
-void DesktopWindowTreeHostWin::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- if (compositor())
- compositor()->SetVisible(true);
- gfx::Rect pixel_bounds =
- display::win::ScreenWin::DIPToScreenRect(GetHWND(), restored_bounds);
- message_handler_->ShowMaximizedWithBounds(pixel_bounds);
+ gfx::Rect pixel_restore_bounds;
+ if (show_state == ui::SHOW_STATE_MAXIMIZED) {
+ pixel_restore_bounds =
+ display::win::ScreenWin::DIPToScreenRect(GetHWND(), restore_bounds);
+ }
+ message_handler_->Show(show_state, pixel_restore_bounds);
+
+ content_window()->Show();
}
bool DesktopWindowTreeHostWin::IsVisible() const {
@@ -504,7 +503,7 @@ gfx::AcceleratedWidget DesktopWindowTreeHostWin::GetAcceleratedWidget() {
}
void DesktopWindowTreeHostWin::ShowImpl() {
- message_handler_->Show();
+ Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
}
void DesktopWindowTreeHostWin::HideImpl() {
@@ -729,7 +728,8 @@ void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size,
}
}
-bool DesktopWindowTreeHostWin::GetClientAreaInsets(gfx::Insets* insets) const {
+bool DesktopWindowTreeHostWin::GetClientAreaInsets(gfx::Insets* insets,
+ HMONITOR monitor) const {
return false;
}
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 022de4037ff..364d6df184c 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
@@ -67,8 +67,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void Close() override;
void CloseNow() override;
aura::WindowTreeHost* AsWindowTreeHost() override;
- void ShowWindowWithState(ui::WindowShowState show_state) override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
bool IsVisible() const override;
void SetSize(const gfx::Size& size) override;
void StackAbove(aura::Window* window) override;
@@ -169,7 +169,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
bool WillProcessWorkAreaChange() const override;
int GetNonClientComponent(const gfx::Point& point) const override;
void GetWindowMask(const gfx::Size& size, gfx::Path* path) override;
- bool GetClientAreaInsets(gfx::Insets* insets) const override;
+ bool GetClientAreaInsets(gfx::Insets* insets,
+ HMONITOR monitor) const override;
void GetMinMaxSize(gfx::Size* min_size, gfx::Size* max_size) const override;
gfx::Size GetRootViewSize() const override;
gfx::Size DIPToScreenSize(const gfx::Size& dip_size) const override;
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 22a9914957a..4e04197810d 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
@@ -20,6 +20,7 @@
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
+#include "ui/aura/null_window_targeter.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/base/class_property.h"
@@ -38,7 +39,6 @@
#include "ui/events/event_utils.h"
#include "ui/events/keyboard_hook.h"
#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/null_event_targeter.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -514,16 +514,23 @@ aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
return this;
}
-void DesktopWindowTreeHostX11::ShowWindowWithState(
- ui::WindowShowState show_state) {
+void DesktopWindowTreeHostX11::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
if (compositor())
SetVisible(true);
- if (!IsVisible() || !window_mapped_in_server_)
+
+ if (!IsVisible())
MapWindow(show_state);
switch (show_state) {
case ui::SHOW_STATE_MAXIMIZED:
Maximize();
+ if (!restore_bounds.IsEmpty()) {
+ // Enforce |restored_bounds_in_pixels_| since calling Maximize() could
+ // have reset it.
+ restored_bounds_in_pixels_ = ToPixelRect(restore_bounds);
+ }
+
break;
case ui::SHOW_STATE_MINIMIZED:
Minimize();
@@ -536,18 +543,12 @@ void DesktopWindowTreeHostX11::ShowWindowWithState(
}
native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
-}
-void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
- // Enforce |restored_bounds_in_pixels_| since calling Maximize() could have
- // reset it.
- restored_bounds_in_pixels_ = ToPixelRect(restored_bounds);
+ content_window()->Show();
}
bool DesktopWindowTreeHostX11::IsVisible() const {
- return window_mapped_in_client_;
+ return window_mapped_in_client_ && !IsMinimized();
}
void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
@@ -800,7 +801,7 @@ bool DesktopWindowTreeHostX11::IsActive() const {
}
void DesktopWindowTreeHostX11::Maximize() {
- if (ui::HasWMSpecProperty(window_properties_in_server_,
+ if (ui::HasWMSpecProperty(window_properties_,
gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"))) {
// Unfullscreen the window if it is fullscreen.
SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_FULLSCREEN"), x11::None);
@@ -826,31 +827,34 @@ void DesktopWindowTreeHostX11::Maximize() {
SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
if (IsMinimized())
- ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+ Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
}
void DesktopWindowTreeHostX11::Minimize() {
ReleaseCapture();
- XIconifyWindow(xdisplay_, xwindow_, 0);
+ if (window_mapped_in_client_)
+ XIconifyWindow(xdisplay_, xwindow_, 0);
+ else
+ SetWMSpecState(true, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::None);
}
void DesktopWindowTreeHostX11::Restore() {
should_maximize_after_map_ = false;
SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
- if (IsMinimized())
- ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+ Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
+ SetWMSpecState(false, gfx::GetAtom("_NET_WM_STATE_HIDDEN"), x11::None);
}
bool DesktopWindowTreeHostX11::IsMaximized() const {
- return (ui::HasWMSpecProperty(window_properties_in_server_,
+ return (ui::HasWMSpecProperty(window_properties_,
gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) &&
- ui::HasWMSpecProperty(window_properties_in_server_,
+ ui::HasWMSpecProperty(window_properties_,
gfx::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")));
}
bool DesktopWindowTreeHostX11::IsMinimized() const {
- return ui::HasWMSpecProperty(window_properties_in_server_,
+ return ui::HasWMSpecProperty(window_properties_,
gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
}
@@ -1036,7 +1040,7 @@ void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
OnHostMovedInPixels(bounds_in_pixels_.origin());
OnHostResizedInPixels(bounds_in_pixels_.size());
- if (ui::HasWMSpecProperty(window_properties_in_server_,
+ if (ui::HasWMSpecProperty(window_properties_,
gfx::GetAtom("_NET_WM_STATE_FULLSCREEN")) ==
fullscreen) {
Relayout();
@@ -1190,11 +1194,11 @@ gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
}
void DesktopWindowTreeHostX11::ShowImpl() {
- ShowWindowWithState(ui::SHOW_STATE_NORMAL);
+ Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
}
void DesktopWindowTreeHostX11::HideImpl() {
- if (IsVisible()) {
+ if (window_mapped_in_client_) {
XWithdrawWindow(xdisplay_, xwindow_, 0);
window_mapped_in_client_ = false;
native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
@@ -1411,7 +1415,7 @@ void DesktopWindowTreeHostX11::InitX11Window(
}
swa.background_pixel = background_color;
- ::Atom window_type;
+ XAtom window_type;
switch (params.type) {
case Widget::InitParams::TYPE_MENU:
swa.override_redirect = x11::True;
@@ -1498,7 +1502,7 @@ void DesktopWindowTreeHostX11::InitX11Window(
// TODO(erg): We currently only request window deletion events. We also
// should listen for activation events and anything else that GTK+ listens
// for, and do something useful.
- ::Atom protocols[2];
+ XAtom protocols[2];
protocols[0] = gfx::GetAtom("WM_DELETE_WINDOW");
protocols[1] = gfx::GetAtom("_NET_WM_PING");
XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
@@ -1521,25 +1525,25 @@ void DesktopWindowTreeHostX11::InitX11Window(
XA_ATOM, 32, PropModeReplace,
reinterpret_cast<unsigned char*>(&window_type), 1);
- // List of window state properties (_NET_WM_STATE) to set, if any.
- std::vector< ::Atom> state_atom_list;
+ // The changes to |window_properties_| here will be sent to the X server just
+ // before the window is mapped.
// Remove popup windows from taskbar unless overridden.
if ((params.type == Widget::InitParams::TYPE_POPUP ||
params.type == Widget::InitParams::TYPE_BUBBLE) &&
!params.force_show_in_taskbar) {
- state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
+ window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
}
// If the window should stay on top of other windows, add the
// _NET_WM_STATE_ABOVE property.
is_always_on_top_ = params.keep_on_top;
if (is_always_on_top_)
- state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_ABOVE"));
+ window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_ABOVE"));
workspace_ = base::nullopt;
if (params.visible_on_all_workspaces) {
- state_atom_list.push_back(gfx::GetAtom("_NET_WM_STATE_STICKY"));
+ window_properties_.insert(gfx::GetAtom("_NET_WM_STATE_STICKY"));
ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
} else if (!params.workspace.empty()) {
int workspace;
@@ -1547,18 +1551,6 @@ void DesktopWindowTreeHostX11::InitX11Window(
ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", workspace);
}
- // Setting _NET_WM_STATE by sending a message to the root_window (with
- // SetWMSpecState) has no effect here since the window has not yet been
- // mapped. So we manually change the state.
- if (!state_atom_list.empty()) {
- DCHECK(window_properties_in_client_.empty());
- window_properties_in_client_ = state_atom_list;
- ui::SetAtomArrayProperty(xwindow_,
- "_NET_WM_STATE",
- "ATOM",
- state_atom_list);
- }
-
if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
ui::SetWindowClassHint(
xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
@@ -1653,31 +1645,41 @@ gfx::Size DesktopWindowTreeHostX11::AdjustSize(
void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
XAtom state1,
XAtom state2) {
- if (IsVisible())
+ if (window_mapped_in_client_) {
ui::SetWMSpecState(xwindow_, enabled, state1, state2);
- for (XAtom atom : {state1, state2}) {
- if (atom != x11::None) {
+ } else {
+ // The updated state will be set when the window is (re)mapped.
+ base::flat_set<XAtom> new_window_properties = window_properties_;
+ for (XAtom atom : {state1, state2}) {
if (enabled)
- window_properties_in_client_.insert(atom);
+ new_window_properties.insert(atom);
else
- window_properties_in_client_.erase(atom);
+ new_window_properties.erase(atom);
}
+ UpdateWindowProperties(new_window_properties);
}
}
void DesktopWindowTreeHostX11::OnWMStateUpdated() {
- std::vector< ::Atom> atom_list;
- // Ignore the return value of gfx::GetAtomArrayProperty(). Fluxbox removes the
- // _NET_WM_STATE property when no _NET_WM_STATE atoms are set.
- ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list);
+ // The EWMH spec requires window managers to remove the _NET_WM_STATE property
+ // when a window is unmapped. However, Chromium code wants the state to
+ // persist across a Hide() and Show(). So if the window is currently
+ // unmapped, leave the state unchanged so it will be restored when the window
+ // is remapped.
+ std::vector<XAtom> atom_list;
+ if (ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list) ||
+ window_mapped_in_client_) {
+ UpdateWindowProperties(
+ base::flat_set<XAtom>(std::begin(atom_list), std::end(atom_list)));
+ }
+}
+void DesktopWindowTreeHostX11::UpdateWindowProperties(
+ const base::flat_set<XAtom>& new_window_properties) {
bool was_minimized = IsMinimized();
bool was_maximized = IsMaximized();
- window_properties_in_server_.clear();
- std::copy(atom_list.begin(), atom_list.end(),
- inserter(window_properties_in_server_,
- window_properties_in_server_.begin()));
+ window_properties_ = new_window_properties;
bool is_minimized = IsMinimized();
bool is_maximized = IsMaximized();
@@ -1705,7 +1707,6 @@ void DesktopWindowTreeHostX11::OnWMStateUpdated() {
}
if (restored_bounds_in_pixels_.IsEmpty()) {
- DCHECK(!IsFullscreen());
if (IsMaximized()) {
// The request that we become maximized originated from a different
// process. |bounds_in_pixels_| already contains our maximized bounds. Do
@@ -1726,7 +1727,7 @@ void DesktopWindowTreeHostX11::OnWMStateUpdated() {
// do preprocessing before the x window's fullscreen state is toggled.
is_always_on_top_ = ui::HasWMSpecProperty(
- window_properties_in_server_, gfx::GetAtom("_NET_WM_STATE_ABOVE"));
+ window_properties_, gfx::GetAtom("_NET_WM_STATE_ABOVE"));
if (was_maximized != is_maximized)
OnMaximizedStateChanged();
@@ -1984,11 +1985,16 @@ void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
UpdateMinAndMaxSize();
+ if (window_properties_.empty()) {
+ XDeleteProperty(xdisplay_, xwindow_, gfx::GetAtom("_NET_WM_STATE"));
+ } else {
+ ui::SetAtomArrayProperty(xwindow_, "_NET_WM_STATE", "ATOM",
+ std::vector<XAtom>(std::begin(window_properties_),
+ std::end(window_properties_)));
+ }
+
XMapWindow(xdisplay_, xwindow_);
window_mapped_in_client_ = true;
-
- for (XAtom atom : window_properties_in_client_)
- ui::SetWMSpecState(xwindow_, true, atom, x11::None);
}
void DesktopWindowTreeHostX11::SetWindowTransparency() {
@@ -2312,7 +2318,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
break;
}
case PropertyNotify: {
- ::Atom changed_atom = xev->xproperty.atom;
+ XAtom changed_atom = xev->xproperty.atom;
if (changed_atom == gfx::GetAtom("_NET_WM_STATE")) {
OnWMStateUpdated();
} else if (changed_atom == gfx::GetAtom("_NET_FRAME_EXTENTS")) {
@@ -2361,21 +2367,20 @@ gfx::Rect DesktopWindowTreeHostX11::ToPixelRect(
return gfx::ToEnclosingRect(rect_in_pixels);
}
-std::unique_ptr<base::Closure>
+std::unique_ptr<base::OnceClosure>
DesktopWindowTreeHostX11::DisableEventListening() {
// Allows to open multiple file-pickers. See https://crbug.com/678982
modal_dialog_counter_++;
if (modal_dialog_counter_ == 1) {
// 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)));
+ // with NullWindowEventTargeter to make |dialog| modal.
+ targeter_for_modal_ = std::make_unique<aura::ScopedWindowTargeter>(
+ window(), std::make_unique<aura::NullWindowTargeter>());
}
- return std::make_unique<base::Closure>(
- base::Bind(&DesktopWindowTreeHostX11::EnableEventListening,
- weak_factory_.GetWeakPtr()));
+ return std::make_unique<base::OnceClosure>(
+ base::BindOnce(&DesktopWindowTreeHostX11::EnableEventListening,
+ weak_factory_.GetWeakPtr()));
}
void DesktopWindowTreeHostX11::EnableEventListening() {
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 c5e6df7ce81..cc9d5fb4823 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
@@ -86,7 +86,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
static void CleanUpWindowList(void (*func)(aura::Window* window));
// Disables event listening to make |dialog| modal.
- std::unique_ptr<base::Closure> DisableEventListening();
+ std::unique_ptr<base::OnceClosure> DisableEventListening();
// Returns a map of KeyboardEvent code to KeyboardEvent key values.
base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override;
@@ -103,8 +103,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
void Close() override;
void CloseNow() override;
aura::WindowTreeHost* AsWindowTreeHost() override;
- void ShowWindowWithState(ui::WindowShowState show_state) override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
bool IsVisible() const override;
void SetSize(const gfx::Size& requested_size) override;
void StackAbove(aura::Window* window) override;
@@ -208,12 +208,21 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// If mapped, sends a message to the window manager to enable or disable the
// states |state1| and |state2|. Otherwise, the states will be enabled or
- // disabled on the next map.
+ // disabled on the next map. It's the caller's responsibility to make sure
+ // atoms are set and unset in the appropriate pairs. For example, if a caller
+ // sets (_NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ), it would
+ // be invalid to unset the maximized state by making two calls like
+ // (_NET_WM_STATE_MAXIMIZED_VERT, x11::None), (_NET_WM_STATE_MAXIMIZED_HORZ,
+ // x11::None).
void SetWMSpecState(bool enabled, XAtom state1, XAtom state2);
// Called when |xwindow_|'s _NET_WM_STATE property is updated.
void OnWMStateUpdated();
+ // Updates |window_properties_| with |new_window_properties|.
+ void UpdateWindowProperties(
+ const base::flat_set<XAtom>& new_window_properties);
+
// Called when |xwindow_|'s _NET_FRAME_EXTENTS property is updated.
void OnFrameExtentsUpdated();
@@ -343,12 +352,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
// _NET_WM_DESKTOP is unset.
base::Optional<int> workspace_;
- // The window manager state bits as indicated by the server. May be
- // out-of-sync. May include bits set by non-Chrome apps.
- base::flat_set<::Atom> window_properties_in_server_;
-
- // The window manager state bits that Chrome has set.
- base::flat_set<::Atom> window_properties_in_client_;
+ // The window manager state bits.
+ base::flat_set<XAtom> window_properties_;
// Whether |xwindow_| was requested to be fullscreen via SetFullscreen().
bool is_fullscreen_;
@@ -381,7 +386,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
DesktopWindowTreeHostX11* window_parent_;
std::set<DesktopWindowTreeHostX11*> window_children_;
- base::ObserverList<DesktopWindowTreeHostObserverX11> observer_list_;
+ base::ObserverList<DesktopWindowTreeHostObserverX11>::Unchecked
+ observer_list_;
// The window shape if the window is non-rectangular.
gfx::XScopedPtr<_XRegion, gfx::XObjectDeleter<_XRegion, int, XDestroyRegion>>
diff --git a/chromium/ui/views/widget/desktop_aura/window_event_filter.cc b/chromium/ui/views/widget/desktop_aura/window_event_filter.cc
index e2d9e3e8a6f..530b079289b 100644
--- a/chromium/ui/views/widget/desktop_aura/window_event_filter.cc
+++ b/chromium/ui/views/widget/desktop_aura/window_event_filter.cc
@@ -4,7 +4,7 @@
#include "ui/views/widget/desktop_aura/window_event_filter.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
@@ -47,7 +47,7 @@ void WindowEventFilter::OnMouseEvent(ui::MouseEvent* event) {
OnClickedMaximizeButton(event);
} else {
if (target->GetProperty(aura::client::kResizeBehaviorKey) &
- ui::mojom::kResizeBehaviorCanResize) {
+ ws::mojom::kResizeBehaviorCanResize) {
MaybeDispatchHostWindowDragMovement(component, event);
}
}
@@ -97,7 +97,7 @@ void WindowEventFilter::OnClickedCaption(ui::MouseEvent* event,
break;
case LinuxUI::WINDOW_FRAME_ACTION_TOGGLE_MAXIMIZE:
if (target->GetProperty(aura::client::kResizeBehaviorKey) &
- ui::mojom::kResizeBehaviorCanMaximize)
+ ws::mojom::kResizeBehaviorCanMaximize)
ToggleMaximizedState();
event->SetHandled();
break;
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 e8e030f2b4d..bcf36736232 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
+++ b/chromium/ui/views/widget/desktop_aura/x11_desktop_handler.h
@@ -78,7 +78,7 @@ class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher,
// Events selected on x_root_window_.
std::unique_ptr<ui::XScopedEventSelector> x_root_window_events_;
- base::ObserverList<X11DesktopHandlerObserver> observers_;
+ base::ObserverList<X11DesktopHandlerObserver>::Unchecked observers_;
std::string workspace_;
diff --git a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
index 3d5ecdc2cfe..bd73d7293f8 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_window_event_filter.cc
@@ -4,7 +4,7 @@
#include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
diff --git a/chromium/ui/views/widget/drop_helper.cc b/chromium/ui/views/widget/drop_helper.cc
index 540301a61aa..f201f7311bd 100644
--- a/chromium/ui/views/widget/drop_helper.cc
+++ b/chromium/ui/views/widget/drop_helper.cc
@@ -64,8 +64,8 @@ int DropHelper::OnDrop(const OSExchangeData& data,
gfx::Point view_location(root_view_location);
View* root_view = drop_view->GetWidget()->GetRootView();
View::ConvertPointToTarget(root_view, drop_view, &view_location);
- ui::DropTargetEvent drop_event(data, view_location, view_location,
- drag_operation);
+ ui::DropTargetEvent drop_event(data, gfx::PointF(view_location),
+ gfx::PointF(view_location), drag_operation);
return drop_view->OnPerformDrop(drop_event);
}
@@ -127,9 +127,8 @@ void DropHelper::NotifyDragEntered(const OSExchangeData& data,
gfx::Point target_view_location(root_view_location);
View::ConvertPointToTarget(root_view_, target_view_, &target_view_location);
- ui::DropTargetEvent enter_event(data,
- target_view_location,
- target_view_location,
+ ui::DropTargetEvent enter_event(data, gfx::PointF(target_view_location),
+ gfx::PointF(target_view_location),
drag_operation);
target_view_->OnDragEntered(enter_event);
}
@@ -142,9 +141,8 @@ int DropHelper::NotifyDragOver(const OSExchangeData& data,
gfx::Point target_view_location(root_view_location);
View::ConvertPointToTarget(root_view_, target_view_, &target_view_location);
- ui::DropTargetEvent enter_event(data,
- target_view_location,
- target_view_location,
+ ui::DropTargetEvent enter_event(data, gfx::PointF(target_view_location),
+ gfx::PointF(target_view_location),
drag_operation);
return target_view_->OnDragUpdated(enter_event);
}
diff --git a/chromium/ui/views/widget/native_widget.h b/chromium/ui/views/widget/native_widget.h
index d01265f81f8..ec1a4ec93cb 100644
--- a/chromium/ui/views/widget/native_widget.h
+++ b/chromium/ui/views/widget/native_widget.h
@@ -5,9 +5,12 @@
#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_H_
#define UI_VIEWS_WIDGET_NATIVE_WIDGET_H_
-#include "ui/views/widget/widget.h"
+#include "ui/views/views_export.h"
namespace views {
+
+class Widget;
+
namespace internal {
class NativeWidgetPrivate;
}
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index 0b3370a18ac..e6661017075 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -10,8 +10,8 @@
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#include "services/ui/public/interfaces/window_manager.mojom.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_manager.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
@@ -101,11 +101,12 @@ void SetIcon(aura::Window* window,
// NativeWidgetAura, public:
NativeWidgetAura::NativeWidgetAura(internal::NativeWidgetDelegate* delegate,
- bool is_parallel_widget_in_window_manager)
+ bool is_parallel_widget_in_window_manager,
+ aura::Env* env)
: delegate_(delegate),
is_parallel_widget_in_window_manager_(
is_parallel_widget_in_window_manager),
- window_(new aura::Window(this)),
+ window_(new aura::Window(this, aura::client::WINDOW_TYPE_UNKNOWN, env)),
ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
destroying_(false),
cursor_(gfx::kNullCursor),
@@ -153,9 +154,9 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
ownership_ = params.ownership;
RegisterNativeWidgetForWindow(this, window_);
- // MusClient has assertions that ui::mojom::WindowType matches
+ // MusClient has assertions that ws::mojom::WindowType matches
// views::Widget::InitParams::Type.
- aura::SetWindowType(window_, static_cast<ui::mojom::WindowType>(params.type));
+ aura::SetWindowType(window_, static_cast<ws::mojom::WindowType>(params.type));
if (params.corner_radius) {
window_->SetProperty(aura::client::kWindowCornerRadiusKey,
*params.corner_radius);
@@ -237,8 +238,8 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
SetBounds(window_bounds);
window_->SetEventTargetingPolicy(
params.accept_events
- ? ui::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS
- : ui::mojom::EventTargetingPolicy::NONE);
+ ? ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS
+ : ws::mojom::EventTargetingPolicy::NONE);
DCHECK(GetWidget()->GetRootView());
if (params.type != Widget::InitParams::TYPE_TOOLTIP)
tooltip_manager_.reset(new views::TooltipManagerAura(GetWidget()));
@@ -546,30 +547,20 @@ void NativeWidgetAura::CloseNow() {
delete window_;
}
-void NativeWidgetAura::Show() {
- ShowWithWindowState(ui::SHOW_STATE_NORMAL);
-}
-
-void NativeWidgetAura::Hide() {
- if (window_)
- window_->Hide();
-}
-
-void NativeWidgetAura::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- SetRestoreBounds(window_, restored_bounds);
- ShowWithWindowState(ui::SHOW_STATE_MAXIMIZED);
-}
-
-void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
+void NativeWidgetAura::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
if (!window_)
return;
- if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN)
- window_->SetProperty(aura::client::kShowStateKey, state);
+ if (show_state == ui::SHOW_STATE_MAXIMIZED && !restore_bounds.IsEmpty())
+ SetRestoreBounds(window_, restore_bounds);
+ if (show_state == ui::SHOW_STATE_MAXIMIZED ||
+ show_state == ui::SHOW_STATE_FULLSCREEN) {
+ window_->SetProperty(aura::client::kShowStateKey, show_state);
+ }
window_->Show();
if (delegate_->CanActivate()) {
- if (state != ui::SHOW_STATE_INACTIVE)
+ if (show_state != ui::SHOW_STATE_INACTIVE)
Activate();
// SetInitialFocus() should be always be called, even for
// SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
@@ -577,15 +568,20 @@ void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
// Activate() might fail if the window is non-activatable. In this case, we
// should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial
// focused view from getting focused. See crbug.com/515594 for example.
- SetInitialFocus(IsActive() ? state : ui::SHOW_STATE_INACTIVE);
+ SetInitialFocus(IsActive() ? show_state : ui::SHOW_STATE_INACTIVE);
}
// On desktop aura, a window is activated first even when it is shown as
// minimized. Do the same for consistency.
- if (state == ui::SHOW_STATE_MINIMIZED)
+ if (show_state == ui::SHOW_STATE_MINIMIZED)
Minimize();
}
+void NativeWidgetAura::Hide() {
+ if (window_)
+ window_->Hide();
+}
+
bool NativeWidgetAura::IsVisible() const {
return window_ && window_->IsVisible();
}
@@ -717,6 +713,11 @@ bool NativeWidgetAura::IsMouseEventsEnabled() const {
return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
}
+bool NativeWidgetAura::IsMouseButtonDown() const {
+ return window_ ? window_->env()->IsMouseButtonDown()
+ : aura::Env::GetInstance()->IsMouseButtonDown();
+}
+
void NativeWidgetAura::ClearNativeFocus() {
aura::client::FocusClient* client = aura::client::GetFocusClient(window_);
if (window_ && client && window_->Contains(client->GetFocusedWindow()))
@@ -798,11 +799,15 @@ bool NativeWidgetAura::IsTranslucentWindowOpacitySupported() const {
return true;
}
+ui::GestureRecognizer* NativeWidgetAura::GetGestureRecognizer() {
+ return window_->env()->gesture_recognizer();
+}
+
void NativeWidgetAura::OnSizeConstraintsChanged() {
if (is_parallel_widget_in_window_manager_)
return;
- int32_t behavior = ui::mojom::kResizeBehaviorNone;
+ int32_t behavior = ws::mojom::kResizeBehaviorNone;
if (GetWidget()->widget_delegate())
behavior = GetWidget()->widget_delegate()->GetResizeBehavior();
window_->SetProperty(aura::client::kResizeBehaviorKey, behavior);
@@ -827,7 +832,7 @@ gfx::Size NativeWidgetAura::GetMaximumSize() const {
// A window should not have a maximum size and also be maximizable.
DCHECK(delegate_->GetMaximumSize().IsEmpty() ||
!(window_->GetProperty(aura::client::kResizeBehaviorKey) &
- ui::mojom::kResizeBehaviorCanMaximize));
+ ws::mojom::kResizeBehaviorCanMaximize));
return delegate_->GetMaximumSize();
}
@@ -890,8 +895,12 @@ void NativeWidgetAura::OnWindowDestroying(aura::Window* window) {
void NativeWidgetAura::OnWindowDestroyed(aura::Window* window) {
window_ = NULL;
+ // |OnNativeWidgetDestroyed| may delete |this| if the object does not own
+ // itself.
+ bool should_delete_this =
+ (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET);
delegate_->OnNativeWidgetDestroyed();
- if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ if (should_delete_this)
delete this;
}
@@ -1097,8 +1106,15 @@ namespace internal {
// static
NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
+ const Widget::InitParams& init_params,
internal::NativeWidgetDelegate* delegate) {
- return new NativeWidgetAura(delegate);
+ aura::Env* env = nullptr;
+ if (init_params.parent)
+ env = init_params.parent->env();
+ else if (init_params.context)
+ env = init_params.context->env();
+ return new NativeWidgetAura(
+ delegate, /*is_parallel_widget_in_window_manager*/ false, env);
}
// static
@@ -1208,11 +1224,6 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
}
// static
-bool NativeWidgetPrivate::IsMouseButtonDown() {
- return aura::Env::GetInstance()->IsMouseButtonDown();
-}
-
-// static
gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
#if defined(OS_WIN)
NONCLIENTMETRICS_XP ncm;
diff --git a/chromium/ui/views/widget/native_widget_aura.h b/chromium/ui/views/widget/native_widget_aura.h
index b0276c0158b..768f0bde976 100644
--- a/chromium/ui/views/widget/native_widget_aura.h
+++ b/chromium/ui/views/widget/native_widget_aura.h
@@ -21,6 +21,7 @@
#include "ui/wm/public/activation_delegate.h"
namespace aura {
+class Env;
class Window;
}
@@ -43,7 +44,8 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
// NativeWidgetAura is created in the window manager to represent a client
// window, in all other cases it's false.
explicit NativeWidgetAura(internal::NativeWidgetDelegate* delegate,
- bool is_parallel_widget_in_window_manager = false);
+ bool is_parallel_widget_in_window_manager = false,
+ aura::Env* env = nullptr);
// Called internally by NativeWidgetAura and DesktopNativeWidgetAura to
// associate |native_widget| with |window|.
@@ -103,10 +105,9 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
void SetShape(std::unique_ptr<Widget::ShapeRects> shape) override;
void Close() override;
void CloseNow() override;
- void Show() override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
void Hide() override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
- void ShowWithWindowState(ui::WindowShowState state) override;
bool IsVisible() const override;
void Activate() override;
void Deactivate() override;
@@ -133,6 +134,7 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
void SchedulePaintInRect(const gfx::Rect& rect) override;
void SetCursor(gfx::NativeCursor cursor) override;
bool IsMouseEventsEnabled() const override;
+ bool IsMouseButtonDown() const override;
void ClearNativeFocus() override;
gfx::Rect GetWorkAreaBoundsInScreen() const override;
Widget::MoveLoopResult RunMoveLoop(
@@ -145,6 +147,7 @@ class VIEWS_EXPORT NativeWidgetAura : public internal::NativeWidgetPrivate,
void SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) override;
bool IsTranslucentWindowOpacitySupported() const override;
+ ui::GestureRecognizer* GetGestureRecognizer() override;
void OnSizeConstraintsChanged() override;
void RepostNativeEvent(gfx::NativeEvent native_event) override;
std::string GetName() const override;
diff --git a/chromium/ui/views/widget/native_widget_aura_unittest.cc b/chromium/ui/views/widget/native_widget_aura_unittest.cc
index b1ef3a6805f..ee5f354c7c0 100644
--- a/chromium/ui/views/widget/native_widget_aura_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_aura_unittest.cc
@@ -9,7 +9,7 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/run_loop.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
@@ -310,9 +310,9 @@ class PropertyTestLayoutManager : public TestLayoutManagerBase {
private:
// aura::LayoutManager:
void OnWindowAddedToLayout(aura::Window* child) override {
- EXPECT_EQ(ui::mojom::kResizeBehaviorCanResize |
- ui::mojom::kResizeBehaviorCanMaximize |
- ui::mojom::kResizeBehaviorCanMinimize,
+ EXPECT_EQ(ws::mojom::kResizeBehaviorCanResize |
+ ws::mojom::kResizeBehaviorCanMaximize |
+ ws::mojom::kResizeBehaviorCanMinimize,
child->GetProperty(aura::client::kResizeBehaviorKey));
added_ = true;
}
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
index d515251a082..5bb34bd75c3 100644
--- a/chromium/ui/views/widget/native_widget_mac.h
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -19,9 +19,11 @@ namespace views {
namespace test {
class HitTestNativeWidgetMac;
class MockNativeWidgetMac;
+class WidgetTest;
}
class BridgedNativeWidget;
+class BridgedNativeWidgetHostImpl;
class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
public:
@@ -30,13 +32,11 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// Retrieves the bridge associated with the given NSWindow. Returns null if
// the supplied handle has no associated Widget.
+ static BridgedNativeWidgetHostImpl* GetBridgeHostImplForNativeWindow(
+ gfx::NativeWindow window);
static BridgedNativeWidget* GetBridgeForNativeWindow(
gfx::NativeWindow window);
- // Return true if the delegate's modal type is window-modal. These display as
- // a native window "sheet", and have a different lifetime to regular windows.
- bool IsWindowModalSheet() const;
-
// Informs |delegate_| that the native widget is about to be destroyed.
// BridgedNativeWidget::OnWindowWillClose() invokes this early when the
// NSWindowDelegate informs the bridge that the window is being closed (later,
@@ -96,10 +96,9 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
void SetShape(std::unique_ptr<Widget::ShapeRects> shape) override;
void Close() override;
void CloseNow() override;
- void Show() override;
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) override;
void Hide() override;
- void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
- void ShowWithWindowState(ui::WindowShowState state) override;
bool IsVisible() const override;
void Activate() override;
void Deactivate() override;
@@ -126,6 +125,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
void SchedulePaintInRect(const gfx::Rect& rect) override;
void SetCursor(gfx::NativeCursor cursor) override;
bool IsMouseEventsEnabled() const override;
+ bool IsMouseButtonDown() const override;
void ClearNativeFocus() override;
gfx::Rect GetWorkAreaBoundsInScreen() const override;
Widget::MoveLoopResult RunMoveLoop(
@@ -138,6 +138,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
void SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) override;
bool IsTranslucentWindowOpacitySupported() const override;
+ ui::GestureRecognizer* GetGestureRecognizer() override;
void OnSizeConstraintsChanged() override;
void RepostNativeEvent(gfx::NativeEvent native_event) override;
std::string GetName() const override;
@@ -145,6 +146,10 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
protected:
// Creates the NSWindow that will be passed to the BridgedNativeWidget.
// Called by InitNativeWidget. The return value will be autoreleased.
+ // Note that some tests (in particular, views_unittests that interact
+ // with ScopedFakeNSWindowFullscreen, on 10.10) assume that these windows
+ // are autoreleased, and will crash if the window has a more precise
+ // lifetime.
virtual NativeWidgetMacNSWindow* CreateNSWindow(
const Widget::InitParams& params);
@@ -152,13 +157,18 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
virtual void OnWindowDestroying(NSWindow* window) {}
internal::NativeWidgetDelegate* delegate() { return delegate_; }
+ BridgedNativeWidget* bridge() const;
+ BridgedNativeWidgetHostImpl* bridge_host_for_testing() const {
+ return bridge_host_.get();
+ }
private:
friend class test::MockNativeWidgetMac;
friend class test::HitTestNativeWidgetMac;
+ friend class views::test::WidgetTest;
internal::NativeWidgetDelegate* delegate_;
- std::unique_ptr<BridgedNativeWidget> bridge_;
+ std::unique_ptr<BridgedNativeWidgetHostImpl> bridge_host_;
Widget::InitParams::Ownership ownership_;
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index 3cf9af6b957..decbcdf69ac 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -9,6 +9,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/lazy_instance.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
@@ -18,6 +19,7 @@
#import "ui/base/cocoa/window_size_constants.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#include "ui/events/gestures/gesture_recognizer_impl_mac.h"
#include "ui/gfx/font_list.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/gfx/mac/nswindow_frame_controls.h"
@@ -25,6 +27,7 @@
#include "ui/native_theme/native_theme_mac.h"
#import "ui/views/cocoa/bridged_content_view.h"
#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/cocoa/cocoa_mouse_capture.h"
#import "ui/views/cocoa/drag_drop_client_mac.h"
#import "ui/views/cocoa/native_widget_mac_nswindow.h"
@@ -33,21 +36,25 @@
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/native_frame_view.h"
-// Self-owning animation delegate that starts a hide animation, then calls
-// -[NSWindow close] when the animation ends, releasing itself.
-@interface ViewsNSWindowCloseAnimator : NSObject<NSAnimationDelegate> {
- @private
- base::scoped_nsobject<NSWindow> window_;
- base::scoped_nsobject<NSAnimation> animation_;
-}
-
-+ (void)closeWindowWithAnimation:(NSWindow*)window;
-
-@end
+using views_bridge_mac::mojom::WindowVisibilityState;
namespace views {
namespace {
+base::LazyInstance<ui::GestureRecognizerImplMac>::Leaky
+ g_gesture_recognizer_instance = LAZY_INSTANCE_INITIALIZER;
+
+NativeWidgetMac* GetNativeWidgetMacForNativeWindow(
+ gfx::NativeWindow native_window) {
+ id<NSWindowDelegate> window_delegate = [native_window delegate];
+ if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) {
+ ViewsNSWindowDelegate* delegate =
+ base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate);
+ return [delegate nativeWidgetMac];
+ }
+ return nullptr; // Not created by NativeWidgetMac.
+}
+
NSInteger StyleMaskForParams(const Widget::InitParams& params) {
// If the Widget is modal, it will be displayed as a sheet. This works best if
// it has NSTitledWindowMask. For example, with NSBorderlessWindowMask, the
@@ -75,9 +82,8 @@ NSInteger StyleMaskForParams(const Widget::InitParams& params) {
NativeWidgetMac::NativeWidgetMac(internal::NativeWidgetDelegate* delegate)
: delegate_(delegate),
- bridge_(new BridgedNativeWidget(this)),
- ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) {
-}
+ bridge_host_(new BridgedNativeWidgetHostImpl(this)),
+ ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) {}
NativeWidgetMac::~NativeWidgetMac() {
if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
@@ -89,19 +95,17 @@ NativeWidgetMac::~NativeWidgetMac() {
// static
BridgedNativeWidget* NativeWidgetMac::GetBridgeForNativeWindow(
gfx::NativeWindow window) {
- id<NSWindowDelegate> window_delegate = [window delegate];
- if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) {
- ViewsNSWindowDelegate* delegate =
- base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate);
- return [delegate nativeWidgetMac]->bridge_.get();
- }
+ if (NativeWidgetMac* widget = GetNativeWidgetMacForNativeWindow(window))
+ return widget->bridge();
return nullptr; // Not created by NativeWidgetMac.
}
-bool NativeWidgetMac::IsWindowModalSheet() const {
- return bridge_ && bridge_->parent() &&
- GetWidget()->widget_delegate()->GetModalType() ==
- ui::MODAL_TYPE_WINDOW;
+// static
+BridgedNativeWidgetHostImpl* NativeWidgetMac::GetBridgeHostImplForNativeWindow(
+ gfx::NativeWindow window) {
+ if (NativeWidgetMac* widget = GetNativeWidgetMacForNativeWindow(window))
+ return widget->bridge_host_.get();
+ return nullptr; // Not created by NativeWidgetMac.
}
void NativeWidgetMac::WindowDestroying() {
@@ -110,10 +114,14 @@ void NativeWidgetMac::WindowDestroying() {
}
void NativeWidgetMac::WindowDestroyed() {
- DCHECK(bridge_);
- bridge_.reset();
+ DCHECK(bridge());
+ bridge_host_.reset();
+ // |OnNativeWidgetDestroyed| may delete |this| if the object does not own
+ // itself.
+ bool should_delete_this =
+ (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET);
delegate_->OnNativeWidgetDestroyed();
- if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
+ if (should_delete_this)
delete this;
}
@@ -129,9 +137,10 @@ int NativeWidgetMac::SheetPositionY() {
void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
ownership_ = params.ownership;
name_ = params.name;
- base::scoped_nsobject<NSWindow> window([CreateNSWindow(params) retain]);
- [window setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
- bridge_->Init(window, params);
+ base::scoped_nsobject<NativeWidgetMacNSWindow> window(
+ [CreateNSWindow(params) retain]);
+ bridge()->SetWindow(window);
+ bridge_host_->InitWindow(params);
// Only set always-on-top here if it is true since setting it may affect how
// the window is treated by Expose.
@@ -141,21 +150,20 @@ void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
delegate_->OnNativeWidgetCreated(true);
DCHECK(GetWidget()->GetRootView());
- bridge_->SetRootView(GetWidget()->GetRootView());
+ bridge_host_->SetRootView(GetWidget()->GetRootView());
+ bridge()->CreateContentView(GetWidget()->GetRootView()->bounds());
+ bridge()->CreateDragDropClient(GetWidget()->GetRootView());
if (auto* focus_manager = GetWidget()->GetFocusManager()) {
- [window makeFirstResponder:bridge_->ns_view()];
- bridge_->SetFocusManager(focus_manager);
+ bridge()->MakeFirstResponder();
+ bridge_host_->SetFocusManager(focus_manager);
}
- // "Infer" must be handled by ViewsDelegate::OnBeforeWidgetInit().
- DCHECK_NE(Widget::InitParams::INFER_OPACITY, params.opacity);
- bool translucent = params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
- bridge_->CreateLayer(params.layer_type, translucent);
+ bridge_host_->CreateCompositor(params);
}
void NativeWidgetMac::OnWidgetInitDone() {
OnSizeConstraintsChanged();
- bridge_->OnWidgetInitDone();
+ bridge_host_->OnWidgetInitDone();
}
NonClientFrameView* NativeWidgetMac::CreateNonClientFrameView() {
@@ -193,7 +201,7 @@ gfx::NativeView NativeWidgetMac::GetNativeView() const {
}
gfx::NativeWindow NativeWidgetMac::GetNativeWindow() const {
- return bridge_ ? bridge_->ns_window() : nil;
+ return bridge() ? bridge()->ns_window() : nil;
}
Widget* NativeWidgetMac::GetTopLevelWidget() {
@@ -202,60 +210,61 @@ Widget* NativeWidgetMac::GetTopLevelWidget() {
}
const ui::Compositor* NativeWidgetMac::GetCompositor() const {
- return bridge_ && bridge_->layer() ? bridge_->layer()->GetCompositor()
- : nullptr;
+ return bridge_host_ && bridge_host_->layer()
+ ? bridge_host_->layer()->GetCompositor()
+ : nullptr;
}
const ui::Layer* NativeWidgetMac::GetLayer() const {
- return bridge_ ? bridge_->layer() : nullptr;
+ return bridge_host_ ? bridge_host_->layer() : nullptr;
}
void NativeWidgetMac::ReorderNativeViews() {
- if (bridge_)
- bridge_->ReorderChildViews();
+ if (bridge())
+ bridge()->ReorderChildViews();
}
void NativeWidgetMac::ViewRemoved(View* view) {
- DragDropClientMac* client = bridge_ ? bridge_->drag_drop_client() : nullptr;
+ DragDropClientMac* client = bridge() ? bridge()->drag_drop_client() : nullptr;
if (client)
client->drop_helper()->ResetTargetViewIfEquals(view);
}
void NativeWidgetMac::SetNativeWindowProperty(const char* name, void* value) {
- if (bridge_)
- bridge_->SetNativeWindowProperty(name, value);
+ if (bridge())
+ bridge()->SetNativeWindowProperty(name, value);
}
void* NativeWidgetMac::GetNativeWindowProperty(const char* name) const {
- if (bridge_)
- return bridge_->GetNativeWindowProperty(name);
+ if (bridge())
+ return bridge()->GetNativeWindowProperty(name);
return nullptr;
}
TooltipManager* NativeWidgetMac::GetTooltipManager() const {
- if (bridge_)
- return bridge_->tooltip_manager();
+ if (bridge())
+ return bridge()->tooltip_manager();
return nullptr;
}
void NativeWidgetMac::SetCapture() {
- if (bridge_ && !bridge_->HasCapture())
- bridge_->AcquireCapture();
+ if (bridge())
+ bridge()->AcquireCapture();
}
void NativeWidgetMac::ReleaseCapture() {
- if (bridge_)
- bridge_->ReleaseCapture();
+ if (bridge())
+ bridge()->ReleaseCapture();
}
bool NativeWidgetMac::HasCapture() const {
- return bridge_ && bridge_->HasCapture();
+ return bridge_host_ && bridge_host_->IsMouseCaptureActive();
}
ui::InputMethod* NativeWidgetMac::GetInputMethod() {
- return bridge_ ? bridge_->GetInputMethod() : nullptr;
+ return bridge_host_ ? bridge_host_->GetInputMethod() : nullptr;
}
void NativeWidgetMac::CenterWindow(const gfx::Size& size) {
@@ -280,14 +289,9 @@ void NativeWidgetMac::GetWindowPlacement(
}
bool NativeWidgetMac::SetWindowTitle(const base::string16& title) {
- NSWindow* window = GetNativeWindow();
- NSString* current_title = [window title];
- NSString* new_title = base::SysUTF16ToNSString(title);
- if ([current_title isEqualToString:new_title])
+ if (!bridge_host_)
return false;
-
- [window setTitle:new_title];
- return true;
+ return bridge_host_->SetWindowTitle(title);
}
void NativeWidgetMac::SetWindowIcons(const gfx::ImageSkia& window_icon,
@@ -307,23 +311,21 @@ void NativeWidgetMac::InitModalType(ui::ModalType modal_type) {
// A peculiarity of the constrained window framework is that it permits a
// dialog of MODAL_TYPE_WINDOW to have a null parent window; falling back to
// a non-modal window in this case.
- DCHECK(bridge_->parent() || modal_type == ui::MODAL_TYPE_WINDOW);
+ DCHECK(bridge()->parent() || modal_type == ui::MODAL_TYPE_WINDOW);
// Everything happens upon show.
}
gfx::Rect NativeWidgetMac::GetWindowBoundsInScreen() const {
- return gfx::ScreenRectFromNSRect([GetNativeWindow() frame]);
+ return bridge_host_ ? bridge_host_->GetWindowBoundsInScreen() : gfx::Rect();
}
gfx::Rect NativeWidgetMac::GetClientAreaBoundsInScreen() const {
- NSWindow* window = GetNativeWindow();
- return gfx::ScreenRectFromNSRect(
- [window contentRectForFrameRect:[window frame]]);
+ return bridge_host_ ? bridge_host_->GetContentBoundsInScreen() : gfx::Rect();
}
gfx::Rect NativeWidgetMac::GetRestoredBounds() const {
- return bridge_ ? bridge_->GetRestoredBounds() : gfx::Rect();
+ return bridge_host_ ? bridge_host_->GetRestoredBounds() : gfx::Rect();
}
std::string NativeWidgetMac::GetWorkspace() const {
@@ -331,18 +333,18 @@ std::string NativeWidgetMac::GetWorkspace() const {
}
void NativeWidgetMac::SetBounds(const gfx::Rect& bounds) {
- if (bridge_)
- bridge_->SetBounds(bounds);
+ if (bridge_host_)
+ bridge_host_->SetBounds(bounds);
}
void NativeWidgetMac::SetBoundsConstrained(const gfx::Rect& bounds) {
- if (!bridge_)
+ if (!bridge())
return;
gfx::Rect new_bounds(bounds);
NativeWidgetPrivate* ancestor =
- bridge_ && bridge_->parent()
- ? GetNativeWidgetForNativeWindow(bridge_->parent()->GetNSWindow())
+ bridge() && bridge()->parent()
+ ? GetNativeWidgetForNativeWindow(bridge()->parent()->GetNSWindow())
: nullptr;
if (!ancestor) {
new_bounds = ConstrainBoundsToDisplayWorkArea(new_bounds);
@@ -373,87 +375,23 @@ void NativeWidgetMac::SetShape(std::unique_ptr<Widget::ShapeRects> shape) {
}
void NativeWidgetMac::Close() {
- if (!bridge_)
- return;
-
- // Keep |window| on the stack so that the ObjectiveC block below can capture
- // it and properly increment the reference count bound to the posted task.
- NSWindow* window = GetNativeWindow();
-
- if (IsWindowModalSheet()) {
- // Sheets can't be closed normally. This starts the sheet closing. Once the
- // sheet has finished animating, it will call sheetDidEnd: on the parent
- // window's delegate. Note it still needs to be asynchronous, since code
- // calling Widget::Close() doesn't expect things to be deleted upon return.
- // Ensure |window| is retained by a block. Note in some cases during
- // teardown, [window sheetParent] may be nil.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(base::RetainBlock(^{
- [NSApp endSheet:window];
- })));
- return;
- }
-
- // For other modal types, animate the close.
- if (bridge_->ShouldRunCustomAnimationFor(Widget::ANIMATE_HIDE)) {
- [ViewsNSWindowCloseAnimator closeWindowWithAnimation:window];
- return;
- }
-
- // Clear the view early to suppress repaints.
- bridge_->SetRootView(nullptr);
-
- // Widget::Close() ensures [Non]ClientView::CanClose() returns true, so there
- // is no need to call the NSWindow or its delegate's -windowShouldClose:
- // implementation in the manner of -[NSWindow performClose:]. But,
- // like -performClose:, first remove the window from AppKit's display
- // list to avoid crashes like http://crbug.com/156101.
- [window orderOut:nil];
-
- // 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::BindOnce(base::RetainBlock(^{
- [window close];
- })));
+ if (bridge())
+ bridge()->CloseWindow();
}
void NativeWidgetMac::CloseNow() {
- if (!bridge_)
- return;
-
- // NSWindows must be retained until -[NSWindow close] returns.
- base::scoped_nsobject<NSWindow> window(GetNativeWindow(),
- base::scoped_policy::RETAIN);
-
- // If there's a bridge at this point, it means there must be a window as well.
- DCHECK(window);
- [window close];
- // Note: |this| is deleted here when ownership_ == NATIVE_WIDGET_OWNS_WIDGET.
+ if (bridge())
+ bridge()->CloseWindowNow();
+ // Note: |bridge_host_| will be deleted her, and |this| will be deleted here
+ // when ownership_ == NATIVE_WIDGET_OWNS_WIDGET,
}
-void NativeWidgetMac::Show() {
- ShowWithWindowState(ui::SHOW_STATE_NORMAL);
-}
-
-void NativeWidgetMac::Hide() {
- if (!bridge_)
+void NativeWidgetMac::Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) {
+ if (!bridge())
return;
- bridge_->SetVisibilityState(BridgedNativeWidget::HIDE_WINDOW);
-}
-
-void NativeWidgetMac::ShowMaximizedWithBounds(
- const gfx::Rect& restored_bounds) {
- NOTIMPLEMENTED();
-}
-
-void NativeWidgetMac::ShowWithWindowState(ui::WindowShowState state) {
- if (!bridge_)
- return;
-
- switch (state) {
+ switch (show_state) {
case ui::SHOW_STATE_DEFAULT:
case ui::SHOW_STATE_NORMAL:
case ui::SHOW_STATE_INACTIVE:
@@ -467,24 +405,30 @@ void NativeWidgetMac::ShowWithWindowState(ui::WindowShowState state) {
NOTREACHED();
break;
}
- bridge_->SetVisibilityState(state == ui::SHOW_STATE_INACTIVE
- ? BridgedNativeWidget::SHOW_INACTIVE
- : BridgedNativeWidget::SHOW_AND_ACTIVATE_WINDOW);
+ bridge()->SetVisibilityState(
+ show_state == ui::SHOW_STATE_INACTIVE
+ ? WindowVisibilityState::kShowInactive
+ : WindowVisibilityState::kShowAndActivateWindow);
// Ignore the SetInitialFocus() result. BridgedContentView should get
// firstResponder status regardless.
- delegate_->SetInitialFocus(state);
+ delegate_->SetInitialFocus(show_state);
+}
+
+void NativeWidgetMac::Hide() {
+ if (!bridge())
+ return;
+ bridge()->SetVisibilityState(WindowVisibilityState::kHideWindow);
}
bool NativeWidgetMac::IsVisible() const {
- return bridge_ && bridge_->window_visible();
+ return bridge_host_ && bridge_host_->IsVisible();
}
void NativeWidgetMac::Activate() {
- if (!bridge_)
+ if (!bridge())
return;
-
- bridge_->SetVisibilityState(BridgedNativeWidget::SHOW_AND_ACTIVATE_WINDOW);
+ bridge()->SetVisibilityState(WindowVisibilityState::kShowAndActivateWindow);
}
void NativeWidgetMac::Deactivate() {
@@ -492,7 +436,7 @@ void NativeWidgetMac::Deactivate() {
}
bool NativeWidgetMac::IsActive() const {
- return [GetNativeWindow() isKeyWindow];
+ return bridge_host_ ? bridge_host_->IsWindowKey() : false;
}
void NativeWidgetMac::SetAlwaysOnTop(bool always_on_top) {
@@ -504,7 +448,9 @@ bool NativeWidgetMac::IsAlwaysOnTop() const {
}
void NativeWidgetMac::SetVisibleOnAllWorkspaces(bool always_visible) {
- gfx::SetNSWindowVisibleOnAllWorkspaces(GetNativeWindow(), always_visible);
+ if (!bridge())
+ return;
+ bridge()->SetVisibleOnAllSpaces(always_visible);
}
bool NativeWidgetMac::IsVisibleOnAllWorkspaces() const {
@@ -516,13 +462,9 @@ void NativeWidgetMac::Maximize() {
}
void NativeWidgetMac::Minimize() {
- NSWindow* window = GetNativeWindow();
- // Calling performMiniaturize: will momentarily highlight the button, but
- // AppKit will reject it if there is no miniaturize button.
- if ([window styleMask] & NSMiniaturizableWindowMask)
- [window performMiniaturize:nil];
- else
- [window miniaturize:nil];
+ if (!bridge())
+ return;
+ bridge()->SetMiniaturized(true);
}
bool NativeWidgetMac::IsMaximized() const {
@@ -532,32 +474,38 @@ bool NativeWidgetMac::IsMaximized() const {
}
bool NativeWidgetMac::IsMinimized() const {
- return [GetNativeWindow() isMiniaturized];
+ if (!bridge_host_)
+ return false;
+ return bridge_host_->IsMiniaturized();
}
void NativeWidgetMac::Restore() {
- SetFullscreen(false);
- [GetNativeWindow() deminiaturize:nil];
+ if (!bridge())
+ return;
+ bridge()->SetFullscreen(false);
+ bridge()->SetMiniaturized(false);
}
void NativeWidgetMac::SetFullscreen(bool fullscreen) {
- if (!bridge_ || fullscreen == IsFullscreen())
+ if (!bridge_host_)
return;
-
- bridge_->ToggleDesiredFullscreenState();
+ bridge_host_->SetFullscreen(fullscreen);
}
bool NativeWidgetMac::IsFullscreen() const {
- return bridge_ && bridge_->target_fullscreen_state();
+ return bridge_host_ && bridge_host_->target_fullscreen_state();
}
void NativeWidgetMac::SetOpacity(float opacity) {
- [GetNativeWindow() setAlphaValue:opacity];
+ if (!bridge())
+ return;
+ bridge()->SetOpacity(opacity);
}
void NativeWidgetMac::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
- [GetNativeWindow() setContentAspectRatio:NSMakeSize(aspect_ratio.width(),
- aspect_ratio.height())];
+ if (!bridge())
+ return;
+ bridge()->SetContentAspectRatio(aspect_ratio);
}
void NativeWidgetMac::FlashFrame(bool flash_frame) {
@@ -569,7 +517,7 @@ void NativeWidgetMac::RunShellDrag(View* view,
const gfx::Point& location,
int operation,
ui::DragDropTypes::DragEventSource source) {
- bridge_->drag_drop_client()->StartDragAndDrop(view, data, operation, source);
+ bridge()->drag_drop_client()->StartDragAndDrop(view, data, operation, source);
}
void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
@@ -582,13 +530,13 @@ void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
target_rect.origin.y =
NSHeight(client_rect) - target_rect.origin.y - NSHeight(target_rect);
[GetNativeView() setNeedsDisplayInRect:target_rect];
- if (bridge_ && bridge_->layer())
- bridge_->layer()->SchedulePaint(rect);
+ if (bridge_host_ && bridge_host_->layer())
+ bridge_host_->layer()->SchedulePaint(rect);
}
void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
- if (bridge_)
- bridge_->SetCursor(cursor);
+ if (bridge())
+ bridge()->SetCursor(cursor);
}
bool NativeWidgetMac::IsMouseEventsEnabled() const {
@@ -598,35 +546,42 @@ bool NativeWidgetMac::IsMouseEventsEnabled() const {
return true;
}
+bool NativeWidgetMac::IsMouseButtonDown() const {
+ return [NSEvent pressedMouseButtons] != 0;
+}
+
void NativeWidgetMac::ClearNativeFocus() {
// To quote DesktopWindowTreeHostX11, "This method is weird and misnamed."
// The goal is to set focus to the content window, thereby removing focus from
// any NSView in the window that doesn't belong to toolkit-views.
- [GetNativeWindow() makeFirstResponder:GetNativeView()];
+ if (!bridge())
+ return;
+ bridge()->MakeFirstResponder();
}
gfx::Rect NativeWidgetMac::GetWorkAreaBoundsInScreen() const {
- return gfx::ScreenRectFromNSRect([[GetNativeWindow() screen] visibleFrame]);
+ return bridge_host_ ? bridge_host_->GetCurrentDisplay().work_area()
+ : gfx::Rect();
}
Widget::MoveLoopResult NativeWidgetMac::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
- if (!bridge_)
+ if (!bridge())
return Widget::MOVE_LOOP_CANCELED;
- return bridge_->RunMoveLoop(drag_offset);
+ return bridge()->RunMoveLoop(drag_offset);
}
void NativeWidgetMac::EndMoveLoop() {
- if (bridge_)
- bridge_->EndMoveLoop();
+ if (bridge())
+ bridge()->EndMoveLoop();
}
void NativeWidgetMac::SetVisibilityChangedAnimationsEnabled(bool value) {
- if (bridge_)
- bridge_->SetAnimationEnabled(value);
+ if (bridge())
+ bridge()->SetAnimationEnabled(value);
}
void NativeWidgetMac::SetVisibilityAnimationDuration(
@@ -636,16 +591,24 @@ void NativeWidgetMac::SetVisibilityAnimationDuration(
void NativeWidgetMac::SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) {
- if (bridge_)
- bridge_->set_transitions_to_animate(transition);
+ if (bridge())
+ bridge()->set_transitions_to_animate(transition);
}
bool NativeWidgetMac::IsTranslucentWindowOpacitySupported() const {
return false;
}
+ui::GestureRecognizer* NativeWidgetMac::GetGestureRecognizer() {
+ return g_gesture_recognizer_instance.Pointer();
+}
+
void NativeWidgetMac::OnSizeConstraintsChanged() {
- bridge_->OnSizeConstraintsChanged();
+ Widget* widget = GetWidget();
+ bridge()->SetSizeConstraints(widget->GetMinimumSize(),
+ widget->GetMaximumSize(),
+ widget->widget_delegate()->CanResize(),
+ widget->widget_delegate()->CanMaximize());
}
void NativeWidgetMac::RepostNativeEvent(gfx::NativeEvent native_event) {
@@ -668,6 +631,10 @@ NativeWidgetMacNSWindow* NativeWidgetMac::CreateNSWindow(
defer:NO] autorelease];
}
+BridgedNativeWidget* NativeWidgetMac::bridge() const {
+ return bridge_host_ ? bridge_host_->bridge_impl() : nullptr;
+}
+
////////////////////////////////////////////////////////////////////////////////
// Widget, public:
@@ -709,6 +676,7 @@ namespace internal {
// static
NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
+ const Widget::InitParams& init_params,
internal::NativeWidgetDelegate* delegate) {
return new NativeWidgetMac(delegate);
}
@@ -721,13 +689,9 @@ NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
// static
NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
- gfx::NativeWindow native_window) {
- id<NSWindowDelegate> window_delegate = [native_window delegate];
- if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) {
- ViewsNSWindowDelegate* delegate =
- base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate);
- return [delegate nativeWidgetMac];
- }
+ gfx::NativeWindow window) {
+ if (NativeWidgetMac* widget = GetNativeWidgetMacForNativeWindow(window))
+ return widget;
return nullptr; // Not created by NativeWidgetMac.
}
@@ -842,11 +806,6 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
}
// static
-bool NativeWidgetPrivate::IsMouseButtonDown() {
- return [NSEvent pressedMouseButtons] != 0;
-}
-
-// static
gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
NOTIMPLEMENTED();
return gfx::FontList();
@@ -860,29 +819,3 @@ gfx::NativeView NativeWidgetPrivate::GetGlobalCapture(
} // namespace internal
} // namespace views
-
-@implementation ViewsNSWindowCloseAnimator
-
-- (id)initWithWindow:(NSWindow*)window {
- if ((self = [super init])) {
- window_.reset([window retain]);
- animation_.reset(
- [[ConstrainedWindowAnimationHide alloc] initWithWindow:window]);
- [animation_ setDelegate:self];
- [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
- [animation_ startAnimation];
- }
- return self;
-}
-
-+ (void)closeWindowWithAnimation:(NSWindow*)window {
- [[ViewsNSWindowCloseAnimator alloc] initWithWindow:window];
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- [window_ close];
- [animation_ setDelegate:nil];
- [self release];
-}
-
-@end
diff --git a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
index f6d68885a92..bb6fe00eaeb 100644
--- a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
@@ -12,7 +12,7 @@
#include "ui/base/test/ui_controls.h"
#import "ui/base/test/windowed_nsnotification_observer.h"
#import "ui/events/test/cocoa_test_event_utils.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/test_widget_observer.h"
#include "ui/views/test/views_interactive_ui_test_base.h"
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index 8fcb213c579..ebb9ea6cd6d 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -27,7 +27,7 @@
#import "ui/events/test/cocoa_test_event_utils.h"
#include "ui/events/test/event_generator.h"
#import "ui/gfx/mac/coordinate_conversion.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#import "ui/views/cocoa/bridged_content_view.h"
#import "ui/views/cocoa/bridged_native_widget.h"
#import "ui/views/cocoa/native_widget_mac_nswindow.h"
@@ -103,15 +103,11 @@ class BridgedNativeWidgetTestApi {
// Simulate a frame swap from the compositor.
void SimulateFrameSwap(const gfx::Size& size) {
const float kScaleFactor = 1.0f;
- ui::CALayerFrameSink* ca_layer_frame_sink =
- ui::CALayerFrameSink::FromAcceleratedWidget(
- bridge_->compositor_->widget()->accelerated_widget());
gfx::CALayerParams ca_layer_params;
ca_layer_params.is_empty = false;
ca_layer_params.pixel_size = size;
ca_layer_params.scale_factor = kScaleFactor;
- ca_layer_frame_sink->UpdateCALayerTree(ca_layer_params);
- bridge_->AcceleratedWidgetCALayerParamsUpdated();
+ bridge_->SetCALayerParams(ca_layer_params);
}
NSAnimation* show_animation() {
@@ -1756,7 +1752,7 @@ class CustomTitleWidgetDelegate : public WidgetDelegate {
};
// Test that undocumented title-hiding API we're using does the job.
-TEST_F(NativeWidgetMacTest, DoesHideTitle) {
+TEST_F(NativeWidgetMacTest, DISABLED_DoesHideTitle) {
// Same as CreateTopLevelPlatformWidget but with a custom delegate.
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
Widget* widget = new Widget;
@@ -1922,10 +1918,13 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Titled) {
NSWindow* window = widget->GetNativeWindow();
base::scoped_nsobject<MockBridgedView> mock_bridged_view(
[[MockBridgedView alloc] init]);
+ // Reset drawRect count.
+ [mock_bridged_view setDrawRectCount:0];
[window setContentView:mock_bridged_view];
// Ensure the initial draw of the window is done.
- base::RunLoop().RunUntilIdle();
+ while ([mock_bridged_view drawRectCount] == 0)
+ base::RunLoop().RunUntilIdle();
// Add a dummy view to the widget. This will cause SchedulePaint to be called
// on the dummy view.
@@ -1937,7 +1936,8 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Titled) {
widget->GetContentsView()->AddChildView(dummy_view);
// SchedulePaint is asyncronous. Wait for drawRect: to be called.
- base::RunLoop().RunUntilIdle();
+ while ([mock_bridged_view drawRectCount] == 0)
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, [mock_bridged_view drawRectCount]);
int client_area_height = widget->GetClientAreaBoundsInScreen().height();
@@ -1964,10 +1964,13 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Borderless) {
NSWindow* window = widget->GetNativeWindow();
base::scoped_nsobject<MockBridgedView> mock_bridged_view(
[[MockBridgedView alloc] init]);
+ // Reset drawRect count.
+ [mock_bridged_view setDrawRectCount:0];
[window setContentView:mock_bridged_view];
// Ensure the initial draw of the window is done.
- base::RunLoop().RunUntilIdle();
+ while ([mock_bridged_view drawRectCount] == 0)
+ base::RunLoop().RunUntilIdle();
// Add a dummy view to the widget. This will cause SchedulePaint to be called
// on the dummy view.
@@ -1979,7 +1982,8 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Borderless) {
widget->GetRootView()->AddChildView(dummy_view);
// SchedulePaint is asyncronous. Wait for drawRect: to be called.
- base::RunLoop().RunUntilIdle();
+ while ([mock_bridged_view drawRectCount] == 0)
+ base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, [mock_bridged_view drawRectCount]);
// These are expected dummy_view bounds in AppKit coordinate system. The y
diff --git a/chromium/ui/views/widget/native_widget_private.h b/chromium/ui/views/widget/native_widget_private.h
index 53c60d77ace..6aedb90e714 100644
--- a/chromium/ui/views/widget/native_widget_private.h
+++ b/chromium/ui/views/widget/native_widget_private.h
@@ -12,6 +12,7 @@
#include "ui/base/ui_base_types.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/native_widget.h"
+#include "ui/views/widget/widget.h"
namespace gfx {
class FontList;
@@ -21,6 +22,7 @@ class Rect;
namespace ui {
class InputMethod;
+class GestureRecognizer;
class OSExchangeData;
}
@@ -49,6 +51,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
// Creates an appropriate default NativeWidgetPrivate implementation for the
// current OS/circumstance.
static NativeWidgetPrivate* CreateNativeWidget(
+ const Widget::InitParams& init_params,
internal::NativeWidgetDelegate* delegate);
static NativeWidgetPrivate* GetNativeWidgetForNativeView(
@@ -68,9 +71,6 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
static void ReparentNativeView(gfx::NativeView native_view,
gfx::NativeView new_parent);
- // Returns true if any mouse button is currently down.
- static bool IsMouseButtonDown();
-
static gfx::FontList GetWindowTitleFontList();
// Returns the NativeView with capture, otherwise NULL if there is no current
@@ -184,12 +184,9 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual void SetShape(std::unique_ptr<Widget::ShapeRects> shape) = 0;
virtual void Close() = 0;
virtual void CloseNow() = 0;
- virtual void Show() = 0;
+ virtual void Show(ui::WindowShowState show_state,
+ const gfx::Rect& restore_bounds) = 0;
virtual void Hide() = 0;
- // Invoked if the initial show should maximize the window. |restored_bounds|
- // is the bounds of the window when not maximized.
- virtual void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) = 0;
- virtual void ShowWithWindowState(ui::WindowShowState show_state) = 0;
virtual bool IsVisible() const = 0;
virtual void Activate() = 0;
virtual void Deactivate() = 0;
@@ -216,6 +213,8 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual void SchedulePaintInRect(const gfx::Rect& rect) = 0;
virtual void SetCursor(gfx::NativeCursor cursor) = 0;
virtual bool IsMouseEventsEnabled() const = 0;
+ // Returns true if any mouse button is currently down.
+ virtual bool IsMouseButtonDown() const = 0;
virtual void ClearNativeFocus() = 0;
virtual gfx::Rect GetWorkAreaBoundsInScreen() const = 0;
virtual Widget::MoveLoopResult RunMoveLoop(
@@ -229,6 +228,7 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
virtual void SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) = 0;
virtual bool IsTranslucentWindowOpacitySupported() const = 0;
+ virtual ui::GestureRecognizer* GetGestureRecognizer() = 0;
virtual void OnSizeConstraintsChanged() = 0;
// Repost an unhandled event to the native widget for default OS processing.
diff --git a/chromium/ui/views/widget/root_view_unittest.cc b/chromium/ui/views/widget/root_view_unittest.cc
index 82959179009..d1bee1793e7 100644
--- a/chromium/ui/views/widget/root_view_unittest.cc
+++ b/chromium/ui/views/widget/root_view_unittest.cc
@@ -8,6 +8,7 @@
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "ui/events/event_utils.h"
+#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view_targeter.h"
@@ -133,7 +134,8 @@ TEST_F(RootViewTest, ContextMenuFromKeyEvent) {
focused_view->RequestFocus();
// No context menu should be shown for a keypress of 'A'.
- ui::KeyEvent nomenu_key_event('a', ui::VKEY_A, ui::EF_NONE);
+ ui::KeyEvent nomenu_key_event('a', ui::VKEY_A, ui::DomCode::NONE,
+ ui::EF_NONE);
ui::EventDispatchDetails details =
root_view->OnEventFromSource(&nomenu_key_event);
EXPECT_FALSE(details.target_destroyed);
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index e4e7fc6ce96..5ad48b616fa 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -39,6 +39,11 @@
#include "ui/views/window/custom_frame_view.h"
#include "ui/views/window/dialog_delegate.h"
+#if defined(USE_AURA)
+#include "ui/aura/env.h" // nogncheck
+#include "ui/aura/window.h" // nogncheck
+#endif
+
namespace views {
namespace {
@@ -70,7 +75,7 @@ NativeWidget* CreateNativeWidget(const Widget::InitParams& params,
if (native_widget)
return native_widget;
}
- return internal::NativeWidgetPrivate::CreateNativeWidget(delegate);
+ return internal::NativeWidgetPrivate::CreateNativeWidget(params, delegate);
}
void NotifyCaretBoundsChanged(ui::InputMethod* input_method) {
@@ -334,11 +339,9 @@ void Widget::Init(const InitParams& in_params) {
native_widget_ = CreateNativeWidget(params, this)->AsNativeWidgetPrivate();
root_view_.reset(CreateRootView());
default_theme_provider_.reset(new ui::DefaultThemeProvider);
- if (params.type == InitParams::TYPE_MENU) {
- is_mouse_button_pressed_ =
- internal::NativeWidgetPrivate::IsMouseButtonDown();
- }
native_widget_->InitNativeWidget(params);
+ if (params.type == InitParams::TYPE_MENU)
+ is_mouse_button_pressed_ = native_widget_->IsMouseButtonDown();
if (RequiresNonClientView(params.type)) {
non_client_view_ = new NonClientView;
non_client_view_->SetFrameView(CreateNonClientFrameView());
@@ -617,19 +620,20 @@ void Widget::Show() {
if (saved_show_state_ == ui::SHOW_STATE_MAXIMIZED &&
!initial_restored_bounds_.IsEmpty() &&
!IsFullscreen()) {
- native_widget_->ShowMaximizedWithBounds(initial_restored_bounds_);
+ native_widget_->Show(ui::SHOW_STATE_MAXIMIZED, initial_restored_bounds_);
} else {
- native_widget_->ShowWithWindowState(
- IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : saved_show_state_);
+ native_widget_->Show(
+ IsFullscreen() ? ui::SHOW_STATE_FULLSCREEN : saved_show_state_,
+ gfx::Rect());
}
// |saved_show_state_| only applies the first time the window is shown.
// If we don't reset the value the window may be shown maximized every time
// it is subsequently shown after being hidden.
saved_show_state_ = ui::SHOW_STATE_NORMAL;
} else {
- CanActivate()
- ? native_widget_->Show()
- : native_widget_->ShowWithWindowState(ui::SHOW_STATE_INACTIVE);
+ native_widget_->Show(
+ CanActivate() ? ui::SHOW_STATE_NORMAL : ui::SHOW_STATE_INACTIVE,
+ gfx::Rect());
}
}
@@ -647,7 +651,7 @@ void Widget::ShowInactive() {
SetBounds(initial_restored_bounds_);
saved_show_state_ = ui::SHOW_STATE_NORMAL;
}
- native_widget_->ShowWithWindowState(ui::SHOW_STATE_INACTIVE);
+ native_widget_->Show(ui::SHOW_STATE_INACTIVE, gfx::Rect());
}
void Widget::Activate() {
@@ -836,10 +840,6 @@ void Widget::UpdateWindowTitle() {
return;
non_client_view_->UpdateWindowTitle();
-
- // If the non-client view is rendering its own title, it'll need to relayout
- // now and to get a paint update later on.
- non_client_view_->Layout();
}
void Widget::UpdateWindowIcon() {
@@ -953,7 +953,7 @@ void Widget::SetCapture(View* view) {
return;
}
- if (internal::NativeWidgetPrivate::IsMouseButtonDown())
+ if (native_widget_->IsMouseButtonDown())
is_mouse_button_pressed_ = true;
root_view_->SetMouseHandler(view);
}
@@ -981,7 +981,12 @@ gfx::Rect Widget::GetWorkAreaBoundsInScreen() const {
void Widget::SynthesizeMouseMoveEvent() {
// In screen coordinate.
- gfx::Point mouse_location = EventMonitor::GetLastMouseLocation();
+ gfx::Point mouse_location =
+#if defined(USE_AURA)
+ GetNativeWindow()->env()->last_mouse_location();
+#else
+ display::Screen::GetScreen()->GetCursorScreenPoint();
+#endif
if (!GetWindowBoundsInScreen().Contains(mouse_location))
return;
@@ -998,6 +1003,10 @@ bool Widget::IsTranslucentWindowOpacitySupported() const {
return native_widget_->IsTranslucentWindowOpacitySupported();
}
+ui::GestureRecognizer* Widget::GetGestureRecognizer() {
+ return native_widget_->GetGestureRecognizer();
+}
+
void Widget::OnSizeConstraintsChanged() {
native_widget_->OnSizeConstraintsChanged();
if (non_client_view_)
@@ -1202,7 +1211,7 @@ void Widget::OnMouseEvent(ui::MouseEvent* event) {
// mouse-button is still down before attempting to do a capture.
if (root_view && root_view->OnMousePressed(*event) &&
widget_deletion_observer.IsWidgetAlive() && IsVisible() &&
- internal::NativeWidgetPrivate::IsMouseButtonDown() &&
+ native_widget_->IsMouseButtonDown() &&
current_capture == internal::NativeWidgetPrivate::GetGlobalCapture(
native_widget_->GetNativeView())) {
is_mouse_button_pressed_ = true;
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index 6862cfb45d0..2efbe5c4d89 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -34,9 +34,6 @@
#if defined(IsMinimized)
#undef IsMinimized
#endif
-#if defined(CreateWindow)
-#undef CreateWindow
-#endif
#endif
namespace base {
@@ -52,6 +49,7 @@ namespace ui {
class Accelerator;
class Compositor;
class DefaultThemeProvider;
+class GestureRecognizer;
class InputMethod;
class Layer;
class NativeTheme;
@@ -772,6 +770,10 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Whether the widget supports translucency.
bool IsTranslucentWindowOpacitySupported() const;
+ // Returns the gesture recognizer which can handle touch/gesture events on
+ // this.
+ ui::GestureRecognizer* GetGestureRecognizer();
+
// Called when the delegate's CanResize or CanMaximize changes.
void OnSizeConstraintsChanged();
@@ -891,7 +893,7 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
base::ObserverList<WidgetObserver> observers_;
- base::ObserverList<WidgetRemovalsObserver> removals_observers_;
+ base::ObserverList<WidgetRemovalsObserver>::Unchecked removals_observers_;
// Non-owned pointer to the Widget's delegate. If a NULL delegate is supplied
// to Init() a default WidgetDelegate is created.
diff --git a/chromium/ui/views/widget/widget_delegate.cc b/chromium/ui/views/widget/widget_delegate.cc
index f1a5004ec93..f87e90d76e4 100644
--- a/chromium/ui/views/widget/widget_delegate.cc
+++ b/chromium/ui/views/widget/widget_delegate.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/view.h"
#include "ui/views/views_delegate.h"
@@ -57,13 +57,13 @@ bool WidgetDelegate::CanMinimize() const {
}
int32_t WidgetDelegate::GetResizeBehavior() const {
- int32_t behavior = ui::mojom::kResizeBehaviorNone;
+ int32_t behavior = ws::mojom::kResizeBehaviorNone;
if (CanResize())
- behavior |= ui::mojom::kResizeBehaviorCanResize;
+ behavior |= ws::mojom::kResizeBehaviorCanResize;
if (CanMaximize())
- behavior |= ui::mojom::kResizeBehaviorCanMaximize;
+ behavior |= ws::mojom::kResizeBehaviorCanMaximize;
if (CanMinimize())
- behavior |= ui::mojom::kResizeBehaviorCanMinimize;
+ behavior |= ws::mojom::kResizeBehaviorCanMinimize;
return behavior;
}
diff --git a/chromium/ui/views/widget/widget_delegate.h b/chromium/ui/views/widget/widget_delegate.h
index c1cfaebc417..5e394416c1e 100644
--- a/chromium/ui/views/widget/widget_delegate.h
+++ b/chromium/ui/views/widget/widget_delegate.h
@@ -62,7 +62,7 @@ class VIEWS_EXPORT WidgetDelegate {
// Returns true if the window can be minimized.
virtual bool CanMinimize() const;
- // Returns a bitmask of ui::mojom::kResizeBehavior values.
+ // Returns a bitmask of ws::mojom::kResizeBehavior values.
virtual int32_t GetResizeBehavior() const;
// Returns true if the window can be activated.
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index 54744d6d8ed..ab1cd09214e 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -1341,10 +1341,6 @@ TEST_F(WidgetTestInteractive, InactiveWidgetDoesNotGrabActivation) {
// Test that window state is not changed after getting out of full screen.
TEST_F(WidgetTestInteractive, MAYBE_ExitFullscreenRestoreState) {
- // TODO(http://crbug.com/864618): Fails flakily in mus with ws2.
- if (IsMus())
- return;
-
Widget* toplevel = CreateTopLevelPlatformWidget();
toplevel->Show();
diff --git a/chromium/ui/views/widget/widget_observer.h b/chromium/ui/views/widget/widget_observer.h
index fc13afae682..aa3e17f2047 100644
--- a/chromium/ui/views/widget/widget_observer.h
+++ b/chromium/ui/views/widget/widget_observer.h
@@ -5,6 +5,7 @@
#ifndef UI_VIEWS_WIDGET_WIDGET_OBSERVER_H_
#define UI_VIEWS_WIDGET_WIDGET_OBSERVER_H_
+#include "base/observer_list_types.h"
#include "ui/views/views_export.h"
namespace gfx {
@@ -16,7 +17,7 @@ namespace views {
class Widget;
// Observers can listen to various events on the Widgets.
-class VIEWS_EXPORT WidgetObserver {
+class VIEWS_EXPORT WidgetObserver : public base::CheckedObserver {
public:
// The closing notification is sent immediately in response to (i.e. in the
// same call stack as) a request to close the Widget (via Close() or
@@ -46,7 +47,7 @@ class VIEWS_EXPORT WidgetObserver {
const gfx::Rect& new_bounds) {}
protected:
- virtual ~WidgetObserver() {}
+ ~WidgetObserver() override {}
};
} // namespace views
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index 3c77de47e4e..24c23336a45 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -20,7 +20,7 @@
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/native_widget_types.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/event_monitor.h"
#include "ui/views/test/native_widget_factory.h"
@@ -640,17 +640,8 @@ TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
class WidgetObserverTest : public WidgetTest, public WidgetObserver {
public:
- WidgetObserverTest()
- : active_(nullptr),
- widget_closed_(nullptr),
- widget_activated_(nullptr),
- widget_shown_(nullptr),
- widget_hidden_(nullptr),
- widget_bounds_changed_(nullptr),
- widget_to_close_on_hide_(nullptr) {
- }
-
- ~WidgetObserverTest() override {}
+ WidgetObserverTest() = default;
+ ~WidgetObserverTest() override = default;
// Set a widget to Close() the next time the Widget being observed is hidden.
void CloseOnNextHide(Widget* widget) {
@@ -721,16 +712,16 @@ class WidgetObserverTest : public WidgetTest, public WidgetObserver {
const Widget* widget_bounds_changed() const { return widget_bounds_changed_; }
private:
- Widget* active_;
+ Widget* active_ = nullptr;
- Widget* widget_closed_;
- Widget* widget_activated_;
- Widget* widget_deactivated_;
- Widget* widget_shown_;
- Widget* widget_hidden_;
- Widget* widget_bounds_changed_;
+ Widget* widget_closed_ = nullptr;
+ Widget* widget_activated_ = nullptr;
+ Widget* widget_deactivated_ = nullptr;
+ Widget* widget_shown_ = nullptr;
+ Widget* widget_hidden_ = nullptr;
+ Widget* widget_bounds_changed_ = nullptr;
- Widget* widget_to_close_on_hide_;
+ Widget* widget_to_close_on_hide_ = nullptr;
};
// This test appears to be flaky on Mac.
@@ -741,21 +732,14 @@ class WidgetObserverTest : public WidgetTest, public WidgetObserver {
#endif
TEST_F(WidgetObserverTest, MAYBE_ActivationChange) {
- // TODO(http://crbug.com/864800): Fails flakily in mus with ws2.
- if (IsMus())
- return;
-
- WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
WidgetAutoclosePtr toplevel1(NewWidget());
WidgetAutoclosePtr toplevel2(NewWidget());
toplevel1->Show();
toplevel2->Show();
-
reset();
toplevel1->Activate();
-
RunPendingMessages();
EXPECT_EQ(toplevel1.get(), widget_activated());
@@ -1947,7 +1931,8 @@ TEST_F(WidgetTest, DestroyedWithCaptureViaEventMonitor) {
widget->SetCapture(view_handler);
ClosingEventHandler monitor_handler(widget);
- auto monitor = EventMonitor::CreateApplicationMonitor(&monitor_handler);
+ auto monitor = EventMonitor::CreateApplicationMonitor(
+ &monitor_handler, widget->GetNativeWindow());
ui::test::EventGenerator generator(
IsMus() ? widget->GetNativeWindow() : GetContext(),
@@ -1959,6 +1944,29 @@ TEST_F(WidgetTest, DestroyedWithCaptureViaEventMonitor) {
EXPECT_TRUE(observer.widget_closed());
}
+// Widget used to destroy itself when OnNativeWidgetDestroyed is called.
+class TestNativeWidgetDestroyedWidget : public Widget {
+ public:
+ // Overridden from NativeWidgetDelegate:
+ void OnNativeWidgetDestroyed() override;
+};
+
+void TestNativeWidgetDestroyedWidget::OnNativeWidgetDestroyed() {
+ Widget::OnNativeWidgetDestroyed();
+ delete this;
+}
+
+// Verifies that widget destroyed itself in OnNativeWidgetDestroyed does not
+// crash in ASan.
+TEST_F(WidgetTest, WidgetDestroyedItselfDoesNotCrash) {
+ TestDesktopWidgetDelegate delegate(new TestNativeWidgetDestroyedWidget);
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ delegate.InitWidget(params);
+ delegate.GetWidget()->Show();
+ delegate.GetWidget()->CloseNow();
+}
+
// Verifies WindowClosing() is invoked correctly on the delegate when a Widget
// is closed.
TEST_F(WidgetTest, SingleWindowClosing) {
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index d5f442f71da..54eb0fcd0bf 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -31,6 +31,7 @@
#include "ui/base/ime/text_input_type.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/view_prop.h"
+#include "ui/base/win/hwnd_metrics.h"
#include "ui/base/win/internal_constants.h"
#include "ui/base/win/lock_state.h"
#include "ui/base/win/mouse_wheel_util.h"
@@ -615,52 +616,57 @@ void HWNDMessageHandler::StackAtTop() {
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
-void HWNDMessageHandler::Show() {
- if (IsWindow(hwnd())) {
- if (!(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_TRANSPARENT) &&
- !(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)) {
- ShowWindowWithState(ui::SHOW_STATE_NORMAL);
- } else {
- ShowWindowWithState(ui::SHOW_STATE_INACTIVE);
- }
- }
-}
-
-void HWNDMessageHandler::ShowWindowWithState(ui::WindowShowState show_state) {
- TRACE_EVENT0("views", "HWNDMessageHandler::ShowWindowWithState");
+void HWNDMessageHandler::Show(ui::WindowShowState show_state,
+ const gfx::Rect& pixel_restore_bounds) {
+ TRACE_EVENT0("views", "HWNDMessageHandler::Show");
DWORD native_show_state;
- switch (show_state) {
- case ui::SHOW_STATE_INACTIVE:
- native_show_state = SW_SHOWNOACTIVATE;
- break;
- case ui::SHOW_STATE_MAXIMIZED:
- native_show_state = SW_SHOWMAXIMIZED;
- break;
- case ui::SHOW_STATE_MINIMIZED:
- native_show_state = SW_SHOWMINIMIZED;
- break;
- case ui::SHOW_STATE_NORMAL:
- native_show_state = SW_SHOWNORMAL;
- break;
- case ui::SHOW_STATE_FULLSCREEN:
- native_show_state = SW_SHOWNORMAL;
- SetFullscreen(true);
- break;
- default:
- native_show_state = delegate_->GetInitialShowState();
- break;
- }
+ if (show_state == ui::SHOW_STATE_MAXIMIZED &&
+ !pixel_restore_bounds.IsEmpty()) {
+ WINDOWPLACEMENT placement = {0};
+ placement.length = sizeof(WINDOWPLACEMENT);
+ placement.showCmd = SW_SHOWMAXIMIZED;
+ placement.rcNormalPosition = pixel_restore_bounds.ToRECT();
+ SetWindowPlacement(hwnd(), &placement);
+ native_show_state = SW_SHOWMAXIMIZED;
+ } else {
+ switch (show_state) {
+ case ui::SHOW_STATE_INACTIVE:
+ native_show_state = SW_SHOWNOACTIVATE;
+ break;
+ case ui::SHOW_STATE_MAXIMIZED:
+ native_show_state = SW_SHOWMAXIMIZED;
+ break;
+ case ui::SHOW_STATE_MINIMIZED:
+ native_show_state = SW_SHOWMINIMIZED;
+ break;
+ case ui::SHOW_STATE_NORMAL:
+ if ((GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_TRANSPARENT) ||
+ (GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)) {
+ native_show_state = SW_SHOWNOACTIVATE;
+ } else {
+ native_show_state = SW_SHOWNORMAL;
+ }
+ break;
+ case ui::SHOW_STATE_FULLSCREEN:
+ native_show_state = SW_SHOWNORMAL;
+ SetFullscreen(true);
+ break;
+ default:
+ native_show_state = delegate_->GetInitialShowState();
+ break;
+ }
- ShowWindow(hwnd(), native_show_state);
- // When launched from certain programs like bash and Windows Live Messenger,
- // show_state is set to SW_HIDE, so we need to correct that condition. We
- // don't just change show_state to SW_SHOWNORMAL because MSDN says we must
- // always first call ShowWindow with the specified value from STARTUPINFO,
- // otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead,
- // we call ShowWindow again in this case.
- if (native_show_state == SW_HIDE) {
- native_show_state = SW_SHOWNORMAL;
ShowWindow(hwnd(), native_show_state);
+ // When launched from certain programs like bash and Windows Live
+ // Messenger, show_state is set to SW_HIDE, so we need to correct that
+ // condition. We don't just change show_state to SW_SHOWNORMAL because
+ // MSDN says we must always first call ShowWindow with the specified
+ // value from STARTUPINFO, otherwise all future ShowWindow calls will be
+ // ignored (!!#@@#!). Instead, we call ShowWindow again in this case.
+ if (native_show_state == SW_HIDE) {
+ native_show_state = SW_SHOWNORMAL;
+ ShowWindow(hwnd(), native_show_state);
+ }
}
// We need to explicitly activate the window if we've been shown with a state
@@ -675,19 +681,6 @@ void HWNDMessageHandler::ShowWindowWithState(ui::WindowShowState show_state) {
SetInitialFocus();
}
-void HWNDMessageHandler::ShowMaximizedWithBounds(const gfx::Rect& bounds) {
- WINDOWPLACEMENT placement = { 0 };
- placement.length = sizeof(WINDOWPLACEMENT);
- placement.showCmd = SW_SHOWMAXIMIZED;
- placement.rcNormalPosition = bounds.ToRECT();
- SetWindowPlacement(hwnd(), &placement);
-
- // We need to explicitly activate the window, because if we're opened from a
- // desktop shortcut while an existing window is already running it doesn't
- // seem to be enough to use SW_SHOWMAXIMIZED to activate the window.
- Activate();
-}
-
void HWNDMessageHandler::Hide() {
if (IsWindow(hwnd())) {
// NOTE: Be careful not to activate any windows here (for example, calling
@@ -1359,8 +1352,9 @@ void HWNDMessageHandler::ClientAreaSizeChanged() {
sent_window_size_changing_ = false;
}
-bool HWNDMessageHandler::GetClientAreaInsets(gfx::Insets* insets) const {
- if (delegate_->GetClientAreaInsets(insets))
+bool HWNDMessageHandler::GetClientAreaInsets(gfx::Insets* insets,
+ HMONITOR monitor) const {
+ if (delegate_->GetClientAreaInsets(insets, monitor))
return true;
DCHECK(insets->IsEmpty());
@@ -1372,11 +1366,11 @@ bool HWNDMessageHandler::GetClientAreaInsets(gfx::Insets* insets) const {
if (IsMaximized()) {
// Windows automatically adds a standard width border to all sides when a
// window is maximized.
- int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
+ int frame_thickness = ui::GetFrameThickness(monitor);
if (!delegate_->HasFrame())
- border_thickness -= 1;
- *insets = gfx::Insets(
- border_thickness, border_thickness, border_thickness, border_thickness);
+ frame_thickness -= 1;
+ *insets = gfx::Insets(frame_thickness, frame_thickness, frame_thickness,
+ frame_thickness);
return true;
}
@@ -1648,7 +1642,7 @@ LRESULT HWNDMessageHandler::OnDpiChanged(UINT msg,
dpi = display::win::GetDPIFromScalingFactor(scaling_factor);
} else {
dpi = LOWORD(w_param);
- scaling_factor = display::win::GetScalingFactorFromDPI(dpi_);
+ scaling_factor = display::win::GetScalingFactorFromDPI(dpi);
}
// The first WM_DPICHANGED originates from EnableChildWindowDpiMessage during
@@ -1997,16 +1991,36 @@ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
}
}
+ RECT* client_rect =
+ mode ? &(reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0])
+ : reinterpret_cast<RECT*>(l_param);
+
+ HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONULL);
+ if (!monitor) {
+ // We might end up here if the window was previously minimized and the
+ // user clicks on the taskbar button to restore it in the previous
+ // position. In that case WM_NCCALCSIZE is sent before the window
+ // coordinates are restored to their previous values, so our (left,top)
+ // would probably be (-32000,-32000) like all minimized windows. So the
+ // above MonitorFromWindow call fails, but if we check the window rect
+ // given with WM_NCCALCSIZE (which is our previous restored window
+ // position) we will get the correct monitor handle.
+ monitor = MonitorFromRect(client_rect, MONITOR_DEFAULTTONULL);
+ if (!monitor) {
+ // This is probably an extreme case that we won't hit, but if we don't
+ // intersect any monitor, let us not adjust the client rect since our
+ // window will not be visible anyway.
+ return 0;
+ }
+ }
+
gfx::Insets insets;
- bool got_insets = GetClientAreaInsets(&insets);
+ bool got_insets = GetClientAreaInsets(&insets, monitor);
if (!got_insets && !IsFullscreen() && !(mode && !delegate_->HasFrame())) {
SetMsgHandled(FALSE);
return 0;
}
- RECT* client_rect = mode ?
- &(reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0]) :
- reinterpret_cast<RECT*>(l_param);
client_rect->left += insets.left();
client_rect->top += insets.top();
client_rect->bottom -= insets.bottom();
@@ -2016,24 +2030,6 @@ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
// thickness of the auto-hide taskbar on each such edge, so the window isn't
// treated as a "fullscreen app", which would cause the taskbars to
// disappear.
- HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONULL);
- if (!monitor) {
- // We might end up here if the window was previously minimized and the
- // user clicks on the taskbar button to restore it in the previously
- // maximized position. In that case WM_NCCALCSIZE is sent before the
- // window coordinates are restored to their previous values, so our
- // (left,top) would probably be (-32000,-32000) like all minimized
- // windows. So the above MonitorFromWindow call fails, but if we check
- // the window rect given with WM_NCCALCSIZE (which is our previous
- // restored window position) we will get the correct monitor handle.
- monitor = MonitorFromRect(client_rect, MONITOR_DEFAULTTONULL);
- if (!monitor) {
- // This is probably an extreme case that we won't hit, but if we don't
- // intersect any monitor, let us not adjust the client rect since our
- // window will not be visible anyway.
- return 0;
- }
- }
const int autohide_edges = GetAppbarAutohideEdges(monitor);
if (autohide_edges & ViewsDelegate::EDGE_LEFT)
client_rect->left += kAutoHideTaskbarThicknessPx;
@@ -2611,7 +2607,7 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
// Windows automatically adds a standard width border to all sides when
// window is maximized. We should take this into account.
gfx::Insets client_area_insets;
- if (GetClientAreaInsets(&client_area_insets))
+ if (GetClientAreaInsets(&client_area_insets, monitor))
expected_maximized_bounds.Inset(client_area_insets.Scale(-1));
}
// Sometimes Windows incorrectly changes bounds of maximized windows after
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index 91afedec8e2..593c3c0e95b 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -107,9 +107,10 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
void StackAbove(HWND other_hwnd);
void StackAtTop();
- void Show();
- void ShowWindowWithState(ui::WindowShowState show_state);
- void ShowMaximizedWithBounds(const gfx::Rect& bounds);
+ // Shows the window. If |show_state| is maximized, |pixel_restore_bounds| is
+ // the bounds to restore the window to when going back to normal.
+ void Show(ui::WindowShowState show_state,
+ const gfx::Rect& pixel_restore_bounds);
void Hide();
void Maximize();
@@ -270,9 +271,14 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// or subsequently.
void ClientAreaSizeChanged();
- // Returns the insets of the client area relative to the non-client area of
- // the window.
- bool GetClientAreaInsets(gfx::Insets* insets) const;
+ // Returns true if |insets| was modified to define a custom client area for
+ // the window, false if the default client area should be used. If false is
+ // returned, |insets| is not modified. |monitor| is the monitor this
+ // window is on. Normally that would be determined from the HWND, but
+ // during WM_NCCALCSIZE Windows does not return the correct monitor for the
+ // HWND, so it must be passed in explicitly (see HWNDMessageHandler::
+ // OnNCCalcSize for more details).
+ bool GetClientAreaInsets(gfx::Insets* insets, HMONITOR monitor) const;
// Resets the window region for the current widget bounds if necessary.
// If |force| is true, the window region is reset to NULL even for native
diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h
index 1b2d98a8573..b3f670dddf8 100644
--- a/chromium/ui/views/win/hwnd_message_handler_delegate.h
+++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h
@@ -87,8 +87,13 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// Returns true if the delegate modifies |insets| to define a custom client
// area for the window, false if the default client area should be used. If
- // false is returned, |insets| is not modified.
- virtual bool GetClientAreaInsets(gfx::Insets* insets) const = 0;
+ // false is returned, |insets| is not modified. |monitor| is the monitor
+ // this window is on. Normally that would be determined from the HWND, but
+ // during WM_NCCALCSIZE Windows does not return the correct monitor for the
+ // HWND, so it must be passed in explicitly (see HWNDMessageHandler::
+ // OnNCCalcSize for more details).
+ virtual bool GetClientAreaInsets(gfx::Insets* insets,
+ HMONITOR monitor) const = 0;
// Returns the minimum and maximum size the window can be resized to by the
// user.
diff --git a/chromium/ui/views/win/pen_event_processor.cc b/chromium/ui/views/win/pen_event_processor.cc
index b5e70938413..b820c51be5e 100644
--- a/chromium/ui/views/win/pen_event_processor.cc
+++ b/chromium/ui/views/win/pen_event_processor.cc
@@ -45,12 +45,12 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateEvent(
// have to check if previously the pointer type is an eraser.
if (pointer_pen_info.penFlags & PEN_FLAG_ERASER) {
input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
- DCHECK(eraser_pointer_id_ == -1 || eraser_pointer_id_ == mapped_pointer_id);
+ DCHECK(!eraser_pointer_id_ || *eraser_pointer_id_ == mapped_pointer_id);
eraser_pointer_id_ = mapped_pointer_id;
- } else if (eraser_pointer_id_ == mapped_pointer_id &&
+ } else if (eraser_pointer_id_ && *eraser_pointer_id_ == mapped_pointer_id &&
message == WM_POINTERUP) {
input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
- eraser_pointer_id_ = -1;
+ eraser_pointer_id_.reset();
}
// convert pressure into a float [0, 1]. The range of the pressure is
diff --git a/chromium/ui/views/win/pen_event_processor.h b/chromium/ui/views/win/pen_event_processor.h
index 87d949c01bf..ab10799c7be 100644
--- a/chromium/ui/views/win/pen_event_processor.h
+++ b/chromium/ui/views/win/pen_event_processor.h
@@ -9,6 +9,7 @@
#include <memory>
+#include "base/optional.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/sequential_id_generator.h"
@@ -54,7 +55,7 @@ class VIEWS_EXPORT PenEventProcessor {
bool send_touch_for_pen_ = false;
bool sent_mouse_down_ = false;
bool sent_touch_start_ = false;
- int eraser_pointer_id_ = -1;
+ base::Optional<unsigned int> eraser_pointer_id_;
DISALLOW_COPY_AND_ASSIGN(PenEventProcessor);
};
diff --git a/chromium/ui/views/win/windows_session_change_observer.cc b/chromium/ui/views/win/windows_session_change_observer.cc
index e2021dbcdc3..c2de1e1b3e4 100644
--- a/chromium/ui/views/win/windows_session_change_observer.cc
+++ b/chromium/ui/views/win/windows_session_change_observer.cc
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task/post_task.h"
#include "ui/gfx/win/singleton_hwnd.h"
#include "ui/gfx/win/singleton_hwnd_observer.h"
#include "ui/views/views_delegate.h"
@@ -98,7 +98,8 @@ class WindowsSessionChangeObserver::WtsRegistrationNotificationManager {
observer.ClearCallback();
}
- base::ObserverList<WindowsSessionChangeObserver, true> observer_list_;
+ base::ObserverList<WindowsSessionChangeObserver, true>::Unchecked
+ observer_list_;
std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
DISALLOW_COPY_AND_ASSIGN(WtsRegistrationNotificationManager);
diff --git a/chromium/ui/views/window/custom_frame_view.cc b/chromium/ui/views/window/custom_frame_view.cc
index 22d0bed6be8..0ae8ebd9ad3 100644
--- a/chromium/ui/views/window/custom_frame_view.cc
+++ b/chromium/ui/views/window/custom_frame_view.cc
@@ -197,8 +197,12 @@ void CustomFrameView::UpdateWindowIcon() {
}
void CustomFrameView::UpdateWindowTitle() {
- if (frame_->widget_delegate()->ShouldShowWindowTitle())
+ if (frame_->widget_delegate()->ShouldShowWindowTitle() &&
+ // If this is still unset, we haven't laid out window controls yet.
+ maximum_title_bar_x_ > -1) {
+ LayoutTitleBar();
SchedulePaintInRect(title_bounds_);
+ }
}
void CustomFrameView::SizeConstraintsChanged() {
diff --git a/chromium/ui/views/window/dialog_delegate.h b/chromium/ui/views/window/dialog_delegate.h
index 83019bb77d9..bbba8b1be6e 100644
--- a/chromium/ui/views/window/dialog_delegate.h
+++ b/chromium/ui/views/window/dialog_delegate.h
@@ -145,7 +145,7 @@ class VIEWS_EXPORT DialogDelegate : public ui::DialogModel,
base::TimeTicks creation_time_;
// Observers for DialogModel changes.
- base::ObserverList<DialogObserver> observer_list_;
+ base::ObserverList<DialogObserver>::Unchecked observer_list_;
DISALLOW_COPY_AND_ASSIGN(DialogDelegate);
};
diff --git a/chromium/ui/views/window/dialog_delegate_unittest.cc b/chromium/ui/views/window/dialog_delegate_unittest.cc
index bb2b8d54a35..5fd4c862b0e 100644
--- a/chromium/ui/views/window/dialog_delegate_unittest.cc
+++ b/chromium/ui/views/window/dialog_delegate_unittest.cc
@@ -214,25 +214,23 @@ TEST_F(DialogTest, HitTest_HiddenTitle) {
// Ensure that BubbleFrameView hit-tests as expected when the title is hidden.
const NonClientView* view = dialog()->GetWidget()->non_client_view();
BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view());
- const int border = frame->bubble_border()->GetBorderThickness();
struct {
const int point;
const int hit;
} cases[] = {
- {border, HTSYSMENU},
- {border + 10, HTSYSMENU},
- {border + 20, HTNOWHERE},
- {border + 50, HTCLIENT /* Space is reserved for the close button. */},
- {border + 60, HTCLIENT},
+ {0, HTSYSMENU},
+ {10, HTSYSMENU},
+ {20, HTNOWHERE},
+ {50, HTCLIENT /* Space is reserved for the close button. */},
+ {60, HTCLIENT},
{1000, HTNOWHERE},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
- << " case " << i << " with border: " << border << ", at point "
- << cases[i].point;
+ << " case " << i << " at point " << cases[i].point;
}
}
@@ -243,22 +241,19 @@ TEST_F(DialogTest, HitTest_HiddenTitleNoCloseButton) {
const NonClientView* view = dialog()->GetWidget()->non_client_view();
BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view());
- const int border = frame->bubble_border()->GetBorderThickness();
struct {
const int point;
const int hit;
} cases[] = {
- {border, HTSYSMENU}, {border + 10, HTSYSMENU},
- {border + 20, HTCLIENT}, {border + 50, HTCLIENT},
- {border + 60, HTCLIENT}, {1000, HTNOWHERE},
+ {0, HTSYSMENU}, {10, HTSYSMENU}, {20, HTCLIENT},
+ {50, HTCLIENT}, {60, HTCLIENT}, {1000, HTNOWHERE},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
- << " case " << i << " with border: " << border << ", at point "
- << cases[i].point;
+ << " case " << i << " at point " << cases[i].point;
}
}
@@ -268,24 +263,19 @@ TEST_F(DialogTest, HitTest_WithTitle) {
dialog()->set_title(base::ASCIIToUTF16("Title"));
dialog()->GetWidget()->UpdateWindowTitle();
BubbleFrameView* frame = static_cast<BubbleFrameView*>(view->frame_view());
- const int border = frame->bubble_border()->GetBorderThickness();
struct {
const int point;
const int hit;
} cases[] = {
- { border, HTSYSMENU },
- { border + 10, HTSYSMENU },
- { border + 20, HTCAPTION },
- { border + 50, HTCLIENT },
- { border + 60, HTCLIENT },
- { 1000, HTNOWHERE },
+ {0, HTSYSMENU}, {10, HTSYSMENU}, {20, HTCAPTION},
+ {50, HTCLIENT}, {60, HTCLIENT}, {1000, HTNOWHERE},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
gfx::Point point(cases[i].point, cases[i].point);
EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
- << " with border: " << border << ", at point " << cases[i].point;
+ << " at point " << cases[i].point;
}
}
diff --git a/chromium/ui/views/window/hit_test_utils.cc b/chromium/ui/views/window/hit_test_utils.cc
new file mode 100644
index 00000000000..30d8e45eb8c
--- /dev/null
+++ b/chromium/ui/views/window/hit_test_utils.cc
@@ -0,0 +1,38 @@
+// Copyright 2018 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/window/hit_test_utils.h"
+
+#include "ui/base/hit_test.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/views/view.h"
+#include "ui/views/view_properties.h"
+
+namespace views {
+
+int GetHitTestComponent(View* view, const gfx::Point& point_in_widget) {
+ gfx::Point point_in_view(point_in_widget);
+ View::ConvertPointFromWidget(view, &point_in_view);
+
+ if (!view->GetLocalBounds().Contains(point_in_view))
+ return HTNOWHERE;
+
+ View* target_view = view->GetEventHandlerForPoint(point_in_view);
+ while (target_view) {
+ int component = target_view->GetProperty(kHitTestComponentKey);
+ if (component != HTNOWHERE)
+ return component;
+ if (target_view == view)
+ break;
+ target_view = target_view->parent();
+ }
+
+ return HTNOWHERE;
+}
+
+void SetHitTestComponent(View* view, int hit_test_id) {
+ view->SetProperty(kHitTestComponentKey, hit_test_id);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/window/hit_test_utils.h b/chromium/ui/views/window/hit_test_utils.h
new file mode 100644
index 00000000000..3709e185151
--- /dev/null
+++ b/chromium/ui/views/window/hit_test_utils.h
@@ -0,0 +1,29 @@
+// Copyright 2018 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_WINDOW_HIT_TEST_UTILS_H_
+#define UI_VIEWS_WINDOW_HIT_TEST_UTILS_H_
+
+#include "ui/views/views_export.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+
+class View;
+
+// Returns the inner most non-HTNOWHERE |kHitTestComponentKey| value at
+// |point_in_widget| within the hierarchy of |view|, otherwise returns
+// HTNOWHERE.
+VIEWS_EXPORT int GetHitTestComponent(View* view,
+ const gfx::Point& point_in_widget);
+
+// Sets the |kHitTestComponentKey| property of |view|.
+VIEWS_EXPORT void SetHitTestComponent(View* view, int hit_test_id);
+
+} // namespace views
+
+#endif // UI_VIEWS_WINDOW_HIT_TEST_UTILS_H_
diff --git a/chromium/ui/views/window/hit_test_utils_unittest.cc b/chromium/ui/views/window/hit_test_utils_unittest.cc
new file mode 100644
index 00000000000..a2f2f9ab53a
--- /dev/null
+++ b/chromium/ui/views/window/hit_test_utils_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright 2018 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/window/hit_test_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/hit_test.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/view_properties.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+using GetHitTestComponentTest = ViewsTestBase;
+
+TEST_F(GetHitTestComponentTest, BasicTests) {
+ Widget* widget = new Widget;
+ widget->Init(CreateParams(Widget::InitParams::TYPE_WINDOW));
+
+ // Testing arrangement diagram:
+ // *=============root:HTCLIENT=============*
+ // | *=left:HTLEFT=* *=nowhere:HTNOWHERE=* |
+ // | | | | *=right:HTRIGHT=* | |
+ // | | | | | | | |
+ // | | | | *===============* | |
+ // | *=============* *===================* |
+ // *=======================================*
+ View* root = widget->GetRootView();
+ root->SetProperty(views::kHitTestComponentKey, static_cast<int>(HTCLIENT));
+ root->SetBounds(0, 0, 100, 100);
+
+ View* left = new View;
+ left->SetProperty(views::kHitTestComponentKey, static_cast<int>(HTLEFT));
+ left->SetBounds(10, 10, 30, 80);
+ root->AddChildView(left);
+
+ View* nowhere = new View;
+ nowhere->SetBounds(60, 10, 30, 80);
+ root->AddChildView(nowhere);
+
+ View* right = new View;
+ right->SetProperty(views::kHitTestComponentKey, static_cast<int>(HTRIGHT));
+ right->SetBounds(10, 10, 10, 60);
+ nowhere->AddChildView(right);
+
+ // Hit the root view.
+ EXPECT_EQ(GetHitTestComponent(root, gfx::Point(50, 50)), HTCLIENT);
+
+ // Hit the left view.
+ EXPECT_EQ(GetHitTestComponent(root, gfx::Point(25, 50)), HTLEFT);
+
+ // Hit the nowhere view, should return the root view's value.
+ EXPECT_EQ(GetHitTestComponent(root, gfx::Point(65, 50)), HTCLIENT);
+
+ // Hit the right view.
+ EXPECT_EQ(GetHitTestComponent(root, gfx::Point(75, 50)), HTRIGHT);
+
+ // Hit outside the root view.
+ EXPECT_EQ(GetHitTestComponent(root, gfx::Point(200, 50)), HTNOWHERE);
+
+ widget->CloseNow();
+}
+
+} // namespace views