summaryrefslogtreecommitdiff
path: root/chromium/ui/views
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-12-10 16:19:40 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-12-10 16:01:50 +0000
commit51f6c2793adab2d864b3d2b360000ef8db1d3e92 (patch)
tree835b3b4446b012c75e80177cef9fbe6972cc7dbe /chromium/ui/views
parent6036726eb981b6c4b42047513b9d3f4ac865daac (diff)
downloadqtwebengine-chromium-51f6c2793adab2d864b3d2b360000ef8db1d3e92.tar.gz
BASELINE: Update Chromium to 71.0.3578.93
Change-Id: I6a32086c33670e1b033f8b10e6bf1fd4da1d105d Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/ui/views')
-rw-r--r--chromium/ui/views/BUILD.gn75
-rw-r--r--chromium/ui/views/DEPS2
-rw-r--r--chromium/ui/views/OWNERS3
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc40
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.h14
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.cc115
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.h60
-rw-r--r--chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc204
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc11
-rw-r--r--chromium/ui/views/accessibility/view_accessibility_utils.cc44
-rw-r--r--chromium/ui/views/accessibility/view_accessibility_utils.h29
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc48
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.h6
-rw-r--r--chromium/ui/views/accessible_pane_view.cc3
-rw-r--r--chromium/ui/views/accessible_pane_view_unittest.cc33
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc4
-rw-r--r--chromium/ui/views/animation/ink_drop_mask.cc16
-rw-r--r--chromium/ui/views/animation/ink_drop_mask.h21
-rw-r--r--chromium/ui/views/bubble/OWNERS1
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc31
-rw-r--r--chromium/ui/views/bubble/bubble_border.h3
-rw-r--r--chromium/ui/views/bubble/bubble_border_unittest.cc9
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.cc76
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.h19
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc62
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc21
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h11
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc31
-rw-r--r--chromium/ui/views/bubble/info_bubble.cc2
-rw-r--r--chromium/ui/views/bubble/tooltip_icon.cc2
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.cc496
-rw-r--r--chromium/ui/views/bubble/tray_bubble_view.h230
-rw-r--r--chromium/ui/views/cocoa/DEPS1
-rw-r--r--chromium/ui/views/cocoa/bridge_factory_host.cc35
-rw-r--r--chromium/ui/views/cocoa/bridge_factory_host.h47
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.h83
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view.mm1577
-rw-r--r--chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm118
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.h351
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget.mm1283
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host.h152
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.h228
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm500
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm4
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_owner.h44
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_unittest.mm198
-rw-r--r--chromium/ui/views/cocoa/cocoa_mouse_capture.h53
-rw-r--r--chromium/ui/views/cocoa/cocoa_mouse_capture.mm128
-rw-r--r--chromium/ui/views/cocoa/cocoa_mouse_capture_delegate.h31
-rw-r--r--chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm8
-rw-r--r--chromium/ui/views/cocoa/cocoa_window_move_loop.h53
-rw-r--r--chromium/ui/views/cocoa/cocoa_window_move_loop.mm127
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac.h29
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac.mm6
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm14
-rw-r--r--chromium/ui/views/cocoa/native_widget_mac_nswindow.h52
-rw-r--r--chromium/ui/views/cocoa/native_widget_mac_nswindow.mm337
-rw-r--r--chromium/ui/views/cocoa/tooltip_manager_mac.h15
-rw-r--r--chromium/ui/views/cocoa/tooltip_manager_mac.mm26
-rw-r--r--chromium/ui/views/cocoa/views_nswindow_delegate.h55
-rw-r--r--chromium/ui/views/cocoa/views_nswindow_delegate.mm210
-rw-r--r--chromium/ui/views/cocoa/views_scrollbar_bridge.h40
-rw-r--r--chromium/ui/views/cocoa/views_scrollbar_bridge.mm49
-rw-r--r--chromium/ui/views/cocoa/widget_owner_nswindow_adapter.h53
-rw-r--r--chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm166
-rw-r--r--chromium/ui/views/cocoa/window_touch_bar_delegate.h21
-rw-r--r--chromium/ui/views/color_chooser/color_chooser_view.cc4
-rw-r--r--chromium/ui/views/controls/animated_image_view.cc139
-rw-r--r--chromium/ui/views/controls/animated_image_view.h91
-rw-r--r--chromium/ui/views/controls/button/button.cc6
-rw-r--r--chromium/ui/views/controls/button/button.h3
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc5
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.cc3
-rw-r--r--chromium/ui/views/controls/button/label_button_unittest.cc3
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc10
-rw-r--r--chromium/ui/views/controls/button/radio_button.cc2
-rw-r--r--chromium/ui/views/controls/focus_ring.cc6
-rw-r--r--chromium/ui/views/controls/focus_ring.h3
-rw-r--r--chromium/ui/views/controls/image_view.cc133
-rw-r--r--chromium/ui/views/controls/image_view.h66
-rw-r--r--chromium/ui/views/controls/image_view_base.cc160
-rw-r--r--chromium/ui/views/controls/image_view_base.h94
-rw-r--r--chromium/ui/views/controls/image_view_unittest.cc19
-rw-r--r--chromium/ui/views/controls/label_unittest.cc9
-rw-r--r--chromium/ui/views/controls/menu/menu_closure_animation_mac.h21
-rw-r--r--chromium/ui/views/controls/menu/menu_closure_animation_mac.mm12
-rw-r--r--chromium/ui/views/controls/menu/menu_config.cc5
-rw-r--r--chromium/ui/views/controls/menu/menu_config_win.cc13
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc27
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc8
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc15
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view_unittest.cc7
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc18
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm20
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl.cc3
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.cc8
-rw-r--r--chromium/ui/views/controls/menu/submenu_view.h3
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc6
-rw-r--r--chromium/ui/views/controls/native/native_view_host.h4
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc15
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.h1
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.h26
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.mm142
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac_unittest.mm42
-rw-r--r--chromium/ui/views/controls/native/native_view_host_wrapper.h4
-rw-r--r--chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.h4
-rw-r--r--chromium/ui/views/controls/styled_label.cc49
-rw-r--r--chromium/ui/views/controls/styled_label.h1
-rw-r--r--chromium/ui/views/controls/styled_label_unittest.cc29
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc2
-rw-r--r--chromium/ui/views/controls/textfield/textfield.cc63
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h8
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc9
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc41
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu.h5
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_base.cc39
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_base.h7
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm2
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc8
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h1
-rw-r--r--chromium/ui/views/controls/webview/webview.cc25
-rw-r--r--chromium/ui/views/controls/webview/webview.h9
-rw-r--r--chromium/ui/views/corewm/tooltip_controller.cc8
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_unittest.cc6
-rw-r--r--chromium/ui/views/corewm/tooltip_win.cc56
-rw-r--r--chromium/ui/views/corewm/tooltip_win.h20
-rw-r--r--chromium/ui/views/event_utils.cc22
-rw-r--r--chromium/ui/views/event_utils.h28
-rw-r--r--chromium/ui/views/examples/BUILD.gn2
-rw-r--r--chromium/ui/views/examples/animated_image_view_example.cc143
-rw-r--r--chromium/ui/views/examples/animated_image_view_example.h29
-rw-r--r--chromium/ui/views/examples/examples_main.cc5
-rw-r--r--chromium/ui/views/examples/examples_window.cc16
-rw-r--r--chromium/ui/views/examples/examples_window.h7
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.cc5
-rw-r--r--chromium/ui/views/examples/examples_window_with_content.h2
-rw-r--r--chromium/ui/views/examples/examples_with_content_main_exe.cc12
-rw-r--r--chromium/ui/views/examples/menu_example.cc2
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc6
-rw-r--r--chromium/ui/views/focus/widget_focus_manager.cc54
-rw-r--r--chromium/ui/views/focus/widget_focus_manager.h13
-rw-r--r--chromium/ui/views/layout/box_layout.cc4
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.h4
-rw-r--r--chromium/ui/views/mus/ax_remote_host.cc46
-rw-r--r--chromium/ui/views/mus/ax_remote_host.h13
-rw-r--r--chromium/ui/views/mus/ax_remote_host_unittest.cc53
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.cc7
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.h6
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus_unittest.cc9
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.cc71
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.h1
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc45
-rw-r--r--chromium/ui/views/mus/drag_interactive_uitest.cc26
-rw-r--r--chromium/ui/views/mus/mus_client.cc4
-rw-r--r--chromium/ui/views/mus/mus_views_delegate.cc16
-rw-r--r--chromium/ui/views/mus/mus_views_delegate.h4
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.cc45
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.h6
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc15
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc38
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.h10
-rw-r--r--chromium/ui/views/painter.cc57
-rw-r--r--chromium/ui/views/painter.h9
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc101
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.h41
-rw-r--r--chromium/ui/views/view.cc18
-rw-r--r--chromium/ui/views/view.h1
-rw-r--r--chromium/ui/views/view_properties.cc3
-rw-r--r--chromium/ui/views/view_properties.h9
-rw-r--r--chromium/ui/views/views_delegate.cc28
-rw-r--r--chromium/ui/views/views_delegate.h19
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc5
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drop_target_win.cc2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc12
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc53
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_interactive_uitest.cc272
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc23
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h8
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc8
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_event_filter.cc44
-rw-r--r--chromium/ui/views/widget/desktop_aura/window_event_filter.h14
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc9
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc22
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h28
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm291
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm266
-rw-r--r--chromium/ui/views/widget/widget.cc6
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc15
-rw-r--r--chromium/ui/views/widget/widget_utils_mac.mm4
-rw-r--r--chromium/ui/views/widget/window_reorderer.cc5
-rw-r--r--chromium/ui/views/widget/window_reorderer_unittest.cc5
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc22
-rw-r--r--chromium/ui/views/win/pen_event_processor.cc11
-rw-r--r--chromium/ui/views/window/custom_frame_view.cc7
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc15
-rw-r--r--chromium/ui/views/window/dialog_client_view.h10
-rw-r--r--chromium/ui/views/window/dialog_client_view_unittest.cc25
205 files changed, 4410 insertions, 7241 deletions
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index 3265121c103..b7fa6d3073c 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -54,7 +54,13 @@ jumbo_component("views") {
all_dependent_configs = [ ":flags" ]
public = [
+ # TODO(ccameron): Move these sources to the views_bridge_mac component
+ "../views_bridge_mac/bridge_factory_impl.h",
+ "../views_bridge_mac/bridged_native_widget_impl.h",
+ "../views_bridge_mac/native_widget_mac_nswindow.h",
+ "../views_bridge_mac/window_touch_bar_delegate.h",
"accessibility/view_accessibility.h",
+ "accessibility/view_accessibility_utils.h",
"accessible_pane_view.h",
"animation/bounds_animator.h",
"animation/bounds_animator_observer.h",
@@ -84,13 +90,12 @@ jumbo_component("views") {
"bubble/info_bubble.h",
"bubble/tooltip_icon.h",
"button_drag_utils.h",
- "cocoa/bridged_native_widget.h",
- "cocoa/native_widget_mac_nswindow.h",
- "cocoa/window_touch_bar_delegate.h",
+ "cocoa/bridge_factory_host.h",
"color_chooser/color_chooser_listener.h",
"color_chooser/color_chooser_view.h",
"context_menu_controller.h",
"controls/animated_icon_view.h",
+ "controls/animated_image_view.h",
"controls/button/blue_button.h",
"controls/button/button.h",
"controls/button/checkbox.h",
@@ -108,6 +113,7 @@ jumbo_component("views") {
"controls/focus_ring.h",
"controls/focusable_border.h",
"controls/image_view.h",
+ "controls/image_view_base.h",
"controls/label.h",
"controls/link.h",
"controls/link_listener.h",
@@ -176,6 +182,7 @@ jumbo_component("views") {
"drag_utils.h",
"event_monitor.h",
"event_monitor_mac.h",
+ "event_utils.h",
"focus/external_focus_tracker.h",
"focus/focus_manager.h",
"focus/focus_manager_delegate.h",
@@ -256,7 +263,11 @@ jumbo_component("views") {
]
sources = [
+ # TODO(ccameron): Move these sources to the views_bridge_mac component
+ "../views_bridge_mac/bridged_native_widget_impl.mm",
+ "../views_bridge_mac/native_widget_mac_nswindow.mm",
"accessibility/view_accessibility.cc",
+ "accessibility/view_accessibility_utils.cc",
"accessible_pane_view.cc",
"animation/bounds_animator.cc",
"animation/flood_fill_ink_drop_ripple.cc",
@@ -281,10 +292,9 @@ jumbo_component("views") {
"bubble/info_bubble.cc",
"bubble/tooltip_icon.cc",
"button_drag_utils.cc",
- "cocoa/bridged_native_widget.mm",
- "cocoa/native_widget_mac_nswindow.mm",
"color_chooser/color_chooser_view.cc",
"controls/animated_icon_view.cc",
+ "controls/animated_image_view.cc",
"controls/button/blue_button.cc",
"controls/button/button.cc",
"controls/button/checkbox.cc",
@@ -300,6 +310,7 @@ jumbo_component("views") {
"controls/focus_ring.cc",
"controls/focusable_border.cc",
"controls/image_view.cc",
+ "controls/image_view_base.cc",
"controls/label.cc",
"controls/link.cc",
"controls/menu/display_change_listener_mac.cc",
@@ -362,6 +373,7 @@ jumbo_component("views") {
"drag_utils.cc",
"drag_utils_mac.mm",
"event_monitor_mac.mm",
+ "event_utils.cc",
"focus/external_focus_tracker.cc",
"focus/focus_manager.cc",
"focus/focus_manager_factory.cc",
@@ -434,28 +446,24 @@ jumbo_component("views") {
# 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",
+ # TODO(ccameron): Move these sources to the views_bridge_mac component
+ "../views_bridge_mac/bridge_factory_impl.mm",
+ "../views_bridge_mac/bridged_content_view.h",
+ "../views_bridge_mac/bridged_content_view.mm",
+ "../views_bridge_mac/bridged_content_view_touch_bar.mm",
+ "../views_bridge_mac/cocoa_window_move_loop.h",
+ "../views_bridge_mac/cocoa_window_move_loop.mm",
+ "../views_bridge_mac/views_nswindow_delegate.h",
+ "../views_bridge_mac/views_nswindow_delegate.mm",
+ "../views_bridge_mac/views_scrollbar_bridge.h",
+ "../views_bridge_mac/views_scrollbar_bridge.mm",
+ "cocoa/bridge_factory_host.cc",
"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",
@@ -477,6 +485,7 @@ jumbo_component("views") {
"//base:i18n",
"//base/third_party/dynamic_annotations",
"//cc/paint",
+ "//mojo/public/cpp/bindings",
"//services/ws/public/mojom",
"//skia",
"//third_party/icu",
@@ -506,7 +515,6 @@ jumbo_component("views") {
"//ui/gfx/animation",
"//ui/gfx/geometry",
"//ui/views/resources",
- "//ui/views_bridge_mac:mojo",
]
if (use_x11) {
@@ -588,11 +596,11 @@ jumbo_component("views") {
public += [
"accessibility/ax_aura_obj_cache.h",
"accessibility/ax_aura_obj_wrapper.h",
+ "accessibility/ax_root_obj_wrapper.h",
"accessibility/ax_tree_source_views.h",
"accessibility/ax_view_obj_wrapper.h",
"accessibility/ax_widget_obj_wrapper.h",
"accessibility/ax_window_obj_wrapper.h",
- "bubble/tray_bubble_view.h",
"controls/native/native_view_host_aura.h",
"corewm/cursor_height_provider_win.h",
"corewm/tooltip.h",
@@ -620,11 +628,11 @@ jumbo_component("views") {
sources += [
"accessibility/ax_aura_obj_cache.cc",
"accessibility/ax_aura_obj_wrapper.cc",
+ "accessibility/ax_root_obj_wrapper.cc",
"accessibility/ax_tree_source_views.cc",
"accessibility/ax_view_obj_wrapper.cc",
"accessibility/ax_widget_obj_wrapper.cc",
"accessibility/ax_window_obj_wrapper.cc",
- "bubble/tray_bubble_view.cc",
"controls/menu/display_change_listener_aura.cc",
"controls/menu/menu_pre_target_handler_aura.cc",
"controls/menu/menu_pre_target_handler_aura.h",
@@ -658,6 +666,7 @@ jumbo_component("views") {
"//services/ws/public/mojom",
"//ui/aura",
"//ui/platform_window",
+ "//ui/platform_window/platform_window_handler",
"//ui/touch_selection",
"//ui/wm",
"//ui/wm/public",
@@ -734,7 +743,9 @@ jumbo_component("views") {
"//components/crash/core/common",
"//ui/accelerated_widget_mac",
"//ui/events:dom_keycode_converter",
+ "//ui/views_bridge_mac",
]
+ public_deps += [ "//ui/views_bridge_mac:mojo" ]
libs = [
"AppKit.framework",
"CoreGraphics.framework",
@@ -1111,7 +1122,10 @@ source_set("views_unittests_sources") {
if (is_mac) {
# views_unittests not yet compiling on Mac. http://crbug.com/378134
sources -= [ "controls/native/native_view_host_unittest.cc" ]
- public_deps += [ "//ui/accelerated_widget_mac" ]
+ public_deps += [
+ "//ui/accelerated_widget_mac",
+ "//ui/views_bridge_mac:views_bridge_mac",
+ ]
}
}
@@ -1211,12 +1225,23 @@ source_set("views_interactive_ui_tests") {
"corewm/desktop_capture_controller_unittest.cc",
"widget/native_widget_aura_interactive_uitest.cc",
]
+
deps += [
"//ui/aura",
"//ui/aura:test_support",
"//ui/wm",
"//ui/wm/public",
]
+
+ if (!is_chromeos && ((is_linux && !use_x11) || is_fuchsia)) {
+ sources += [ "widget/desktop_aura/desktop_window_tree_host_platform_interactive_uitest.cc" ]
+ }
+
+ deps += [
+ "//ui/events/platform",
+ "//ui/platform_window",
+ "//ui/platform_window/platform_window_handler",
+ ]
}
if (use_x11) {
diff --git a/chromium/ui/views/DEPS b/chromium/ui/views/DEPS
index f591ea6f71c..a2d0ab1f98c 100644
--- a/chromium/ui/views/DEPS
+++ b/chromium/ui/views/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+cc/paint",
"+components/crash/core/common/crash_key.h",
"+components/vector_icons",
+ "+mojo/public/cpp/bindings",
"+services/ws/public/mojom",
"+skia/ext",
"+third_party/iaccessible2",
@@ -20,6 +21,7 @@ include_rules = [
"+ui/resources/grit/ui_resources.h",
"+ui/strings/grit/ui_strings.h",
"+ui/touch_selection",
+ "+ui/views_bridge_mac",
"+ui/wm/core",
"+ui/wm/public",
diff --git a/chromium/ui/views/OWNERS b/chromium/ui/views/OWNERS
index 4aca57c69ca..57c9ed66f82 100644
--- a/chromium/ui/views/OWNERS
+++ b/chromium/ui/views/OWNERS
@@ -10,4 +10,7 @@ per-file *_mac.*=ellyjones@chromium.org
per-file *_cocoa.*=ellyjones@chromium.org
per-file *.mm=ellyjones@chromium.org
+# If you're doing structural changes get a review from one of the OWNERS.
+per-file BUILD.gn=*
+
# COMPONENT: Internals>Views
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
index 519d09c2959..5811bf26790 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -31,6 +31,9 @@ AXAuraObjCache* AXAuraObjCache::GetInstance() {
}
AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) {
+ // Avoid problems with transient focus events. https://crbug.com/729449
+ if (!view->GetWidget())
+ return nullptr;
return CreateInternal<AXViewObjWrapper>(view, view_to_id_map_);
}
@@ -122,24 +125,28 @@ AXAuraObjCache::~AXAuraObjCache() {
}
View* AXAuraObjCache::GetFocusedView() {
- if (root_windows_.empty())
- return nullptr;
- aura::client::FocusClient* focus_client =
- GetFocusClient(*root_windows_.begin());
- if (!focus_client)
- return nullptr;
-
- aura::Window* focused_window = focus_client->GetFocusedWindow();
- if (!focused_window)
- return nullptr;
-
- Widget* focused_widget = Widget::GetWidgetForNativeView(focused_window);
- while (!focused_widget) {
- focused_window = focused_window->parent();
+ Widget* focused_widget = focused_widget_for_testing_;
+ aura::Window* focused_window = nullptr;
+ if (!focused_widget) {
+ if (root_windows_.empty())
+ return nullptr;
+ aura::client::FocusClient* focus_client =
+ GetFocusClient(*root_windows_.begin());
+ if (!focus_client)
+ return nullptr;
+
+ focused_window = focus_client->GetFocusedWindow();
if (!focused_window)
- break;
+ return nullptr;
focused_widget = Widget::GetWidgetForNativeView(focused_window);
+ while (!focused_widget) {
+ focused_window = focused_window->parent();
+ if (!focused_window)
+ break;
+
+ focused_widget = Widget::GetWidgetForNativeView(focused_window);
+ }
}
if (!focused_widget)
@@ -153,7 +160,8 @@ View* AXAuraObjCache::GetFocusedView() {
if (focused_view)
return focused_view;
- if (focused_window->GetProperty(
+ if (focused_window &&
+ focused_window->GetProperty(
aura::client::kAccessibilityFocusFallsbackToWidgetKey)) {
// If focused widget has non client view, falls back to first child view of
// its client view. We don't expect that non client view gets keyboard
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.h b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
index f798bdb059e..3a4a448e0ed 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.h
@@ -45,8 +45,11 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
ax::mojom::Event event_type) = 0;
};
- // Get or create an entry in the cache based on an Aura view.
+ // Get or create an entry in the cache. May return null if the View is not
+ // associated with a Widget.
AXAuraObjWrapper* GetOrCreate(View* view);
+
+ // Get or create an entry in the cache.
AXAuraObjWrapper* GetOrCreate(Widget* widget);
AXAuraObjWrapper* GetOrCreate(aura::Window* window);
@@ -92,6 +95,13 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
+ // Changes the behavior of GetFocusedView() so that it only considers
+ // views within the given Widget, this enables making tests
+ // involving focus reliable.
+ void set_focused_widget_for_testing(views::Widget* widget) {
+ focused_widget_for_testing_ = widget;
+ }
+
private:
friend struct base::DefaultSingletonTraits<AXAuraObjCache>;
@@ -131,6 +141,8 @@ class VIEWS_EXPORT AXAuraObjCache : public aura::client::FocusChangeObserver {
std::set<aura::Window*> root_windows_;
+ views::Widget* focused_widget_for_testing_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(AXAuraObjCache);
};
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
new file mode 100644
index 00000000000..8f16302c7cb
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
@@ -0,0 +1,115 @@
+// 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/accessibility/ax_root_obj_wrapper.h"
+
+#include <utility>
+
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_window_obj_wrapper.h"
+
+AXRootObjWrapper::AXRootObjWrapper(views::AXAuraObjCache::Delegate* delegate)
+ : alert_window_(std::make_unique<aura::Window>(nullptr)),
+ delegate_(delegate) {
+ alert_window_->Init(ui::LAYER_NOT_DRAWN);
+#if !defined(IS_CHROMECAST)
+ aura::Env::GetInstance()->AddObserver(this);
+
+ if (display::Screen::GetScreen())
+ display::Screen::GetScreen()->AddObserver(this);
+#endif
+}
+
+AXRootObjWrapper::~AXRootObjWrapper() {
+#if !defined(IS_CHROMECAST)
+ if (display::Screen::GetScreen())
+ display::Screen::GetScreen()->RemoveObserver(this);
+
+ // If alert_window_ is nullptr already, that means OnWillDestroyEnv
+ // was already called, so we shouldn't call RemoveObserver(this) again.
+ if (!alert_window_)
+ return;
+
+ aura::Env::GetInstance()->RemoveObserver(this);
+#endif
+ alert_window_.reset();
+}
+
+views::AXAuraObjWrapper* AXRootObjWrapper::GetAlertForText(
+ const std::string& text) {
+ alert_window_->SetTitle(base::UTF8ToUTF16((text)));
+ views::AXWindowObjWrapper* window_obj =
+ static_cast<views::AXWindowObjWrapper*>(
+ views::AXAuraObjCache::GetInstance()->GetOrCreate(
+ alert_window_.get()));
+ window_obj->set_is_alert(true);
+ return window_obj;
+}
+
+bool AXRootObjWrapper::HasChild(views::AXAuraObjWrapper* child) {
+ std::vector<views::AXAuraObjWrapper*> children;
+ GetChildren(&children);
+ return base::ContainsValue(children, child);
+}
+
+bool AXRootObjWrapper::IsIgnored() {
+ return false;
+}
+
+views::AXAuraObjWrapper* AXRootObjWrapper::GetParent() {
+ return NULL;
+}
+
+void AXRootObjWrapper::GetChildren(
+ std::vector<views::AXAuraObjWrapper*>* out_children) {
+ views::AXAuraObjCache::GetInstance()->GetTopLevelWindows(out_children);
+ out_children->push_back(
+ views::AXAuraObjCache::GetInstance()->GetOrCreate(alert_window_.get()));
+}
+
+void AXRootObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
+ out_node_data->id = unique_id_.Get();
+ out_node_data->role = ax::mojom::Role::kDesktop;
+
+#if !defined(IS_CHROMECAST)
+ display::Screen* screen = display::Screen::GetScreen();
+ if (!screen)
+ return;
+
+ const display::Display& display = screen->GetPrimaryDisplay();
+
+ // Utilize the display bounds to figure out if this screen is in landscape or
+ // portrait. We use this rather than |rotation| because some devices default
+ // to landscape, some in portrait. Encode landscape as horizontal state,
+ // portrait as vertical state.
+ if (display.bounds().width() > display.bounds().height())
+ out_node_data->AddState(ax::mojom::State::kHorizontal);
+ else
+ out_node_data->AddState(ax::mojom::State::kVertical);
+#endif
+}
+
+const ui::AXUniqueId& AXRootObjWrapper::GetUniqueId() const {
+ return unique_id_;
+}
+
+void AXRootObjWrapper::OnDisplayMetricsChanged(const display::Display& display,
+ uint32_t changed_metrics) {
+ delegate_->OnEvent(this, ax::mojom::Event::kLocationChanged);
+}
+
+void AXRootObjWrapper::OnWindowInitialized(aura::Window* window) {}
+
+void AXRootObjWrapper::OnWillDestroyEnv() {
+ alert_window_.reset();
+ aura::Env::GetInstance()->RemoveObserver(this);
+}
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
new file mode 100644
index 00000000000..f90f9853dab
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
@@ -0,0 +1,60 @@
+// 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_ACCESSIBILITY_AX_ROOT_OBJ_WRAPPER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_ROOT_OBJ_WRAPPER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/accessibility/platform/ax_unique_id.h"
+#include "ui/aura/env_observer.h"
+#include "ui/display/display_observer.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+
+class VIEWS_EXPORT AXRootObjWrapper : public views::AXAuraObjWrapper,
+ display::DisplayObserver,
+ aura::EnvObserver {
+ public:
+ explicit AXRootObjWrapper(views::AXAuraObjCache::Delegate* delegate);
+ ~AXRootObjWrapper() override;
+
+ // Returns an AXAuraObjWrapper for an alert window with title set to |text|.
+ views::AXAuraObjWrapper* GetAlertForText(const std::string& text);
+
+ // Convenience method to check for existence of a child.
+ bool HasChild(views::AXAuraObjWrapper* child);
+
+ // views::AXAuraObjWrapper overrides.
+ bool IsIgnored() override;
+ views::AXAuraObjWrapper* GetParent() override;
+ void GetChildren(
+ std::vector<views::AXAuraObjWrapper*>* out_children) override;
+ void Serialize(ui::AXNodeData* out_node_data) override;
+ const ui::AXUniqueId& GetUniqueId() const override;
+
+ private:
+ // display::DisplayObserver:
+ void OnDisplayMetricsChanged(const display::Display& display,
+ uint32_t changed_metrics) override;
+
+ // aura::EnvObserver:
+ void OnWindowInitialized(aura::Window* window) override;
+ void OnWillDestroyEnv() override;
+
+ ui::AXUniqueId unique_id_;
+
+ std::unique_ptr<aura::Window> alert_window_;
+
+ views::AXAuraObjCache::Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXRootObjWrapper);
+};
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_ROOT_OBJ_WRAPPER_H_
diff --git a/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc b/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
index 84b893fca7f..aa9e497e6b1 100644
--- a/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
+++ b/chromium/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
@@ -21,6 +21,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/test/gl_surface_test_support.h"
+#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_test_api.h"
#include "ui/views/test/widget_test.h"
@@ -74,6 +75,132 @@ class AXSystemCaretWinTest : public test::WidgetTest {
DISALLOW_COPY_AND_ASSIGN(AXSystemCaretWinTest);
};
+class WinAccessibilityCaretEventMonitor {
+ public:
+ WinAccessibilityCaretEventMonitor(UINT event_min, UINT event_max);
+ ~WinAccessibilityCaretEventMonitor();
+
+ // Blocks until the next event is received. When it's received, it
+ // queries accessibility information about the object that fired the
+ // event and populates the event, hwnd, role, state, and name in the
+ // passed arguments.
+ void WaitForNextEvent(DWORD* out_event, UINT* out_role, UINT* out_state);
+
+ private:
+ void OnWinEventHook(HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time);
+
+ static void CALLBACK WinEventHookThunk(HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time);
+
+ struct EventInfo {
+ DWORD event;
+ HWND hwnd;
+ LONG obj_id;
+ LONG child_id;
+ };
+
+ base::circular_deque<EventInfo> event_queue_;
+ base::RunLoop loop_runner_;
+ HWINEVENTHOOK win_event_hook_handle_;
+ static WinAccessibilityCaretEventMonitor* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(WinAccessibilityCaretEventMonitor);
+};
+
+// static
+WinAccessibilityCaretEventMonitor*
+ WinAccessibilityCaretEventMonitor::instance_ = NULL;
+
+WinAccessibilityCaretEventMonitor::WinAccessibilityCaretEventMonitor(
+ UINT event_min,
+ UINT event_max) {
+ CHECK(!instance_) << "There can be only one instance of"
+ << " WinAccessibilityCaretEventMonitor at a time.";
+ instance_ = this;
+ win_event_hook_handle_ =
+ SetWinEventHook(event_min, event_max, NULL,
+ &WinAccessibilityCaretEventMonitor::WinEventHookThunk,
+ GetCurrentProcessId(),
+ 0, // Hook all threads
+ WINEVENT_OUTOFCONTEXT);
+}
+
+WinAccessibilityCaretEventMonitor::~WinAccessibilityCaretEventMonitor() {
+ UnhookWinEvent(win_event_hook_handle_);
+ instance_ = NULL;
+}
+
+void WinAccessibilityCaretEventMonitor::WaitForNextEvent(DWORD* out_event,
+ UINT* out_role,
+ UINT* out_state) {
+ if (event_queue_.empty())
+ loop_runner_.Run();
+
+ EventInfo event_info = event_queue_.front();
+ event_queue_.pop_front();
+
+ *out_event = event_info.event;
+
+ Microsoft::WRL::ComPtr<IAccessible> acc_obj;
+ base::win::ScopedVariant child_variant;
+ CHECK(S_OK == AccessibleObjectFromEvent(
+ event_info.hwnd, event_info.obj_id, event_info.child_id,
+ acc_obj.GetAddressOf(), child_variant.Receive()));
+
+ base::win::ScopedVariant role_variant;
+ if (S_OK == acc_obj->get_accRole(child_variant, role_variant.Receive()))
+ *out_role = V_I4(role_variant.ptr());
+ else
+ *out_role = 0;
+
+ base::win::ScopedVariant state_variant;
+ if (S_OK == acc_obj->get_accState(child_variant, state_variant.Receive()))
+ *out_state = V_I4(state_variant.ptr());
+ else
+ *out_state = 0;
+}
+
+void WinAccessibilityCaretEventMonitor::OnWinEventHook(HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time) {
+ EventInfo event_info;
+ event_info.event = event;
+ event_info.hwnd = hwnd;
+ event_info.obj_id = obj_id;
+ event_info.child_id = child_id;
+ event_queue_.push_back(event_info);
+ loop_runner_.Quit();
+}
+
+// static
+void CALLBACK
+WinAccessibilityCaretEventMonitor::WinEventHookThunk(HWINEVENTHOOK handle,
+ DWORD event,
+ HWND hwnd,
+ LONG obj_id,
+ LONG child_id,
+ DWORD event_thread,
+ DWORD event_time) {
+ if (instance_ && obj_id == OBJID_CARET) {
+ instance_->OnWinEventHook(handle, event, hwnd, obj_id, child_id,
+ event_thread, event_time);
+ }
+}
} // namespace
TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) {
@@ -183,4 +310,81 @@ TEST_F(AXSystemCaretWinTest, DISABLED_TestMovingWindow) {
EXPECT_EQ(height, height3);
}
+TEST_F(AXSystemCaretWinTest, DISABLED_TestCaretMSAAEvents) {
+ TextfieldTestApi textfield_test_api(textfield_);
+ Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
+ gfx::NativeWindow native_window = widget_->GetNativeWindow();
+ ASSERT_NE(nullptr, native_window);
+ HWND hwnd = native_window->GetHost()->GetAcceleratedWidget();
+ EXPECT_HRESULT_SUCCEEDED(AccessibleObjectFromWindow(
+ hwnd, static_cast<DWORD>(OBJID_CARET), IID_IAccessible,
+ reinterpret_cast<void**>(caret_accessible.GetAddressOf())));
+
+ DWORD event;
+ UINT role;
+ UINT state;
+
+ {
+ // Set caret to start of textfield.
+ WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+ EVENT_OBJECT_LOCATIONCHANGE);
+ textfield_test_api.ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT);
+ monitor.WaitForNextEvent(&event, &role, &state);
+ ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_LOCATIONCHANGE))
+ << "Event should be EVENT_OBJECT_LOCATIONCHANGE";
+ ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+ << "Role should be ROLE_SYSTEM_CARET";
+ ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0";
+ }
+
+ {
+ // Set caret to end of textfield.
+ WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+ EVENT_OBJECT_LOCATIONCHANGE);
+ textfield_test_api.ExecuteTextEditCommand(
+ ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT);
+ monitor.WaitForNextEvent(&event, &role, &state);
+ ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_LOCATIONCHANGE))
+ << "Event should be EVENT_OBJECT_LOCATIONCHANGE";
+ ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+ << "Role should be ROLE_SYSTEM_CARET";
+ ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0";
+ }
+
+ {
+ // Move focus to a button.
+ LabelButton button(nullptr, base::string16());
+ button.SetBounds(500, 0, 200, 20);
+ widget_->GetRootView()->AddChildView(&button);
+ test::WidgetActivationWaiter waiter(widget_, true);
+ WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+ EVENT_OBJECT_LOCATIONCHANGE);
+ widget_->Show();
+ waiter.Wait();
+ button.SetFocusBehavior(View::FocusBehavior::ALWAYS);
+ button.RequestFocus();
+ monitor.WaitForNextEvent(&event, &role, &state);
+ ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_HIDE))
+ << "Event should be EVENT_OBJECT_HIDE";
+ ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+ << "Role should be ROLE_SYSTEM_CARET";
+ ASSERT_EQ(state, static_cast<UINT>(STATE_SYSTEM_INVISIBLE))
+ << "State should be STATE_SYSTEM_INVISIBLE";
+ }
+
+ {
+ // Move focus back to the text field.
+ WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW,
+ EVENT_OBJECT_LOCATIONCHANGE);
+ textfield_->RequestFocus();
+ monitor.WaitForNextEvent(&event, &role, &state);
+ ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_SHOW))
+ << "Event should be EVENT_OBJECT_SHOW";
+ ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET))
+ << "Role should be ROLE_SYSTEM_CARET";
+ ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0";
+ }
+}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index b8ea4c3c754..cd77dabfd1b 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/aura/client/focus_client.h"
@@ -96,9 +97,9 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
if (!window_->IsVisible())
out_node_data->AddState(ax::mojom::State::kInvisible);
out_node_data->location = gfx::RectF(window_->GetBoundsInScreen());
- ui::AXTreeIDRegistry::AXTreeID child_ax_tree_id =
- window_->GetProperty(ui::kChildAXTreeID);
- if (child_ax_tree_id != ui::AXTreeIDRegistry::kNoAXTreeID) {
+ std::string* child_ax_tree_id_ptr = window_->GetProperty(ui::kChildAXTreeID);
+ if (child_ax_tree_id_ptr && ui::AXTreeID::FromString(*child_ax_tree_id_ptr) !=
+ ui::AXTreeIDUnknown()) {
// Most often, child AX trees are parented to Views. We need to handle
// the case where they're not here, but we don't want the same AX tree
// to be a child of two different parents.
@@ -110,8 +111,8 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
return;
}
- out_node_data->AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId,
- child_ax_tree_id);
+ out_node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+ *child_ax_tree_id_ptr);
}
}
diff --git a/chromium/ui/views/accessibility/view_accessibility_utils.cc b/chromium/ui/views/accessibility/view_accessibility_utils.cc
new file mode 100644
index 00000000000..9663921aec7
--- /dev/null
+++ b/chromium/ui/views/accessibility/view_accessibility_utils.cc
@@ -0,0 +1,44 @@
+// 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/accessibility/view_accessibility_utils.h"
+
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+
+// static
+Widget* ViewAccessibilityUtils::GetFocusedChildWidgetForAccessibility(
+ const View* view) {
+ const FocusManager* focus_manager = view->GetFocusManager();
+ if (!focus_manager)
+ return nullptr;
+ const View* focused_view = view->GetFocusManager()->GetFocusedView();
+ if (!focused_view)
+ return nullptr;
+
+ std::set<Widget*> child_widgets;
+ Widget::GetAllOwnedWidgets(view->GetWidget()->GetNativeView(),
+ &child_widgets);
+ for (auto iter = child_widgets.begin(); iter != child_widgets.end(); ++iter) {
+ Widget* child_widget = *iter;
+ DCHECK_NE(view->GetWidget(), child_widget);
+
+ if (IsFocusedChildWidget(child_widget, focused_view))
+ return child_widget;
+ }
+
+ return nullptr;
+}
+
+// static
+bool ViewAccessibilityUtils::IsFocusedChildWidget(Widget* widget,
+ const View* focused_view) {
+ return widget->IsVisible() &&
+ widget->GetContentsView()->Contains(focused_view);
+};
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/view_accessibility_utils.h b/chromium/ui/views/accessibility/view_accessibility_utils.h
new file mode 100644
index 00000000000..24c1a324b14
--- /dev/null
+++ b/chromium/ui/views/accessibility/view_accessibility_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_ACCESSIBILITY_VIEW_ACCESSIBILITY_UTILS_H_
+#define UI_VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_UTILS_H_
+
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+class VIEWS_EXPORT ViewAccessibilityUtils {
+ public:
+ // Returns a focused child widget if the view has a child that should be
+ // treated as a special case. For example, if a tab modal dialog is visible
+ // and focused, this will return the dialog when called on the BrowserView.
+ // This helper function is used to treat such widgets as separate windows for
+ // accessibility. Returns nullptr if no such widget is present.
+ static Widget* GetFocusedChildWidgetForAccessibility(const View* view);
+
+ // Used by GetFocusedChildWidgetForAccessibility to determine if a Widget
+ // should be handled separately.
+ static bool IsFocusedChildWidget(Widget* widget, const View* focused_view);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_UTILS_H_
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
index 10cc9408045..adc4575fd6e 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -9,12 +9,15 @@
#include "base/lazy_instance.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "ui/accessibility/ax_role_properties.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/accessibility/view_accessibility_utils.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
namespace views {
@@ -146,7 +149,7 @@ void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent(
OnMenuEnd();
break;
case ax::mojom::Event::kSelection:
- if (menu_depth_ && GetData().role == ax::mojom::Role::kMenuItem)
+ if (menu_depth_ && ui::IsMenuItem(GetData().role))
OnMenuItemActive();
break;
case ax::mojom::Event::kFocusContext: {
@@ -227,7 +230,12 @@ int ViewAXPlatformNodeDelegate::GetChildCount() {
int child_count = view()->child_count();
std::vector<Widget*> child_widgets;
- PopulateChildWidgetVector(&child_widgets);
+ bool is_tab_modal_showing;
+ PopulateChildWidgetVector(&child_widgets, &is_tab_modal_showing);
+ if (is_tab_modal_showing) {
+ DCHECK_EQ(child_widgets.size(), 1ULL);
+ return 1;
+ }
child_count += child_widgets.size();
return child_count;
@@ -239,7 +247,16 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::ChildAtIndex(int index) {
// If this is a root view, our widget might have child widgets. Include
std::vector<Widget*> child_widgets;
- PopulateChildWidgetVector(&child_widgets);
+ bool is_tab_modal_showing;
+ PopulateChildWidgetVector(&child_widgets, &is_tab_modal_showing);
+
+ // If a visible tab modal dialog is present, ignore |index| and return the
+ // dialog.
+ if (is_tab_modal_showing) {
+ DCHECK_EQ(child_widgets.size(), 1ULL);
+ return child_widgets[0]->GetRootView()->GetNativeViewAccessible();
+ }
+
int child_widget_count = static_cast<int>(child_widgets.size());
if (index < view()->child_count()) {
@@ -290,7 +307,8 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::HitTestSync(int x,
// Search child widgets first, since they're on top in the z-order.
std::vector<Widget*> child_widgets;
- PopulateChildWidgetVector(&child_widgets);
+ bool is_tab_modal_showing;
+ PopulateChildWidgetVector(&child_widgets, &is_tab_modal_showing);
for (Widget* child_widget : child_widgets) {
View* child_root_view = child_widget->GetRootView();
gfx::Point point(x, y);
@@ -358,13 +376,20 @@ const ui::AXUniqueId& ViewAXPlatformNodeDelegate::GetUniqueId() const {
}
void ViewAXPlatformNodeDelegate::PopulateChildWidgetVector(
- std::vector<Widget*>* result_child_widgets) {
+ std::vector<Widget*>* result_child_widgets,
+ bool* is_tab_modal_showing) {
// Only attach child widgets to the root view.
Widget* widget = view()->GetWidget();
// Note that during window close, a Widget may exist in a state where it has
// no NativeView, but hasn't yet torn down its view hierarchy.
- if (!widget || !widget->GetNativeView() || widget->GetRootView() != view())
+ if (!widget || !widget->GetNativeView() || widget->GetRootView() != view()) {
+ *is_tab_modal_showing = false;
return;
+ }
+
+ const views::FocusManager* focus_manager = view()->GetFocusManager();
+ const views::View* focused_view =
+ focus_manager ? focus_manager->GetFocusedView() : nullptr;
std::set<Widget*> child_widgets;
Widget::GetAllOwnedWidgets(widget->GetNativeView(), &child_widgets);
@@ -378,8 +403,19 @@ void ViewAXPlatformNodeDelegate::PopulateChildWidgetVector(
if (widget->GetNativeWindowProperty(kWidgetNativeViewHostKey))
continue;
+ // Focused child widgets should take the place of the web page they cover in
+ // the accessibility tree.
+ if (ViewAccessibilityUtils::IsFocusedChildWidget(child_widget,
+ focused_view)) {
+ result_child_widgets->clear();
+ result_child_widgets->push_back(child_widget);
+ *is_tab_modal_showing = true;
+ return;
+ }
+
result_child_widgets->push_back(child_widget);
}
+ *is_tab_modal_showing = false;
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
index f3829054acc..8dea736b61f 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
@@ -63,7 +63,11 @@ class VIEWS_EXPORT ViewAXPlatformNodeDelegate
explicit ViewAXPlatformNodeDelegate(View* view);
private:
- void PopulateChildWidgetVector(std::vector<Widget*>* result_child_widgets);
+ // |is_tab_modal_showing| is set to true if, instead of populating
+ // |result_child_widgets| normally, a single child widget was returned (e.g. a
+ // dialog that should be read instead of the rest of the page contents).
+ void PopulateChildWidgetVector(std::vector<Widget*>* result_child_widgets,
+ bool* is_tab_modal_showing);
void OnMenuItemActive();
void OnMenuStart();
diff --git a/chromium/ui/views/accessible_pane_view.cc b/chromium/ui/views/accessible_pane_view.cc
index cfd86c97ac1..a0b033b19fd 100644
--- a/chromium/ui/views/accessible_pane_view.cc
+++ b/chromium/ui/views/accessible_pane_view.cc
@@ -174,6 +174,9 @@ bool AccessiblePaneView::AcceleratorPressed(
case ui::VKEY_ESCAPE: {
RemovePaneFocus();
View* last_focused_view = last_focused_view_tracker_->view();
+ // Ignore |last_focused_view| if it's no longer in the same widget.
+ if (last_focused_view && GetWidget() != last_focused_view->GetWidget())
+ last_focused_view = nullptr;
if (last_focused_view) {
focus_manager_->SetFocusedViewWithReason(
last_focused_view, FocusManager::kReasonFocusRestore);
diff --git a/chromium/ui/views/accessible_pane_view_unittest.cc b/chromium/ui/views/accessible_pane_view_unittest.cc
index 7aef74a3bbe..f8e88ebfb46 100644
--- a/chromium/ui/views/accessible_pane_view_unittest.cc
+++ b/chromium/ui/views/accessible_pane_view_unittest.cc
@@ -206,7 +206,7 @@ TEST_F(AccessiblePaneViewTest, PaneFocusTraversal) {
EXPECT_TRUE(original_test_view->SetPaneFocus(
original_test_view->third_child_button()));
- // Test travesal in second view.
+ // Test traversal in second view.
// Set pane focus on second child.
EXPECT_TRUE(test_view->SetPaneFocus(test_view->second_child_button()));
// home
@@ -234,4 +234,35 @@ TEST_F(AccessiblePaneViewTest, PaneFocusTraversal) {
widget->CloseNow();
widget.reset();
}
+
+TEST_F(AccessiblePaneViewTest, DoesntCrashOnEscapeWithRemovedView) {
+ TestBarView* test_view1 = new TestBarView();
+ TestBarView* test_view2 = new TestBarView();
+ Widget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget.Init(params);
+ View* root = widget.GetRootView();
+ root->AddChildView(test_view1);
+ root->AddChildView(test_view2);
+ widget.Show();
+ widget.Activate();
+
+ View* v1 = test_view1->child_button();
+ View* v2 = test_view2->child_button();
+ // Do the following:
+ // 1. focus |v1|.
+ // 2. focus |v2|. This makes |test_view2| remember |v1| as having focus.
+ // 3. Removes |v1| from it's parent.
+ // 4. Presses escape on |test_view2|. Escape attempts to revert focus to |v1|
+ // (because of step 2). Because |v1| is not in a widget this should not
+ // attempt to focus anything.
+ EXPECT_TRUE(test_view1->SetPaneFocus(v1));
+ EXPECT_TRUE(test_view2->SetPaneFocus(v2));
+ v1->parent()->RemoveChildView(v1);
+ // This shouldn't hit a CHECK in the FocusManager.
+ EXPECT_TRUE(test_view2->AcceleratorPressed(test_view2->escape_key()));
+}
+
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index f21c750bd1f..b98691b786e 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -16,6 +16,7 @@
#include "ui/views/animation/ink_drop_stub.h"
#include "ui/views/animation/square_ink_drop_ripple.h"
#include "ui/views/style/platform_style.h"
+#include "ui/views/view_properties.h"
namespace views {
namespace {
@@ -170,6 +171,9 @@ std::unique_ptr<InkDropHighlight> InkDropHostView::CreateInkDropHighlight()
}
std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const {
+ if (gfx::Path* highlight_path = GetProperty(kHighlightPathKey))
+ return std::make_unique<views::PathInkDropMask>(size(), *highlight_path);
+
return nullptr;
}
diff --git a/chromium/ui/views/animation/ink_drop_mask.cc b/chromium/ui/views/animation/ink_drop_mask.cc
index a2d2adb366e..63c93c61b4a 100644
--- a/chromium/ui/views/animation/ink_drop_mask.cc
+++ b/chromium/ui/views/animation/ink_drop_mask.cc
@@ -75,4 +75,20 @@ void CircleInkDropMask::OnPaintLayer(const ui::PaintContext& context) {
recorder.canvas()->DrawCircle(mask_center_, mask_radius_, flags);
}
+// PathInkDropMask
+
+PathInkDropMask::PathInkDropMask(const gfx::Size& layer_size,
+ const gfx::Path& path)
+ : InkDropMask(layer_size), path_(path) {}
+
+void PathInkDropMask::OnPaintLayer(const ui::PaintContext& context) {
+ cc::PaintFlags flags;
+ flags.setAlpha(255);
+ flags.setStyle(cc::PaintFlags::kFill_Style);
+ flags.setAntiAlias(true);
+
+ ui::PaintRecorder recorder(context, layer()->size());
+ recorder.canvas()->DrawPath(path_, flags);
+}
+
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_mask.h b/chromium/ui/views/animation/ink_drop_mask.h
index debfb1604e2..1a3fa87e066 100644
--- a/chromium/ui/views/animation/ink_drop_mask.h
+++ b/chromium/ui/views/animation/ink_drop_mask.h
@@ -11,6 +11,7 @@
#include "ui/gfx/geometry/insets_f.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/path.h"
#include "ui/views/views_export.h"
namespace views {
@@ -33,7 +34,7 @@ class VIEWS_EXPORT InkDropMask : public ui::LayerDelegate {
explicit InkDropMask(const gfx::Size& layer_size);
private:
- // Overriden from ui::LayerDelegate:
+ // ui::LayerDelegate:
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override;
@@ -50,7 +51,7 @@ class VIEWS_EXPORT RoundRectInkDropMask : public InkDropMask {
float corner_radius);
private:
- // Overriden from InkDropMask:
+ // InkDropMask:
void OnPaintLayer(const ui::PaintContext& context) override;
gfx::InsetsF mask_insets_;
@@ -67,7 +68,7 @@ class VIEWS_EXPORT CircleInkDropMask : public InkDropMask {
int mask_radius);
private:
- // Overriden from InkDropMask:
+ // InkDropMask:
void OnPaintLayer(const ui::PaintContext& context) override;
gfx::Point mask_center_;
@@ -76,6 +77,20 @@ class VIEWS_EXPORT CircleInkDropMask : public InkDropMask {
DISALLOW_COPY_AND_ASSIGN(CircleInkDropMask);
};
+// An ink-drop mask that paints a specified path.
+class VIEWS_EXPORT PathInkDropMask : public InkDropMask {
+ public:
+ PathInkDropMask(const gfx::Size& layer_size, const gfx::Path& path);
+
+ private:
+ // InkDropMask:
+ void OnPaintLayer(const ui::PaintContext& context) override;
+
+ gfx::Path path_;
+
+ DISALLOW_COPY_AND_ASSIGN(PathInkDropMask);
+};
+
} // namespace views
#endif // UI_VIEWS_ANIMATION_INK_DROP_MASK_H_
diff --git a/chromium/ui/views/bubble/OWNERS b/chromium/ui/views/bubble/OWNERS
index f04407c0829..d17d1b2257c 100644
--- a/chromium/ui/views/bubble/OWNERS
+++ b/chromium/ui/views/bubble/OWNERS
@@ -1,4 +1,3 @@
msw@chromium.org
-per-file tray_bubble_view.*=stevenjb@chromium.org
# COMPONENT: UI>Browser>Bubbles
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index 9fc042cd02f..88e4653b928 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -14,6 +14,7 @@
#include "third_party/skia/include/core/SkPath.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/path.h"
#include "ui/gfx/scoped_canvas.h"
@@ -127,7 +128,8 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
}
// With NO_ASSETS, there should be further insets, but the same logic is
// used to position the bubble origin according to |anchor_rect|.
- DCHECK(shadow_ != NO_ASSETS || shadow_insets.IsEmpty());
+ DCHECK((shadow_ != NO_ASSETS && shadow_ != NO_SHADOW) ||
+ shadow_insets.IsEmpty());
contents_bounds.Inset(-shadow_insets);
// |arrow_offset_| is used to adjust bubbles that would normally be
// partially offscreen.
@@ -177,6 +179,9 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
if (shadow_ == NO_ASSETS)
return PaintNoAssets(view, canvas);
+ if (shadow_ == NO_SHADOW)
+ return PaintNoShadow(view, canvas);
+
gfx::ScopedCanvas scoped(canvas);
SkRRect r_rect = GetClientRect(view);
@@ -188,9 +193,11 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
}
gfx::Insets BubbleBorder::GetInsets() const {
- return (shadow_ == NO_ASSETS)
- ? gfx::Insets()
- : GetBorderAndShadowInsets(md_shadow_elevation_);
+ if (shadow_ == NO_ASSETS)
+ return gfx::Insets();
+ if (shadow_ == NO_SHADOW)
+ return gfx::Insets(kBorderThicknessDip);
+ return GetBorderAndShadowInsets(md_shadow_elevation_);
}
gfx::Size BubbleBorder::GetMinimumSize() const {
@@ -247,8 +254,8 @@ const cc::PaintFlags& BubbleBorder::GetBorderAndShadowFlags(
return flag_map->find(key)->second;
cc::PaintFlags flags;
- constexpr SkColor kBorderColor = SkColorSetA(SK_ColorBLACK, 0x26);
- flags.setColor(kBorderColor);
+ constexpr SkColor kBlurredBorderColor = SkColorSetA(SK_ColorBLACK, 0x26);
+ flags.setColor(kBlurredBorderColor);
flags.setAntiAlias(true);
flags.setLooper(
gfx::CreateShadowDrawLooper(GetShadowValues(elevation, color)));
@@ -280,6 +287,18 @@ void BubbleBorder::PaintNoAssets(const View& view, gfx::Canvas* canvas) {
canvas->sk_canvas()->drawColor(SK_ColorTRANSPARENT, SkBlendMode::kSrc);
}
+void BubbleBorder::PaintNoShadow(const View& view, gfx::Canvas* canvas) {
+ gfx::RectF bounds(view.GetLocalBounds());
+ bounds.Inset(gfx::InsetsF(kBorderThicknessDip / 2.0f));
+ cc::PaintFlags flags;
+ flags.setAntiAlias(true);
+ flags.setStyle(cc::PaintFlags::kStroke_Style);
+ flags.setStrokeWidth(kBorderThicknessDip);
+ constexpr SkColor kBorderColor = gfx::kGoogleGrey600;
+ flags.setColor(kBorderColor);
+ canvas->DrawRoundRect(bounds, GetBorderCornerRadius(), flags);
+}
+
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 d4a6e2a28a7..79c182cffd1 100644
--- a/chromium/ui/views/bubble/bubble_border.h
+++ b/chromium/ui/views/bubble/bubble_border.h
@@ -229,6 +229,9 @@ class VIEWS_EXPORT BubbleBorder : public Border {
// to make the window shape based on insets and GetBorderCornerRadius().
void PaintNoAssets(const View& view, gfx::Canvas* canvas);
+ // Paint for the NO_SHADOW shadow type. This paints a simple line border.
+ void PaintNoShadow(const View& view, gfx::Canvas* canvas);
+
Arrow arrow_;
int arrow_offset_;
// Corner radius for the bubble border. If supplied the border will use
diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc
index e1420089ab5..54476123fc1 100644
--- a/chromium/ui/views/bubble/bubble_border_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_border_unittest.cc
@@ -314,6 +314,9 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
const int kStrokeWidth =
shadow == BubbleBorder::NO_ASSETS ? 0 : BubbleBorder::kStroke;
+ const int kBorderedContentHeight =
+ kContentSize.height() + (2 * kStrokeWidth);
+
const int kTopHorizArrowY = kAnchor.bottom() + kStrokeWidth - kInsets.top();
const int kBottomHorizArrowY = kAnchor.y() - kTotalSize.height();
const int kLeftVertArrowX = kAnchor.x() + kAnchor.width();
@@ -338,9 +341,9 @@ TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
// Vertical arrow tests.
{BubbleBorder::LEFT_TOP, kLeftVertArrowX, kAnchor.y() + kStrokeWidth},
{BubbleBorder::LEFT_CENTER,
- kLeftVertArrowX - (kInsets.right() - kStrokeWidth),
- kAnchor.CenterPoint().y() - (kTotalSize.height() / 2) +
- (2 * kStrokeWidth)},
+ kLeftVertArrowX - (kInsets.left() - kStrokeWidth),
+ kAnchor.CenterPoint().y() - (kBorderedContentHeight / 2) -
+ (kInsets.top() - kStrokeWidth)},
{BubbleBorder::RIGHT_BOTTOM, kRightVertArrowX,
kAnchor.y() + kAnchor.height() - kTotalSize.height() - kStrokeWidth},
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
index 84d9ade9513..434ae1ea7db 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -17,7 +17,6 @@
#include "ui/views/layout/layout_manager.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/view_properties.h"
-#include "ui/views/view_tracker.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
@@ -51,17 +50,30 @@ class BubbleDialogFrameView : public BubbleFrameView {
DISALLOW_COPY_AND_ASSIGN(BubbleDialogFrameView);
};
+bool CustomShadowsSupported() {
+#if defined(OS_WIN)
+ return ui::win::IsAeroGlassEnabled();
+#else
+ return true;
+#endif
+}
+
// Create a widget to host the bubble.
Widget* CreateBubbleWidget(BubbleDialogDelegateView* bubble) {
Widget* bubble_widget = new Widget();
Widget::InitParams bubble_params(Widget::InitParams::TYPE_BUBBLE);
bubble_params.delegate = bubble;
- bubble_params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW;
+ bubble_params.opacity = CustomShadowsSupported()
+ ? Widget::InitParams::TRANSLUCENT_WINDOW
+ : Widget::InitParams::OPAQUE_WINDOW;
bubble_params.accept_events = bubble->accept_events();
// Use a window default shadow if the bubble doesn't provides its own.
- bubble_params.shadow_type = bubble->shadow() == BubbleBorder::NO_ASSETS
- ? Widget::InitParams::SHADOW_TYPE_DEFAULT
- : Widget::InitParams::SHADOW_TYPE_NONE;
+ if (bubble->GetShadow() == BubbleBorder::NO_ASSETS)
+ bubble_params.shadow_type = Widget::InitParams::SHADOW_TYPE_DEFAULT;
+ else if (CustomShadowsSupported())
+ bubble_params.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE;
+ else
+ bubble_params.shadow_type = Widget::InitParams::SHADOW_TYPE_DROP;
if (bubble->parent_window())
bubble_params.parent = bubble->parent_window();
else if (bubble->anchor_widget())
@@ -102,12 +114,7 @@ Widget* BubbleDialogDelegateView::CreateBubble(
bubble_delegate->SetAnchorView(bubble_delegate->GetAnchorView());
Widget* bubble_widget = CreateBubbleWidget(bubble_delegate);
-#if defined(OS_WIN)
- // If glass is enabled, the bubble is allowed to extend outside the bounds of
- // the parent frame and let DWM handle compositing. If not, then we don't
- // want to allow the bubble to extend the frame because it will be clipped.
- bubble_delegate->set_adjust_if_offscreen(ui::win::IsAeroGlassEnabled());
-#elif (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
+#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
// Linux clips bubble windows that extend outside their parent window bounds.
// Mac never adjusts.
bubble_delegate->set_adjust_if_offscreen(false);
@@ -145,7 +152,11 @@ NonClientFrameView* BubbleDialogDelegateView::CreateNonClientFrameView(
if (base::i18n::IsRTL() && mirror_arrow_in_rtl_)
adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow);
std::unique_ptr<BubbleBorder> border =
- std::make_unique<BubbleBorder>(adjusted_arrow, shadow(), color());
+ std::make_unique<BubbleBorder>(adjusted_arrow, GetShadow(), color());
+ // If custom shadows aren't supported we fall back to an OS provided square
+ // shadow.
+ if (!CustomShadowsSupported())
+ border->SetCornerRadius(0);
frame->SetBubbleBorder(std::move(border));
return frame;
}
@@ -198,16 +209,34 @@ void BubbleDialogDelegateView::OnWidgetBoundsChanged(
SizeToContents();
}
+BubbleBorder::Shadow BubbleDialogDelegateView::GetShadow() const {
+ if (CustomShadowsSupported() || shadow_ == BubbleBorder::NO_ASSETS)
+ return shadow_;
+ return BubbleBorder::NO_SHADOW;
+}
+
View* BubbleDialogDelegateView::GetAnchorView() const {
return anchor_view_tracker_->view();
}
-void BubbleDialogDelegateView::set_arrow(BubbleBorder::Arrow arrow) {
+void BubbleDialogDelegateView::SetHighlightedButton(
+ Button* highlighted_button) {
+ bool visible = GetWidget() && GetWidget()->IsVisible();
+ // If the Widget is visible, ensure the old highlight (if any) is removed
+ // when the highlighted view changes.
+ if (visible)
+ UpdateHighlightedButton(false);
+ highlighted_button_tracker_.SetView(highlighted_button);
+ if (visible)
+ UpdateHighlightedButton(true);
+}
+
+void BubbleDialogDelegateView::SetArrow(BubbleBorder::Arrow arrow) {
if (arrow_ == arrow)
return;
arrow_ = arrow;
- // If set_arrow() is called before CreateWidget(), there's no need to update
+ // If SetArrow() is called before CreateWidget(), there's no need to update
// the BubbleFrameView.
if (GetBubbleFrameView()) {
GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
@@ -321,8 +350,10 @@ void BubbleDialogDelegateView::SetAnchorView(View* anchor_view) {
// change as well.
if (!anchor_view || anchor_widget() != anchor_view->GetWidget()) {
if (anchor_widget()) {
- if (GetWidget() && GetWidget()->IsVisible())
+ if (GetWidget() && GetWidget()->IsVisible()) {
UpdateAnchorWidgetRenderState(false);
+ UpdateHighlightedButton(false);
+ }
anchor_widget_->RemoveObserver(this);
anchor_widget_ = NULL;
}
@@ -330,7 +361,9 @@ void BubbleDialogDelegateView::SetAnchorView(View* anchor_view) {
anchor_widget_ = anchor_view->GetWidget();
if (anchor_widget_) {
anchor_widget_->AddObserver(this);
- UpdateAnchorWidgetRenderState(GetWidget() && GetWidget()->IsVisible());
+ const bool visible = GetWidget() && GetWidget()->IsVisible();
+ UpdateAnchorWidgetRenderState(visible);
+ UpdateHighlightedButton(visible);
}
}
}
@@ -391,8 +424,10 @@ void BubbleDialogDelegateView::UpdateColorsFromTheme(
void BubbleDialogDelegateView::HandleVisibilityChanged(Widget* widget,
bool visible) {
- if (widget == GetWidget())
+ if (widget == GetWidget()) {
UpdateAnchorWidgetRenderState(visible);
+ UpdateHighlightedButton(visible);
+ }
// Fire ax::mojom::Event::kAlert for bubbles marked as
// ax::mojom::Role::kAlertDialog; this instructs accessibility tools to read
@@ -419,4 +454,11 @@ void BubbleDialogDelegateView::UpdateAnchorWidgetRenderState(bool visible) {
anchor_widget()->GetTopLevelWidget()->SetAlwaysRenderAsActive(visible);
}
+void BubbleDialogDelegateView::UpdateHighlightedButton(bool highlighted) {
+ Button* button = Button::AsButton(highlighted_button_tracker_.view());
+ button = button ? button : Button::AsButton(anchor_view_tracker_->view());
+ if (button)
+ button->SetHighlighted(highlighted);
+}
+
} // namespace views
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
index 51a95a0ab17..8d6561420c6 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/views/bubble/bubble_border.h"
+#include "ui/views/view_tracker.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_delegate.h"
@@ -27,7 +28,7 @@ class Rect;
namespace views {
class BubbleFrameView;
-class ViewTracker;
+class Button;
// BubbleDialogDelegateView is a special DialogDelegateView for bubbles.
class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
@@ -68,15 +69,17 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
View* GetAnchorView() const;
Widget* anchor_widget() const { return anchor_widget_; }
+ void SetHighlightedButton(Button* highlighted_button);
+
// The anchor rect is used in the absence of an assigned anchor view.
const gfx::Rect& anchor_rect() const { return anchor_rect_; }
BubbleBorder::Arrow arrow() const { return arrow_; }
- void set_arrow(BubbleBorder::Arrow arrow);
+ void SetArrow(BubbleBorder::Arrow arrow);
void set_mirror_arrow_in_rtl(bool mirror) { mirror_arrow_in_rtl_ = mirror; }
- BubbleBorder::Shadow shadow() const { return shadow_; }
+ BubbleBorder::Shadow GetShadow() const;
void set_shadow(BubbleBorder::Shadow shadow) { shadow_ = shadow; }
SkColor color() const { return color_; }
@@ -182,6 +185,11 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// When a bubble is visible, the anchor widget should always render as active.
void UpdateAnchorWidgetRenderState(bool visible);
+ // Update the button highlight, which may be the anchor view or an explicit
+ // view set in |highlighted_button_tracker_|. This can be overridden to
+ // provide different highlight effects.
+ virtual void UpdateHighlightedButton(bool highlighted);
+
// A flag controlling bubble closure on deactivation.
bool close_on_deactivate_;
@@ -191,6 +199,11 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
std::unique_ptr<ViewTracker> anchor_view_tracker_;
Widget* anchor_widget_;
+ // If provided, this button should be highlighted while the bubble is visible.
+ // If not provided, the anchor_view will attempt to be highlighted. A
+ // ViewTracker is used because the view can be deleted.
+ ViewTracker highlighted_button_tracker_;
+
// The anchor rect used in the absence of an anchor view.
mutable gfx::Rect anchor_rect_;
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
index 5de626a2bd4..cf205c20d3f 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -11,7 +11,10 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/base/hit_test.h"
#include "ui/events/event_utils.h"
+#include "ui/views/animation/test/ink_drop_host_view_test_api.h"
+#include "ui/views/animation/test/test_ink_drop.h"
#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/styled_label.h"
#include "ui/views/test/test_views.h"
@@ -22,6 +25,8 @@
namespace views {
+using test::TestInkDrop;
+
namespace {
constexpr int kContentHeight = 200;
@@ -362,6 +367,7 @@ TEST_F(BubbleDialogDelegateViewTest, CloseMethods) {
BubbleDialogDelegateView::CreateBubble(bubble_delegate);
bubble_widget->Show();
BubbleFrameView* frame_view = bubble_delegate->GetBubbleFrameView();
+ frame_view->ResetViewShownTimeStampForTesting();
Button* close_button = frame_view->close_;
ASSERT_TRUE(close_button);
frame_view->ButtonPressed(
@@ -477,6 +483,62 @@ TEST_F(BubbleDialogDelegateViewTest, StyledLabelTitle) {
bubble_widget->GetWindowBoundsInScreen().height());
}
+// Ensure associated buttons are highlighted or unhighlighted when the bubble
+// widget is shown or hidden respectively.
+TEST_F(BubbleDialogDelegateViewTest, AttachedWidgetShowsInkDropWhenVisible) {
+ std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
+ LabelButton* button = new LabelButton(nullptr, base::string16());
+ anchor_widget->GetContentsView()->AddChildView(button);
+ TestInkDrop* ink_drop = new TestInkDrop();
+ test::InkDropHostViewTestApi(button).SetInkDrop(base::WrapUnique(ink_drop));
+ TestBubbleDialogDelegateView* bubble_delegate =
+ new TestBubbleDialogDelegateView(nullptr);
+ bubble_delegate->set_parent_window(anchor_widget->GetNativeView());
+
+ Widget* bubble_widget =
+ BubbleDialogDelegateView::CreateBubble(bubble_delegate);
+ bubble_delegate->SetHighlightedButton(button);
+ bubble_widget->Show();
+ // Explicitly calling OnWidgetVisibilityChanging to test functionality for
+ // OS_WIN. Outside of the test environment this happens automatically by way
+ // of HWNDMessageHandler.
+ bubble_delegate->OnWidgetVisibilityChanging(bubble_widget, true);
+ EXPECT_EQ(InkDropState::ACTIVATED, ink_drop->GetTargetInkDropState());
+
+ bubble_widget->Close();
+ bubble_delegate->OnWidgetVisibilityChanging(bubble_widget, false);
+ EXPECT_EQ(InkDropState::DEACTIVATED, ink_drop->GetTargetInkDropState());
+}
+
+// Ensure associated buttons are highlighted or unhighlighted when the bubble
+// widget is shown or hidden respectively when highlighted button is set after
+// widget is shown.
+TEST_F(BubbleDialogDelegateViewTest, VisibleWidgetShowsInkDropOnAttaching) {
+ std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
+ LabelButton* button = new LabelButton(nullptr, base::string16());
+ anchor_widget->GetContentsView()->AddChildView(button);
+ TestInkDrop* ink_drop = new TestInkDrop();
+ test::InkDropHostViewTestApi(button).SetInkDrop(base::WrapUnique(ink_drop));
+ TestBubbleDialogDelegateView* bubble_delegate =
+ new TestBubbleDialogDelegateView(nullptr);
+ bubble_delegate->set_parent_window(anchor_widget->GetNativeView());
+
+ Widget* bubble_widget =
+ BubbleDialogDelegateView::CreateBubble(bubble_delegate);
+ bubble_widget->Show();
+ // Explicitly calling OnWidgetVisibilityChanging to test functionality for
+ // OS_WIN. Outside of the test environment this happens automatically by way
+ // of HWNDMessageHandler.
+ bubble_delegate->OnWidgetVisibilityChanging(bubble_widget, true);
+ EXPECT_EQ(InkDropState::HIDDEN, ink_drop->GetTargetInkDropState());
+ bubble_delegate->SetHighlightedButton(button);
+ EXPECT_EQ(InkDropState::ACTIVATED, ink_drop->GetTargetInkDropState());
+
+ bubble_widget->Close();
+ bubble_delegate->OnWidgetVisibilityChanging(bubble_widget, false);
+ EXPECT_EQ(InkDropState::DEACTIVATED, ink_drop->GetTargetInkDropState());
+}
+
TEST_F(BubbleDialogDelegateViewTest, VisibleAnchorChanges) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
TestBubbleDialogDelegateView* bubble_delegate =
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index f43e505afb4..02aa4a05ff8 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -28,10 +28,12 @@
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/image_view.h"
+#include "ui/views/event_utils.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/paint_info.h"
#include "ui/views/resources/grit/views_resources.h"
+#include "ui/views/view_properties.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
@@ -131,6 +133,11 @@ Button* BubbleFrameView::CreateCloseButton(ButtonListener* listener) {
close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
close_button->SizeToPreferredSize();
+ // Let the close button use a circular inkdrop shape.
+ auto highlight_path = std::make_unique<gfx::Path>();
+ highlight_path->addOval(gfx::RectToSkRect(gfx::Rect(close_button->size())));
+ close_button->SetProperty(kHighlightPathKey, highlight_path.release());
+
// Remove the close button from tab traversal on all platforms. Note this does
// not affect screen readers' ability to focus the close button. Keyboard
// access to the close button when not using a screen reader is done via the
@@ -407,6 +414,13 @@ void BubbleFrameView::ViewHierarchyChanged(
}
}
+void BubbleFrameView::VisibilityChanged(View* starting_from, bool is_visible) {
+ NonClientFrameView::VisibilityChanged(starting_from, is_visible);
+
+ if (is_visible)
+ view_shown_time_stamp_ = base::TimeTicks::Now();
+}
+
void BubbleFrameView::OnPaint(gfx::Canvas* canvas) {
OnPaintBackground(canvas);
// Border comes after children.
@@ -424,6 +438,9 @@ void BubbleFrameView::PaintChildren(const PaintInfo& paint_info) {
}
void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
+ if (IsPossiblyUnintendedInteraction(view_shown_time_stamp_, event))
+ return;
+
if (sender == close_) {
close_button_clicked_ = true;
GetWidget()->Close();
@@ -477,6 +494,10 @@ gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect,
return bubble_border_->GetBounds(anchor_rect, size);
}
+void BubbleFrameView::ResetViewShownTimeStampForTesting() {
+ view_shown_time_stamp_ = base::TimeTicks();
+}
+
gfx::Rect BubbleFrameView::GetAvailableScreenBounds(
const gfx::Rect& rect) const {
// The bubble attempts to fit within the current screen bounds.
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index eef3fda7a3e..bfb407a231f 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/time/time.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/controls/button/button.h"
@@ -65,6 +66,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) override;
+ void VisibilityChanged(View* starting_from, bool is_visible) override;
// ButtonListener:
void ButtonPressed(Button* sender, const ui::Event& event) override;
@@ -99,6 +101,11 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
Button* GetCloseButtonForTest() { return close_; }
+ // Resets the time when view has been shown. Tests may need to call this
+ // method if they use events that could be otherwise treated as unintended.
+ // See IsPossiblyUnintendedInteraction().
+ void ResetViewShownTimeStampForTesting();
+
protected:
// Returns the available screen bounds if the frame were to show in |rect|.
virtual gfx::Rect GetAvailableScreenBounds(const gfx::Rect& rect) const;
@@ -115,6 +122,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, GetBoundsForClientView);
FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, RemoveFootnoteView);
FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, LayoutWithIcon);
+ FRIEND_TEST_ALL_PREFIXES(BubbleFrameViewTest, IgnorePossiblyUnintendedClicks);
FRIEND_TEST_ALL_PREFIXES(BubbleDelegateTest, CloseReasons);
FRIEND_TEST_ALL_PREFIXES(BubbleDialogDelegateViewTest, CloseMethods);
@@ -180,6 +188,9 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
// Whether the close button was clicked.
bool close_button_clicked_;
+ // Time when view has been shown.
+ base::TimeTicks view_shown_time_stamp_;
+
DISALLOW_COPY_AND_ASSIGN(BubbleFrameView);
};
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index 0a060d2fbf5..38930c39de0 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -8,14 +8,19 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "build/build_config.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/event.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.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_view.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/metrics.h"
#include "ui/views/test/test_layout_provider.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/views_test_base.h"
@@ -84,7 +89,7 @@ class TestBubbleFrameView : public BubbleFrameView {
: BubbleFrameView(gfx::Insets(), gfx::Insets(kMargin)),
available_bounds_(gfx::Rect(0, 0, 1000, 1000)) {
SetBubbleBorder(std::make_unique<BubbleBorder>(
- kArrow, BubbleBorder::NO_SHADOW, kColor));
+ kArrow, BubbleBorder::BIG_SHADOW, kColor));
widget_ = std::make_unique<Widget>();
widget_delegate_ =
std::make_unique<TestBubbleFrameViewWidgetDelegate>(widget_.get());
@@ -751,4 +756,28 @@ TEST_F(BubbleFrameViewTest, NoElideTitle) {
EXPECT_EQ(title, title_label->GetDisplayTextForTesting());
}
+// Ensures that clicks are ignored for short time after view has been shown.
+TEST_F(BubbleFrameViewTest, IgnorePossiblyUnintendedClicks) {
+ TestBubbleDialogDelegateView delegate;
+ TestAnchor anchor(CreateParams(Widget::InitParams::TYPE_WINDOW));
+ delegate.SetAnchorView(anchor.widget().GetContentsView());
+ Widget* bubble = BubbleDialogDelegateView::CreateBubble(&delegate);
+ bubble->Show();
+
+ BubbleFrameView* frame = delegate.GetBubbleFrameView();
+ frame->ButtonPressed(
+ frame->close_,
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE));
+ EXPECT_FALSE(bubble->IsClosed());
+
+ frame->ButtonPressed(
+ frame->close_,
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow() + base::TimeDelta::FromMilliseconds(
+ GetDoubleClickInterval()),
+ ui::EF_NONE, ui::EF_NONE));
+ EXPECT_TRUE(bubble->IsClosed());
+}
+
} // namespace views
diff --git a/chromium/ui/views/bubble/info_bubble.cc b/chromium/ui/views/bubble/info_bubble.cc
index 65fc0411ece..442287d5d22 100644
--- a/chromium/ui/views/bubble/info_bubble.cc
+++ b/chromium/ui/views/bubble/info_bubble.cc
@@ -79,7 +79,7 @@ NonClientFrameView* InfoBubble::CreateNonClientFrameView(Widget* widget) {
frame_ = new InfoBubbleFrame(margins());
frame_->set_available_bounds(anchor_widget()->GetWindowBoundsInScreen());
frame_->SetBubbleBorder(std::unique_ptr<BubbleBorder>(
- new BubbleBorder(arrow(), shadow(), color())));
+ new BubbleBorder(arrow(), GetShadow(), color())));
return frame_;
}
diff --git a/chromium/ui/views/bubble/tooltip_icon.cc b/chromium/ui/views/bubble/tooltip_icon.cc
index 8e1969cd449..09be527d930 100644
--- a/chromium/ui/views/bubble/tooltip_icon.cc
+++ b/chromium/ui/views/bubble/tooltip_icon.cc
@@ -84,7 +84,7 @@ void TooltipIcon::ShowBubble() {
bubble_ = new InfoBubble(this, tooltip_);
bubble_->set_preferred_width(preferred_width_);
- bubble_->set_arrow(anchor_point_arrow_);
+ bubble_->SetArrow(anchor_point_arrow_);
// When shown due to a gesture event, close on deactivate (i.e. don't use
// "focusless").
bubble_->set_can_activate(!mouse_inside_);
diff --git a/chromium/ui/views/bubble/tray_bubble_view.cc b/chromium/ui/views/bubble/tray_bubble_view.cc
deleted file mode 100644
index 9e2994cfefd..00000000000
--- a/chromium/ui/views/bubble/tray_bubble_view.cc
+++ /dev/null
@@ -1,496 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/bubble/tray_bubble_view.h"
-
-#include <algorithm>
-
-#include "base/macros.h"
-#include "cc/paint/paint_flags.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_owner.h"
-#include "ui/events/event.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/bubble/bubble_frame_view.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/painter.h"
-#include "ui/views/views_delegate.h"
-#include "ui/views/widget/widget.h"
-#include "ui/wm/core/shadow_types.h"
-#include "ui/wm/core/window_util.h"
-
-namespace views {
-
-namespace {
-
-// The sampling time for mouse position changes in ms - which is roughly a frame
-// time.
-const int kFrameTimeInMS = 30;
-
-BubbleBorder::Arrow GetArrowAlignment(
- TrayBubbleView::AnchorAlignment alignment) {
- if (alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
- return base::i18n::IsRTL() ? BubbleBorder::BOTTOM_LEFT
- : BubbleBorder::BOTTOM_RIGHT;
- }
- if (alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT)
- return BubbleBorder::LEFT_BOTTOM;
- return BubbleBorder::RIGHT_BOTTOM;
-}
-
-// Only one TrayBubbleView is visible at a time, but there are cases where the
-// lifetimes of two different bubbles can overlap briefly.
-int g_current_tray_bubble_showing_count_ = 0;
-
-} // namespace
-
-namespace internal {
-
-// Detects any mouse movement. This is needed to detect mouse movements by the
-// user over the bubble if the bubble got created underneath the cursor.
-class MouseMoveDetectorHost : public MouseWatcherHost {
- public:
- MouseMoveDetectorHost();
- ~MouseMoveDetectorHost() override;
-
- bool Contains(const gfx::Point& screen_point, MouseEventType type) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MouseMoveDetectorHost);
-};
-
-MouseMoveDetectorHost::MouseMoveDetectorHost() {
-}
-
-MouseMoveDetectorHost::~MouseMoveDetectorHost() {
-}
-
-bool MouseMoveDetectorHost::Contains(const gfx::Point& screen_point,
- MouseEventType type) {
- return false;
-}
-
-// Custom layout for the bubble-view. Does the default box-layout if there is
-// enough height. Otherwise, makes sure the bottom rows are visible.
-class BottomAlignedBoxLayout : public BoxLayout {
- public:
- explicit BottomAlignedBoxLayout(TrayBubbleView* bubble_view)
- : BoxLayout(BoxLayout::kVertical), bubble_view_(bubble_view) {}
-
- ~BottomAlignedBoxLayout() override {}
-
- private:
- void Layout(View* host) override {
- if (host->height() >= host->GetPreferredSize().height() ||
- !bubble_view_->is_gesture_dragging()) {
- BoxLayout::Layout(host);
- return;
- }
-
- int consumed_height = 0;
- for (int i = host->child_count() - 1;
- i >= 0 && consumed_height < host->height(); --i) {
- View* child = host->child_at(i);
- if (!child->visible())
- continue;
- gfx::Size size = child->GetPreferredSize();
- child->SetBounds(0, host->height() - consumed_height - size.height(),
- host->width(), size.height());
- consumed_height += size.height();
- }
- }
-
- TrayBubbleView* bubble_view_;
-
- DISALLOW_COPY_AND_ASSIGN(BottomAlignedBoxLayout);
-};
-
-} // namespace internal
-
-using internal::BottomAlignedBoxLayout;
-
-TrayBubbleView::Delegate::~Delegate() {}
-
-void TrayBubbleView::Delegate::BubbleViewDestroyed() {}
-
-void TrayBubbleView::Delegate::OnMouseEnteredView() {}
-
-void TrayBubbleView::Delegate::OnMouseExitedView() {}
-
-base::string16 TrayBubbleView::Delegate::GetAccessibleNameForBubble() {
- return base::string16();
-}
-
-bool TrayBubbleView::Delegate::ShouldEnableExtraKeyboardAccessibility() {
- return false;
-}
-
-void TrayBubbleView::Delegate::HideBubble(const TrayBubbleView* bubble_view) {}
-
-void TrayBubbleView::Delegate::ProcessGestureEventForBubble(
- ui::GestureEvent* event) {}
-
-TrayBubbleView::InitParams::InitParams() = default;
-
-TrayBubbleView::InitParams::InitParams(const InitParams& other) = default;
-
-TrayBubbleView::RerouteEventHandler::RerouteEventHandler(
- TrayBubbleView* tray_bubble_view)
- : tray_bubble_view_(tray_bubble_view) {
- aura::Env::GetInstance()->AddPreTargetHandler(
- this, ui::EventTarget::Priority::kSystem);
-}
-
-TrayBubbleView::RerouteEventHandler::~RerouteEventHandler() {
- aura::Env::GetInstance()->RemovePreTargetHandler(this);
-}
-
-void TrayBubbleView::RerouteEventHandler::OnKeyEvent(ui::KeyEvent* event) {
- // Do not handle a key event if it is targeted to the tray or its descendants,
- // or if the target has the tray as a transient ancestor. RerouteEventHandler
- // is for rerouting events which are not targetted to the tray. Those events
- // should be handled by the target.
- aura::Window* target = static_cast<aura::Window*>(event->target());
- aura::Window* tray_window = tray_bubble_view_->GetWidget()->GetNativeView();
- if (target && (tray_window->Contains(target) ||
- wm::HasTransientAncestor(target, tray_window))) {
- return;
- }
-
- // Only passes Tab, Shift+Tab, Esc to the widget as it can consume more key
- // events. e.g. Alt+Tab can be consumed as focus traversal by FocusManager.
- ui::KeyboardCode key_code = event->key_code();
- int flags = event->flags();
- if ((key_code == ui::VKEY_TAB && flags == ui::EF_NONE) ||
- (key_code == ui::VKEY_TAB && flags == ui::EF_SHIFT_DOWN) ||
- (key_code == ui::VKEY_ESCAPE && flags == ui::EF_NONE)) {
- // Make TrayBubbleView activatable as the following Widget::OnKeyEvent might
- // try to activate it.
- tray_bubble_view_->set_can_activate(true);
-
- tray_bubble_view_->GetWidget()->OnKeyEvent(event);
-
- if (event->handled())
- return;
- }
-
- // Always consumes key event not to pass it to other widgets. Calling
- // StopPropagation here to make this consistent with
- // MenuController::OnWillDispatchKeyEvent.
- event->StopPropagation();
-
- // To provide consistent behavior with a menu, process accelerator as a menu
- // is open if the event is not handled by the widget.
- ui::Accelerator accelerator(*event);
- ViewsDelegate::ProcessMenuAcceleratorResult result =
- ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
- accelerator);
- if (result == ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU)
- tray_bubble_view_->CloseBubbleView();
-}
-
-TrayBubbleView::TrayBubbleView(const InitParams& init_params)
- : BubbleDialogDelegateView(init_params.anchor_view,
- GetArrowAlignment(init_params.anchor_alignment)),
- params_(init_params),
- layout_(nullptr),
- delegate_(init_params.delegate),
- preferred_width_(init_params.min_width),
- bubble_border_(new BubbleBorder(
- arrow(),
- init_params.has_shadow ? BubbleBorder::NO_ASSETS
- : BubbleBorder::NO_SHADOW,
- init_params.bg_color.value_or(gfx::kPlaceholderColor))),
- owned_bubble_border_(bubble_border_),
- is_gesture_dragging_(false),
- mouse_actively_entered_(false) {
- DCHECK(delegate_);
- DCHECK(params_.parent_window);
- DCHECK(anchor_widget()); // Computed by BubbleDialogDelegateView().
- bubble_border_->set_use_theme_background_color(!init_params.bg_color);
- if (init_params.corner_radius)
- bubble_border_->SetCornerRadius(init_params.corner_radius.value());
- set_parent_window(params_.parent_window);
- set_can_activate(false);
- set_notify_enter_exit_on_child(true);
- set_close_on_deactivate(init_params.close_on_deactivate);
- set_margins(gfx::Insets());
- SetPaintToLayer();
-
- bubble_content_mask_ = views::Painter::CreatePaintedLayer(
- views::Painter::CreateSolidRoundRectPainter(
- SK_ColorBLACK, bubble_border_->GetBorderCornerRadius()));
-
- auto layout = std::make_unique<BottomAlignedBoxLayout>(this);
- layout->SetDefaultFlex(1);
- layout_ = SetLayoutManager(std::move(layout));
-}
-
-TrayBubbleView::~TrayBubbleView() {
- mouse_watcher_.reset();
-
- if (delegate_) {
- // Inform host items (models) that their views are being destroyed.
- delegate_->BubbleViewDestroyed();
- }
-}
-
-// static
-bool TrayBubbleView::IsATrayBubbleOpen() {
- return g_current_tray_bubble_showing_count_ > 0;
-}
-
-void TrayBubbleView::InitializeAndShowBubble() {
- layer()->parent()->SetMaskLayer(bubble_content_mask_->layer());
-
- GetWidget()->Show();
- UpdateBubble();
-
- ++g_current_tray_bubble_showing_count_;
-
- // If TrayBubbleView cannot be activated and is shown by clicking on the
- // corresponding tray view, register pre target event handler to reroute key
- // events to the widget for activating the view or closing it.
- if (!CanActivate() && params_.show_by_click) {
- reroute_event_handler_ = std::make_unique<RerouteEventHandler>(this);
- }
-}
-
-void TrayBubbleView::UpdateBubble() {
- if (GetWidget()) {
- SizeToContents();
- GetWidget()->GetRootView()->SchedulePaint();
-
- // When extra keyboard accessibility is enabled, focus the default item if
- // no item is focused.
- if (delegate_ && delegate_->ShouldEnableExtraKeyboardAccessibility())
- FocusDefaultIfNeeded();
- }
-}
-
-void TrayBubbleView::SetMaxHeight(int height) {
- params_.max_height = height;
- if (GetWidget())
- SizeToContents();
-}
-
-void TrayBubbleView::SetBottomPadding(int padding) {
- layout_->set_inside_border_insets(gfx::Insets(0, 0, padding, 0));
-}
-
-void TrayBubbleView::SetWidth(int width) {
- width = std::max(std::min(width, params_.max_width), params_.min_width);
- if (preferred_width_ == width)
- return;
- preferred_width_ = width;
- if (GetWidget())
- SizeToContents();
-}
-
-gfx::Insets TrayBubbleView::GetBorderInsets() const {
- return bubble_border_->GetInsets();
-}
-
-void TrayBubbleView::ResetDelegate() {
- reroute_event_handler_.reset();
-
- delegate_ = nullptr;
-}
-
-void TrayBubbleView::ChangeAnchorView(views::View* anchor_view) {
- BubbleDialogDelegateView::SetAnchorView(anchor_view);
-}
-
-int TrayBubbleView::GetDialogButtons() const {
- return ui::DIALOG_BUTTON_NONE;
-}
-
-ax::mojom::Role TrayBubbleView::GetAccessibleWindowRole() const {
- // We override the role because the base class sets it to alert dialog.
- // This would make screen readers announce the whole of the system tray
- // which is undesirable.
- return ax::mojom::Role::kDialog;
-}
-
-void TrayBubbleView::SizeToContents() {
- BubbleDialogDelegateView::SizeToContents();
- bubble_content_mask_->layer()->SetBounds(layer()->parent()->bounds());
-}
-
-void TrayBubbleView::OnBeforeBubbleWidgetInit(Widget::InitParams* params,
- Widget* bubble_widget) const {
- if (bubble_border_->shadow() == BubbleBorder::NO_ASSETS) {
- // Apply a WM-provided shadow (see ui/wm/core/).
- params->shadow_type = Widget::InitParams::SHADOW_TYPE_DROP;
- params->shadow_elevation = wm::kShadowElevationActiveWindow;
- }
-}
-
-void TrayBubbleView::OnWidgetClosing(Widget* widget) {
- // We no longer need to watch key events for activation if the widget is
- // closing.
- reroute_event_handler_.reset();
-
- BubbleDialogDelegateView::OnWidgetClosing(widget);
- --g_current_tray_bubble_showing_count_;
- DCHECK_GE(g_current_tray_bubble_showing_count_, 0)
- << "Closing " << widget->GetName();
-}
-
-void TrayBubbleView::OnWidgetActivationChanged(Widget* widget, bool active) {
- // We no longer need to watch key events for activation if the widget is
- // activated.
- reroute_event_handler_.reset();
-
- BubbleDialogDelegateView::OnWidgetActivationChanged(widget, active);
-}
-
-NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) {
- BubbleFrameView* frame = static_cast<BubbleFrameView*>(
- BubbleDialogDelegateView::CreateNonClientFrameView(widget));
- frame->SetBubbleBorder(std::move(owned_bubble_border_));
- return frame;
-}
-
-bool TrayBubbleView::WidgetHasHitTestMask() const {
- return true;
-}
-
-void TrayBubbleView::GetWidgetHitTestMask(gfx::Path* mask) const {
- DCHECK(mask);
- mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds()));
-}
-
-base::string16 TrayBubbleView::GetAccessibleWindowTitle() const {
- if (delegate_)
- return delegate_->GetAccessibleNameForBubble();
- else
- return base::string16();
-}
-
-gfx::Size TrayBubbleView::CalculatePreferredSize() const {
- DCHECK_LE(preferred_width_, params_.max_width);
- return gfx::Size(preferred_width_, GetHeightForWidth(preferred_width_));
-}
-
-int TrayBubbleView::GetHeightForWidth(int width) const {
- int height = GetInsets().height();
- width = std::max(width - GetInsets().width(), 0);
- for (int i = 0; i < child_count(); ++i) {
- const View* child = child_at(i);
- if (child->visible())
- height += child->GetHeightForWidth(width);
- }
-
- return (params_.max_height != 0) ?
- std::min(height, params_.max_height) : height;
-}
-
-void TrayBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
- mouse_watcher_.reset();
- if (delegate_ && !(event.flags() & ui::EF_IS_SYNTHESIZED)) {
- // Coming here the user was actively moving the mouse over the bubble and
- // we inform the delegate that we entered. This will prevent the bubble
- // to auto close.
- delegate_->OnMouseEnteredView();
- mouse_actively_entered_ = true;
- } else {
- // Coming here the bubble got shown and the mouse was 'accidentally' over it
- // which is not a reason to prevent the bubble to auto close. As such we
- // do not call the delegate, but wait for the first mouse move within the
- // bubble. The used MouseWatcher will notify use of a movement and call
- // |MouseMovedOutOfHost|.
- mouse_watcher_ = std::make_unique<MouseWatcher>(
- std::make_unique<views::internal::MouseMoveDetectorHost>(), this);
- // Set the mouse sampling frequency to roughly a frame time so that the user
- // cannot see a lag.
- mouse_watcher_->set_notify_on_exit_time(
- base::TimeDelta::FromMilliseconds(kFrameTimeInMS));
- mouse_watcher_->Start(GetWidget()->GetNativeWindow());
- }
-}
-
-void TrayBubbleView::OnMouseExited(const ui::MouseEvent& event) {
- // If there was a mouse watcher waiting for mouse movements we disable it
- // immediately since we now leave the bubble.
- mouse_watcher_.reset();
- // Do not notify the delegate of an exit if we never told it that we entered.
- if (delegate_ && mouse_actively_entered_)
- delegate_->OnMouseExitedView();
-}
-
-void TrayBubbleView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- if (delegate_ && CanActivate()) {
- node_data->role = ax::mojom::Role::kWindow;
- node_data->SetName(delegate_->GetAccessibleNameForBubble());
- }
-}
-
-void TrayBubbleView::OnGestureEvent(ui::GestureEvent* event) {
- if (delegate_)
- delegate_->ProcessGestureEventForBubble(event);
-
- if (!event->handled())
- BubbleDialogDelegateView::OnGestureEvent(event);
-}
-
-void TrayBubbleView::MouseMovedOutOfHost() {
- // The mouse was accidentally over the bubble when it opened and the AutoClose
- // logic was not activated. Now that the user did move the mouse we tell the
- // delegate to disable AutoClose.
- if (delegate_)
- delegate_->OnMouseEnteredView();
- mouse_actively_entered_ = true;
- mouse_watcher_->Stop();
-}
-
-void TrayBubbleView::ChildPreferredSizeChanged(View* child) {
- SizeToContents();
-}
-
-void TrayBubbleView::ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) {
- if (details.is_add && details.child == this) {
- details.parent->SetPaintToLayer();
- details.parent->layer()->SetMasksToBounds(true);
- }
-}
-
-void TrayBubbleView::CloseBubbleView() {
- if (!delegate_)
- return;
-
- delegate_->HideBubble(this);
-}
-
-void TrayBubbleView::FocusDefaultIfNeeded() {
- views::FocusManager* manager = GetFocusManager();
- if (!manager || manager->GetFocusedView())
- return;
-
- views::View* view =
- manager->GetNextFocusableView(nullptr, nullptr, false, false);
- if (!view)
- return;
-
- // No need to explicitly activate the widget. View::RequestFocus will activate
- // it if necessary.
- set_can_activate(true);
-
- view->RequestFocus();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/bubble/tray_bubble_view.h b/chromium/ui/views/bubble/tray_bubble_view.h
deleted file mode 100644
index 5ef449781bc..00000000000
--- a/chromium/ui/views/bubble/tray_bubble_view.h
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_BUBBLE_TRAY_BUBBLE_VIEW_H_
-#define UI_VIEWS_BUBBLE_TRAY_BUBBLE_VIEW_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/optional.h"
-#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_view.h"
-#include "ui/views/mouse_watcher.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class LayerOwner;
-}
-
-namespace views {
-class BoxLayout;
-class View;
-class Widget;
-}
-
-namespace views {
-
-// Specialized bubble view for bubbles associated with a tray icon (e.g. the
-// Ash status area). Mostly this handles custom anchor location and arrow and
-// border rendering. This also has its own delegate for handling mouse events
-// and other implementation specific details.
-class VIEWS_EXPORT TrayBubbleView : public BubbleDialogDelegateView,
- public MouseWatcherListener {
- public:
- // AnchorAlignment determines to which side of the anchor the bubble will
- // align itself.
- enum AnchorAlignment {
- ANCHOR_ALIGNMENT_BOTTOM,
- ANCHOR_ALIGNMENT_LEFT,
- ANCHOR_ALIGNMENT_RIGHT,
- };
-
- class VIEWS_EXPORT Delegate {
- public:
- typedef TrayBubbleView::AnchorAlignment AnchorAlignment;
-
- Delegate() {}
- virtual ~Delegate();
-
- // Called when the view is destroyed. Any pointers to the view should be
- // cleared when this gets called.
- virtual void BubbleViewDestroyed();
-
- // Called when the mouse enters/exits the view.
- // Note: This event will only be called if the mouse gets actively moved by
- // the user to enter the view.
- virtual void OnMouseEnteredView();
- virtual void OnMouseExitedView();
-
- // Called from GetAccessibleNodeData(); should return the appropriate
- // accessible name for the bubble.
- virtual base::string16 GetAccessibleNameForBubble();
-
- // Should return true if extra keyboard accessibility is enabled.
- // TrayBubbleView will put focus on the default item if extra keyboard
- // accessibility is enabled.
- virtual bool ShouldEnableExtraKeyboardAccessibility();
-
- // Called when a bubble wants to hide/destroy itself (e.g. last visible
- // child view was closed).
- virtual void HideBubble(const TrayBubbleView* bubble_view);
-
- // Called to process the gesture events that happened on the TrayBubbleView.
- // Swiping down on the opened TrayBubbleView to close the bubble.
- virtual void ProcessGestureEventForBubble(ui::GestureEvent* event);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Delegate);
- };
-
- struct VIEWS_EXPORT InitParams {
- InitParams();
- InitParams(const InitParams& other);
- Delegate* delegate = nullptr;
- gfx::NativeWindow parent_window = nullptr;
- View* anchor_view = nullptr;
- AnchorAlignment anchor_alignment = ANCHOR_ALIGNMENT_BOTTOM;
- int min_width = 0;
- int max_width = 0;
- int max_height = 0;
- bool close_on_deactivate = true;
- // Indicates whether tray bubble view is shown by click on the tray view.
- bool show_by_click = false;
- // If not provided, the bg color will be derived from the NativeTheme.
- base::Optional<SkColor> bg_color;
- base::Optional<int> corner_radius;
- bool has_shadow = true;
- };
-
- explicit TrayBubbleView(const InitParams& init_params);
- ~TrayBubbleView() override;
-
- // Returns whether a tray bubble is active.
- static bool IsATrayBubbleOpen();
-
- // Sets up animations, and show the bubble. Must occur after CreateBubble()
- // is called.
- void InitializeAndShowBubble();
-
- // Called whenever the bubble size or location may have changed.
- void UpdateBubble();
-
- // Sets the maximum bubble height and resizes the bubble.
- void SetMaxHeight(int height);
-
- // Sets the bottom padding that child views will be laid out within.
- void SetBottomPadding(int padding);
-
- // Sets the bubble width.
- void SetWidth(int width);
-
- // Returns the border insets. Called by TrayEventFilter.
- gfx::Insets GetBorderInsets() const;
-
- // Called when the delegate is destroyed. This must be called before the
- // delegate is actually destroyed. TrayBubbleView will do clean up in
- // ResetDelegate.
- void ResetDelegate();
-
- // Anchors the bubble to |anchor_view|.
- void ChangeAnchorView(views::View* anchor_view);
-
- Delegate* delegate() { return delegate_; }
-
- void set_gesture_dragging(bool dragging) { is_gesture_dragging_ = dragging; }
- bool is_gesture_dragging() const { return is_gesture_dragging_; }
-
- // Overridden from views::WidgetDelegate.
- views::NonClientFrameView* CreateNonClientFrameView(
- views::Widget* widget) override;
- bool WidgetHasHitTestMask() const override;
- void GetWidgetHitTestMask(gfx::Path* mask) const override;
- base::string16 GetAccessibleWindowTitle() const override;
-
- // Overridden from views::BubbleDialogDelegateView.
- void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
- Widget* bubble_widget) const override;
- void OnWidgetClosing(Widget* widget) override;
- void OnWidgetActivationChanged(Widget* widget, bool active) override;
-
- // Overridden from views::View.
- gfx::Size CalculatePreferredSize() const override;
- int GetHeightForWidth(int width) const override;
- void OnMouseEntered(const ui::MouseEvent& event) override;
- void OnMouseExited(const ui::MouseEvent& event) override;
- void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
- void OnGestureEvent(ui::GestureEvent* event) override;
-
- // Overridden from MouseWatcherListener
- void MouseMovedOutOfHost() override;
-
- protected:
- // Overridden from views::BubbleDialogDelegateView.
- int GetDialogButtons() const override;
- ax::mojom::Role GetAccessibleWindowRole() const override;
- void SizeToContents() override;
-
- // Overridden from views::View.
- void ChildPreferredSizeChanged(View* child) override;
- void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) override;
-
- private:
- // This reroutes receiving key events to the TrayBubbleView passed in the
- // constructor. TrayBubbleView is not activated by default. But we want to
- // activate it if user tries to interact it with keyboard. To capture those
- // key events in early stage, RerouteEventHandler installs this handler to
- // aura::Env. RerouteEventHandler also sends key events to ViewsDelegate to
- // process accelerator as menu is currently open.
- class RerouteEventHandler : public ui::EventHandler {
- public:
- explicit RerouteEventHandler(TrayBubbleView* tray_bubble_view);
- ~RerouteEventHandler() override;
-
- // Overridden from ui::EventHandler
- void OnKeyEvent(ui::KeyEvent* event) override;
-
- private:
- // TrayBubbleView to which key events are going to be rerouted. Not owned.
- TrayBubbleView* tray_bubble_view_;
-
- DISALLOW_COPY_AND_ASSIGN(RerouteEventHandler);
- };
-
- void CloseBubbleView();
-
- // Focus the default item if no item is focused.
- void FocusDefaultIfNeeded();
-
- InitParams params_;
- BoxLayout* layout_;
- Delegate* delegate_;
- int preferred_width_;
- // |bubble_border_| and |owned_bubble_border_| point to the same thing, but
- // the latter ensures we don't leak it before passing off ownership.
- BubbleBorder* bubble_border_;
- std::unique_ptr<views::BubbleBorder> owned_bubble_border_;
- std::unique_ptr<ui::LayerOwner> bubble_content_mask_;
- bool is_gesture_dragging_;
-
- // True once the mouse cursor was actively moved by the user over the bubble.
- // Only then the OnMouseExitedView() event will get passed on to listeners.
- bool mouse_actively_entered_;
-
- // Used to find any mouse movements.
- std::unique_ptr<MouseWatcher> mouse_watcher_;
-
- // Used to activate tray bubble view if user tries to interact the tray with
- // keyboard.
- std::unique_ptr<EventHandler> reroute_event_handler_;
-
- DISALLOW_COPY_AND_ASSIGN(TrayBubbleView);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_BUBBLE_TRAY_BUBBLE_VIEW_H_
diff --git a/chromium/ui/views/cocoa/DEPS b/chromium/ui/views/cocoa/DEPS
index fcaeee7d596..440d45f5357 100644
--- a/chromium/ui/views/cocoa/DEPS
+++ b/chromium/ui/views/cocoa/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+components/viz/common",
"+ui/accelerated_widget_mac",
"+ui/views_bridge_mac",
]
diff --git a/chromium/ui/views/cocoa/bridge_factory_host.cc b/chromium/ui/views/cocoa/bridge_factory_host.cc
new file mode 100644
index 00000000000..4350aae5c1a
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridge_factory_host.cc
@@ -0,0 +1,35 @@
+// 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/bridge_factory_host.h"
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace views {
+
+BridgeFactoryHost::BridgeFactoryHost(
+ uint64_t host_id,
+ views_bridge_mac::mojom::BridgeFactoryAssociatedRequest* request)
+ : host_id_(host_id) {
+ *request = mojo::MakeRequest(&bridge_factory_ptr_);
+}
+
+BridgeFactoryHost::~BridgeFactoryHost() {
+ for (Observer& obs : observers_)
+ obs.OnBridgeFactoryHostDestroying(this);
+}
+
+views_bridge_mac::mojom::BridgeFactory* BridgeFactoryHost::GetFactory() {
+ return bridge_factory_ptr_.get();
+}
+
+void BridgeFactoryHost::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void BridgeFactoryHost::RemoveObserver(const Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/cocoa/bridge_factory_host.h b/chromium/ui/views/cocoa/bridge_factory_host.h
new file mode 100644
index 00000000000..14a197dce5e
--- /dev/null
+++ b/chromium/ui/views/cocoa/bridge_factory_host.h
@@ -0,0 +1,47 @@
+// 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_BRIDGE_FACTORY_HOST_H_
+#define UI_VIEWS_COCOA_BRIDGE_FACTORY_HOST_H_
+
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "ui/views/views_export.h"
+#include "ui/views_bridge_mac/mojo/bridge_factory.mojom.h"
+
+namespace views {
+
+class VIEWS_EXPORT BridgeFactoryHost {
+ public:
+ class Observer : public base::CheckedObserver {
+ public:
+ virtual void OnBridgeFactoryHostDestroying(BridgeFactoryHost* host) = 0;
+
+ protected:
+ ~Observer() override {}
+ };
+
+ BridgeFactoryHost(
+ uint64_t host_id,
+ views_bridge_mac::mojom::BridgeFactoryAssociatedRequest* request);
+ ~BridgeFactoryHost();
+
+ // Return an id for the host process. This can be used to look up other
+ // factories to create NSViews (e.g in content).
+ uint64_t GetHostId() const { return host_id_; }
+
+ views_bridge_mac::mojom::BridgeFactory* GetFactory();
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(const Observer* observer);
+
+ private:
+ const uint64_t host_id_;
+ views_bridge_mac::mojom::BridgeFactoryAssociatedPtr bridge_factory_ptr_;
+ base::ObserverList<Observer> observers_;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_COCOA_BRIDGE_FACTORY_HOST_H_
diff --git a/chromium/ui/views/cocoa/bridged_content_view.h b/chromium/ui/views/cocoa/bridged_content_view.h
deleted file mode 100644
index a6daf562123..00000000000
--- a/chromium/ui/views/cocoa/bridged_content_view.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
-#define UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#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 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, 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.
- ui::ScopedCrTrackingArea cursorTrackingArea_;
-
- // The keyDown event currently being handled, nil otherwise.
- NSEvent* keyDownEvent_;
-
- // Whether there's an active key down event which is not handled yet.
- BOOL hasUnhandledKeyDownEvent_;
-
- // The last tooltip text, used to limit updates.
- base::string16 lastTooltipText_;
-}
-
-@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)initWithBridge:(views::BridgedNativeWidget*)bridge bounds:(gfx::Rect)rect;
-
-// Clear the hosted view. For example, if it is about to be destroyed.
-- (void)clearView;
-
-// Process a mouse event captured while the widget had global mouse capture.
-- (void)processCapturedMouseEvent:(NSEvent*)theEvent;
-
-// Mac's version of views::corewm::TooltipController::UpdateIfRequired().
-// Updates the tooltip on the ToolTipBaseView if the text needs to change.
-// |locationInContent| is the position from the top left of the window's
-// contentRect (also this NSView's frame), as given by a ui::LocatedEvent.
-- (void)updateTooltipIfRequiredAt:(const gfx::Point&)locationInContent;
-
-// Notifies the associated FocusManager whether full keyboard access is enabled
-// or not.
-- (void)updateFullKeyboardAccess;
-
-@end
-
-#endif // UI_VIEWS_COCOA_BRIDGED_CONTENT_VIEW_H_
diff --git a/chromium/ui/views/cocoa/bridged_content_view.mm b/chromium/ui/views/cocoa/bridged_content_view.mm
deleted file mode 100644
index 9ffa0c183b3..00000000000
--- a/chromium/ui/views/cocoa/bridged_content_view.mm
+++ /dev/null
@@ -1,1577 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/bridged_content_view.h"
-
-#include "base/logging.h"
-#import "base/mac/mac_util.h"
-#import "base/mac/scoped_nsobject.h"
-#import "base/mac/sdk_forward_declarations.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "ui/base/cocoa/appkit_utils.h"
-#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/ime/input_method.h"
-#include "ui/base/ime/text_edit_commands.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/compositor/canvas_painter.h"
-#import "ui/events/cocoa/cocoa_event_utils.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
-#include "ui/gfx/canvas_paint_mac.h"
-#include "ui/gfx/decorated_text.h"
-#import "ui/gfx/decorated_text_mac.h"
-#include "ui/gfx/geometry/rect.h"
-#import "ui/gfx/mac/coordinate_conversion.h"
-#include "ui/gfx/path.h"
-#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/view.h"
-#include "ui/views/widget/native_widget_mac.h"
-#include "ui/views/widget/widget.h"
-
-namespace {
-
-NSString* const kFullKeyboardAccessChangedNotification =
- @"com.apple.KeyboardUIModeDidChange";
-
-// Convert a |point| in |source_window|'s AppKit coordinate system (origin at
-// the bottom left of the window) to |target_window|'s content rect, with the
-// origin at the top left of the content area.
-// If |source_window| is nil, |point| will be treated as screen coordinates.
-gfx::Point MovePointToWindow(const NSPoint& point,
- NSWindow* source_window,
- NSWindow* target_window) {
- NSPoint point_in_screen = source_window
- ? ui::ConvertPointFromWindowToScreen(source_window, point)
- : point;
-
- NSPoint point_in_window =
- ui::ConvertPointFromScreenToWindow(target_window, point_in_screen);
- NSRect content_rect =
- [target_window contentRectForFrameRect:[target_window frame]];
- return gfx::Point(point_in_window.x,
- NSHeight(content_rect) - point_in_window.y);
-}
-
-// Returns true if |client| has RTL text.
-bool IsTextRTL(const ui::TextInputClient* client) {
- return client && client->GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
-}
-
-// Returns true if |event| may have triggered dismissal of an IME and would
-// 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 ||
- key == ui::VKEY_ESCAPE;
-}
-
-// Returns the boundary rectangle for composition characters in the
-// |requested_range|. Sets |actual_range| corresponding to the returned
-// rectangle. For cases, where there is no composition text or the
-// |requested_range| lies outside the composition range, a zero width rectangle
-// corresponding to the caret bounds is returned. Logic used is similar to
-// RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(...).
-gfx::Rect GetFirstRectForRangeHelper(const ui::TextInputClient* client,
- const gfx::Range& requested_range,
- gfx::Range* actual_range) {
- // NSRange doesn't support reversed ranges.
- DCHECK(!requested_range.is_reversed());
- DCHECK(actual_range);
-
- // Set up default return values, to be returned in case of unusual cases.
- gfx::Rect default_rect;
- *actual_range = gfx::Range::InvalidRange();
- if (!client)
- return default_rect;
-
- default_rect = client->GetCaretBounds();
- default_rect.set_width(0);
-
- // If possible, modify actual_range to correspond to caret position.
- gfx::Range selection_range;
- if (client->GetSelectionRange(&selection_range)) {
- // Caret bounds correspond to end index of selection_range.
- *actual_range = gfx::Range(selection_range.end());
- }
-
- gfx::Range composition_range;
- if (!client->HasCompositionText() ||
- !client->GetCompositionTextRange(&composition_range) ||
- !composition_range.Contains(requested_range))
- return default_rect;
-
- DCHECK(!composition_range.is_reversed());
-
- const size_t from = requested_range.start() - composition_range.start();
- const size_t to = requested_range.end() - composition_range.start();
-
- // Pick the first character's bounds as the initial rectangle, then grow it to
- // the full |requested_range| if possible.
- const bool request_is_composition_end = from == composition_range.length();
- const size_t first_index = request_is_composition_end ? from - 1 : from;
- gfx::Rect union_rect;
- if (!client->GetCompositionCharacterBounds(first_index, &union_rect))
- return default_rect;
-
- // If requested_range is empty, return a zero width rectangle corresponding to
- // it.
- if (from == to) {
- if (request_is_composition_end && !IsTextRTL(client)) {
- // In case of an empty requested range at end of composition, return the
- // rectangle to the right of the last compositioned character.
- union_rect.set_origin(union_rect.top_right());
- }
- union_rect.set_width(0);
- *actual_range = requested_range;
- return union_rect;
- }
-
- // Toolkit-views textfields are always single-line, so no need to check for
- // line breaks.
- for (size_t i = from + 1; i < to; i++) {
- gfx::Rect current_rect;
- if (client->GetCompositionCharacterBounds(i, &current_rect)) {
- union_rect.Union(current_rect);
- } else {
- *actual_range =
- gfx::Range(requested_range.start(), i + composition_range.start());
- return union_rect;
- }
- }
- *actual_range = requested_range;
- return union_rect;
-}
-
-// Returns the string corresponding to |requested_range| for the given |client|.
-// If a gfx::Range::InvalidRange() is passed, the full string stored by |client|
-// is returned. Sets |actual_range| corresponding to the returned string.
-base::string16 AttributedSubstringForRangeHelper(
- const ui::TextInputClient* client,
- const gfx::Range& requested_range,
- gfx::Range* actual_range) {
- // NSRange doesn't support reversed ranges.
- DCHECK(!requested_range.is_reversed());
- DCHECK(actual_range);
-
- base::string16 substring;
- gfx::Range text_range;
- *actual_range = gfx::Range::InvalidRange();
- if (!client || !client->GetTextRange(&text_range))
- return substring;
-
- // gfx::Range::Intersect() behaves a bit weirdly. If B is an empty range
- // contained inside a non-empty range A, B intersection A returns
- // gfx::Range::InvalidRange(), instead of returning B.
- *actual_range = text_range.Contains(requested_range)
- ? requested_range
- : text_range.Intersect(requested_range);
-
- // This is a special case for which the complete string should should be
- // returned. NSTextView also follows this, though the same is not mentioned in
- // NSTextInputClient documentation.
- if (!requested_range.IsValid())
- *actual_range = text_range;
-
- client->GetTextFromRange(*actual_range, &substring);
- return substring;
-}
-
-ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- if (action == @selector(undo:))
- return ui::TextEditCommand::UNDO;
- if (action == @selector(redo:))
- return ui::TextEditCommand::REDO;
- if (action == @selector(cut:))
- return ui::TextEditCommand::CUT;
- if (action == @selector(copy:))
- return ui::TextEditCommand::COPY;
- if (action == @selector(paste:))
- return ui::TextEditCommand::PASTE;
- if (action == @selector(selectAll:))
- return ui::TextEditCommand::SELECT_ALL;
- return ui::TextEditCommand::INVALID_COMMAND;
-}
-
-} // namespace
-
-@interface BridgedContentView ()
-
-// 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;
-
-// Allows accelerators to be handled at different points in AppKit key event
-// dispatch. Checks for an unhandled event passed in to -keyDown: and passes it
-// to the Widget for processing. Returns YES if the Widget handles it.
-- (BOOL)handleUnhandledKeyDownAsKeyEvent;
-
-// Handles an NSResponder Action Message by mapping it to a corresponding text
-// editing command from ui_strings.grd and, when not being sent to a
-// TextInputClient, the keyCode that toolkit-views expects internally.
-// For example, moveToLeftEndOfLine: would pass ui::VKEY_HOME in non-RTL locales
-// even though the Home key on Mac defaults to moveToBeginningOfDocument:.
-// This approach also allows action messages a user
-// may have remapped in ~/Library/KeyBindings/DefaultKeyBinding.dict to be
-// catered for.
-// Note: default key bindings in Mac can be read from StandardKeyBinding.dict
-// which lives in /System/Library/Frameworks/AppKit.framework/Resources. Do
-// `plutil -convert xml1 -o StandardKeyBinding.xml StandardKeyBinding.dict` to
-// get something readable.
-- (void)handleAction:(ui::TextEditCommand)command
- keyCode:(ui::KeyboardCode)keyCode
- domCode:(ui::DomCode)domCode
- eventFlags:(int)eventFlags;
-
-// ui::EventLocationFromNative() assumes the event hit the contentView.
-// Adjust |event| if that's not the case (e.g. for reparented views).
-- (void)adjustUiEventLocation:(ui::LocatedEvent*)event
- fromNativeEvent:(NSEvent*)nativeEvent;
-
-// Notification handler invoked when the Full Keyboard Access mode is changed.
-- (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification;
-
-// Helper method which forwards |text| to the active menu or |textInputClient_|.
-- (void)insertTextInternal:(id)text;
-
-// Returns the native Widget's drag drop client. Possibly null.
-- (views::DragDropClientMac*)dragDropClient;
-
-// Menu action handlers.
-- (void)undo:(id)sender;
-- (void)redo:(id)sender;
-- (void)cut:(id)sender;
-- (void)copy:(id)sender;
-- (void)paste:(id)sender;
-- (void)selectAll:(id)sender;
-
-@end
-
-@implementation BridgedContentView
-
-@synthesize bridge = bridge_;
-@synthesize textInputClient = textInputClient_;
-@synthesize drawMenuBackgroundForBlur = drawMenuBackgroundForBlur_;
-
-- (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])) {
- bridge_ = bridge;
-
- // Apple's documentation says that NSTrackingActiveAlways is incompatible
- // with NSTrackingCursorUpdate, so use NSTrackingActiveInActiveApp.
- cursorTrackingArea_.reset([[CrTrackingArea alloc]
- initWithRect:NSZeroRect
- options:NSTrackingMouseMoved | NSTrackingCursorUpdate |
- NSTrackingActiveInActiveApp | NSTrackingInVisibleRect |
- NSTrackingMouseEnteredAndExited
- owner:self
- userInfo:nil]);
- [self addTrackingArea:cursorTrackingArea_.get()];
-
- // Get notified whenever Full Keyboard Access mode is changed.
- [[NSDistributedNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(onFullKeyboardAccessModeChanged:)
- name:kFullKeyboardAccessChangedNotification
- object:nil];
-
- // Initialize the focus manager with the correct keyboard accessibility
- // setting.
- [self updateFullKeyboardAccess];
- [self registerForDraggedTypes:ui::OSExchangeDataProviderMac::
- SupportedPasteboardTypes()];
- }
- return self;
-}
-
-- (void)dealloc {
- // By the time |self| is dealloc'd, it should never be in an NSWindow, and it
- // should never be the current input context.
- DCHECK_EQ(nil, [self window]);
- // Sanity check: NSView always provides an -inputContext.
- DCHECK_NE(nil, [super inputContext]);
- DCHECK_NE([NSTextInputContext currentInputContext], [super inputContext]);
- [super dealloc];
-}
-
-- (void)clearView {
- [self setTextInputClient:nullptr];
- bridge_ = nullptr;
- [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
- [cursorTrackingArea_.get() clearOwner];
- [self removeTrackingArea:cursorTrackingArea_.get()];
-}
-
-- (void)setTextInputClient:(ui::TextInputClient*)newTextInputClient {
- if (pendingTextInputClient_ == newTextInputClient)
- return;
-
- // This method may cause the IME window to dismiss, which may cause it to
- // insert text (e.g. to replace marked text with "real" text). That should
- // happen in the old -inputContext (which AppKit stores a reference to).
- // Unfortunately, the only way to invalidate the the old -inputContext is to
- // invoke -[NSApp updateWindows], which also wants a reference to the _new_
- // -inputContext. So put the new inputContext in |pendingTextInputClient_| and
- // only use it for -inputContext.
- ui::TextInputClient* oldInputClient = textInputClient_;
-
- // Since dismissing an IME may insert text, a misbehaving IME or a
- // ui::TextInputClient that acts on InsertChar() to change focus a second time
- // may invoke -setTextInputClient: recursively; with [NSApp updateWindows]
- // still on the stack. Calling [NSApp updateWindows] recursively may upset
- // an IME. Since the rest of this method is only to decide whether to call
- // updateWindows, and we're already calling it, just bail out.
- if (textInputClient_ != pendingTextInputClient_) {
- pendingTextInputClient_ = newTextInputClient;
- return;
- }
-
- // Start by assuming no need to invoke -updateWindows.
- textInputClient_ = newTextInputClient;
- pendingTextInputClient_ = newTextInputClient;
-
- // If |self| was being used for the input context, and would now report a
- // different input context, manually invoke [NSApp updateWindows]. This is
- // necessary because AppKit holds on to a raw pointer to a NSTextInputContext
- // (which may have been the one returned by [self inputContext]) that is only
- // updated by -updateWindows. And although AppKit invokes that on each
- // iteration through most runloop modes, it does not call it when running
- // NSEventTrackingRunLoopMode, and not _within_ a run loop iteration, where
- // the inputContext may change before further event processing.
- NSTextInputContext* current = [NSTextInputContext currentInputContext];
- if (!current)
- return;
-
- NSTextInputContext* newContext = [self inputContext];
- // If the newContext is non-nil, then it can only be [super inputContext]. So
- // the input context is either not changing, or it was not from |self|. In
- // both cases, there's no need to call -updateWindows.
- if (newContext) {
- DCHECK_EQ(newContext, [super inputContext]);
- return;
- }
-
- if (current == [super inputContext]) {
- DCHECK_NE(oldInputClient, textInputClient_);
- textInputClient_ = oldInputClient;
- [NSApp updateWindows];
- // Note: |pendingTextInputClient_| (and therefore +[NSTextInputContext
- // currentInputContext] may have changed if called recursively.
- textInputClient_ = pendingTextInputClient_;
- }
-}
-
-// 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);
- bool isDraggableBackground = false;
- bridge_->host()->GetIsDraggableBackgroundAt(flippedPoint,
- &isDraggableBackground);
- if (isDraggableBackground)
- return nil;
- return [super hitTest:point];
-}
-
-- (void)processCapturedMouseEvent:(NSEvent*)theEvent {
- if (!bridge_)
- return;
-
- NSWindow* source = [theEvent window];
- NSWindow* target = [self window];
- DCHECK(target);
-
- BOOL isScrollEvent = [theEvent type] == NSScrollWheel;
-
- // If it's the view's window, process normally.
- if ([target isEqual:source]) {
- if (isScrollEvent)
- [self scrollWheel:theEvent];
- else
- [self mouseEvent:theEvent];
-
- return;
- }
-
- gfx::Point event_location =
- MovePointToWindow([theEvent locationInWindow], source, target);
- [self updateTooltipIfRequiredAt:event_location];
-
- if (isScrollEvent) {
- ui::ScrollEvent event(theEvent);
- event.set_location(event_location);
- bridge_->host()->OnScrollEvent(event);
- } else {
- ui::MouseEvent event(theEvent);
- event.set_location(event_location);
- bridge_->host()->OnMouseEvent(event);
- }
-}
-
-- (void)updateTooltipIfRequiredAt:(const gfx::Point&)locationInContent {
- DCHECK(bridge_);
- base::string16 newTooltipText;
-
- bridge_->host()->GetTooltipTextAt(locationInContent, &newTooltipText);
- if (newTooltipText != lastTooltipText_) {
- std::swap(newTooltipText, lastTooltipText_);
- [self setToolTipAtMousePoint:base::SysUTF16ToNSString(lastTooltipText_)];
- }
-}
-
-- (void)updateFullKeyboardAccess {
- if (!bridge_)
- return;
- bridge_->host()->SetKeyboardAccessible([NSApp isFullKeyboardAccessEnabled]);
-}
-
-// BridgedContentView private implementation.
-
-- (void)dispatchKeyEvent:(ui::KeyEvent*)event {
- bool eventHandled = false;
- if (bridge_)
- bridge_->host()->DispatchKeyEvent(*event, &eventHandled);
- if (eventHandled)
- event->SetHandled();
-}
-
-- (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 ([self dispatchKeyEventToMenuController:event])
- return;
-
- [self dispatchKeyEvent:event];
-}
-
-- (BOOL)handleUnhandledKeyDownAsKeyEvent {
- if (!hasUnhandledKeyDownEvent_)
- return NO;
-
- ui::KeyEvent event(keyDownEvent_);
- [self handleKeyEvent:&event];
- hasUnhandledKeyDownEvent_ = NO;
- return event.handled();
-}
-
-- (void)handleAction:(ui::TextEditCommand)command
- keyCode:(ui::KeyboardCode)keyCode
- domCode:(ui::DomCode)domCode
- eventFlags:(int)eventFlags {
- if (!bridge_)
- return;
-
- // Always propagate the shift modifier if present. Shift doesn't always alter
- // the command selector, but should always be passed along. Control and Alt
- // have different meanings on Mac, so they do not propagate automatically.
- if ([keyDownEvent_ modifierFlags] & NSShiftKeyMask)
- eventFlags |= ui::EF_SHIFT_DOWN;
-
- // Generate a synthetic event with the keycode toolkit-views expects.
- ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, eventFlags);
-
- if ([self dispatchKeyEventToMenuController:&event])
- return;
-
- // If there's an active TextInputClient, schedule the editing command to be
- // performed.
- if (textInputClient_ && textInputClient_->IsTextEditCommandEnabled(command))
- textInputClient_->SetTextEditCommandForNextKeyEvent(command);
-
- [self dispatchKeyEvent:&event];
-}
-
-- (void)adjustUiEventLocation:(ui::LocatedEvent*)event
- fromNativeEvent:(NSEvent*)nativeEvent {
- if ([nativeEvent window] && [[self window] contentView] != self) {
- NSPoint p = [self convertPoint:[nativeEvent locationInWindow] fromView:nil];
- event->set_location(gfx::Point(p.x, NSHeight([self frame]) - p.y));
- }
-}
-
-- (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification {
- DCHECK([[notification name]
- isEqualToString:kFullKeyboardAccessChangedNotification]);
- [self updateFullKeyboardAccess];
-}
-
-- (void)insertTextInternal:(id)text {
- if (!bridge_)
- return;
-
- if ([text isKindOfClass:[NSAttributedString class]])
- text = [text string];
-
- bool isCharacterEvent = keyDownEvent_ && [text length] == 1;
- // Pass "character" events to the View hierarchy. Cases this handles (non-
- // exhaustive)-
- // - Space key press on controls. Unlike Tab and newline which have
- // corresponding action messages, an insertText: message is generated for
- // the Space key (insertText:replacementRange: when there's an active
- // input context).
- // - Menu mnemonic selection.
- // Note we create a custom character ui::KeyEvent (and not use the
- // ui::KeyEvent(NSEvent*) constructor) since we can't just rely on the event
- // key code to get the actual characters from the ui::KeyEvent. This for
- // example is necessary for menu mnemonic selection of non-latin text.
-
- // Don't generate a key event when there is marked composition text. These key
- // down events should be consumed by the IME and not reach the Views layer.
- // For example, on pressing Return to commit composition text, if we passed a
- // synthetic key event to the View hierarchy, it will have the effect of
- // performing the default action on the current dialog. We do not want this
- // when there is marked text (Return should only confirm the IME).
-
- // However, IME for phonetic languages such as Korean do not always _mark_
- // text when a composition is active. For these, correct behaviour is to
- // handle the final -keyDown: that caused the composition to be committed, but
- // only _after_ the sequence of insertText: messages coming from IME have been
- // sent to the TextInputClient. Detect this by comparing to -[NSEvent
- // characters]. Note we do not use -charactersIgnoringModifiers: so that,
- // e.g., ß (Alt+s) will match mnemonics with ß rather than s.
- bool isFinalInsertForKeyEvent =
- isCharacterEvent && [text isEqualToString:[keyDownEvent_ characters]];
-
- // Also note that a single, non-IME key down event can also cause multiple
- // insertText:replacementRange: action messages being generated from within
- // -keyDown:'s call to -interpretKeyEvents:. One example, on pressing Alt+e,
- // the accent (´) character is composed via setMarkedText:. Now on pressing
- // the character 'r', two insertText:replacementRange: action messages are
- // generated with the text value of accent (´) and 'r' respectively. The key
- // down event will have characters field of length 2. The first of these
- // insertText messages won't generate a KeyEvent since there'll be active
- // marked text. However, a KeyEvent will be generated corresponding to 'r'.
-
- // Currently there seems to be no use case to pass non-character events routed
- // from insertText: handlers to the View hierarchy.
- if (isFinalInsertForKeyEvent && ![self hasMarkedText]) {
- ui::KeyEvent charEvent([text characterAtIndex:0],
- ui::KeyboardCodeFromNSEvent(keyDownEvent_),
- ui::DomCodeFromNSEvent(keyDownEvent_), ui::EF_NONE);
- [self handleKeyEvent:&charEvent];
- hasUnhandledKeyDownEvent_ = NO;
- if (charEvent.handled())
- return;
- }
-
- // Forward the |text| to |textInputClient_| if no menu is active.
- 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
- // to determine the correct key code for each unicode character. Also a
- // correct keycode is not needed in the current context. Send ui::EF_NONE as
- // the key modifier since |text| already accounts for the pressed key
- // modifiers.
-
- // Also, note we don't check isFinalInsertForKeyEvent, nor use
- // |keyDownEvent_| to generate the synthetic ui::KeyEvent since: For
- // composed text, [keyDownEvent_ characters] might not be the same as
- // |text|. This is because |keyDownEvent_| will correspond to the event that
- // caused the composition text to be confirmed, say, Return key press.
- if (isCharacterEvent) {
- textInputClient_->InsertChar(
- ui::KeyEvent([text characterAtIndex:0], ui::VKEY_UNKNOWN,
- ui::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
- // -handleKeyEvent: earlier in this method since toolkit-views client code
- // assumes it can ignore characters associated with, e.g., VKEY_TAB.
- DCHECK(keyDownEvent_); // Otherwise it is not a character event.
- if ([self hasMarkedText] || !IsImeTriggerEvent(keyDownEvent_))
- hasUnhandledKeyDownEvent_ = NO;
- } else {
- textInputClient_->InsertText(base::SysNSStringToUTF16(text));
- hasUnhandledKeyDownEvent_ = NO;
- }
- }
-}
-
-- (views::DragDropClientMac*)dragDropClient {
- return bridge_ ? bridge_->drag_drop_client() : nullptr;
-}
-
-- (void)undo:(id)sender {
- [self handleAction:ui::TextEditCommand::UNDO
- keyCode:ui::VKEY_Z
- domCode:ui::DomCode::US_Z
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)redo:(id)sender {
- [self handleAction:ui::TextEditCommand::REDO
- keyCode:ui::VKEY_Z
- domCode:ui::DomCode::US_Z
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)cut:(id)sender {
- [self handleAction:ui::TextEditCommand::CUT
- keyCode:ui::VKEY_X
- domCode:ui::DomCode::US_X
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)copy:(id)sender {
- [self handleAction:ui::TextEditCommand::COPY
- keyCode:ui::VKEY_C
- domCode:ui::DomCode::US_C
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)paste:(id)sender {
- [self handleAction:ui::TextEditCommand::PASTE
- keyCode:ui::VKEY_V
- domCode:ui::DomCode::US_V
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)selectAll:(id)sender {
- [self handleAction:ui::TextEditCommand::SELECT_ALL
- keyCode:ui::VKEY_A
- domCode:ui::DomCode::US_A
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-// BaseView implementation.
-
-// Don't use tracking areas from BaseView. BridgedContentView's tracks
-// NSTrackingCursorUpdate and Apple's documentation suggests it's incompatible.
-- (void)enableTracking {
-}
-
-// Translates the location of |theEvent| to toolkit-views coordinates and passes
-// the event to NativeWidgetMac for handling.
-- (void)mouseEvent:(NSEvent*)theEvent {
- if (!bridge_)
- return;
-
- DCHECK([theEvent type] != NSScrollWheel);
- ui::MouseEvent event(theEvent);
- [self adjustUiEventLocation:&event fromNativeEvent:theEvent];
-
- // Aura updates tooltips with the help of aura::Window::AddPreTargetHandler().
- // Mac hooks in here.
- [self updateTooltipIfRequiredAt:event.location()];
- bridge_->host()->OnMouseEvent(event);
-}
-
-- (void)forceTouchEvent:(NSEvent*)theEvent {
- if (ui::ForceClickInvokesQuickLook())
- [self quickLookWithEvent:theEvent];
-}
-
-// NSView implementation.
-
-// This view must consistently return YES or else dragging a tab may drag the
-// entire window. See r549802 for details.
-- (BOOL)acceptsFirstResponder {
- return YES;
-}
-
-- (BOOL)becomeFirstResponder {
- if ([[self window] firstResponder] != self)
- return NO;
- BOOL result = [super becomeFirstResponder];
- if (result && bridge_)
- bridge_->host()->SetIsFirstResponder(true);
- return result;
-}
-
-- (BOOL)resignFirstResponder {
- BOOL result = [super resignFirstResponder];
- if (result && bridge_)
- bridge_->host()->SetIsFirstResponder(false);
- return result;
-}
-
-- (void)viewDidMoveToWindow {
- // When this view is added to a window, AppKit calls setFrameSize before it is
- // added to the window, so the behavior in setFrameSize is not triggered.
- NSWindow* window = [self window];
- if (window)
- [self setFrameSize:NSZeroSize];
-}
-
-- (void)setFrameSize:(NSSize)newSize {
- // The size passed in here does not always use
- // -[NSWindow contentRectForFrameRect]. The following ensures that the
- // contentView for a frameless window can extend over the titlebar of the new
- // 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) {
- 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 (bridge_)
- bridge_->host()->SetViewSize(gfx::Size(newSize.width, newSize.height));
-}
-
-- (BOOL)isOpaque {
- return bridge_ ? !bridge_->is_translucent_window() : NO;
-}
-
-// To maximize consistency with the Cocoa browser (mac_views_browser=0), accept
-// mouse clicks immediately so that clicking on Chrome from an inactive window
-// will allow the event to be processed, rather than merely activate the window.
-- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent {
- return YES;
-}
-
-// NSDraggingDestination protocol overrides.
-
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
- return [self draggingUpdated:sender];
-}
-
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
- views::DragDropClientMac* client = [self dragDropClient];
- return client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE;
-}
-
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
- views::DragDropClientMac* client = [self dragDropClient];
- if (client)
- client->DragExit();
-}
-
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
- views::DragDropClientMac* client = [self dragDropClient];
- return client && client->Drop(sender) != NSDragOperationNone;
-}
-
-- (NSTextInputContext*)inputContext {
- // If the textInputClient_ does not exist, return nil since this view does not
- // conform to NSTextInputClient protocol.
- if (!pendingTextInputClient_)
- return nil;
-
- // 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 hasActiveMenuController])
- return nil;
-
- // When not in an editable mode, or while entering passwords
- // (http://crbug.com/23219), we don't want to show IME candidate windows.
- // Returning nil prevents this view from getting messages defined as part of
- // the NSTextInputClient protocol.
- switch (pendingTextInputClient_->GetTextInputType()) {
- case ui::TEXT_INPUT_TYPE_NONE:
- case ui::TEXT_INPUT_TYPE_PASSWORD:
- return nil;
- default:
- return [super inputContext];
- }
-}
-
-// NSResponder implementation.
-
-- (BOOL)_wantsKeyDownForEvent:(NSEvent*)event {
- // This is a SPI that AppKit apparently calls after |performKeyEquivalent:|
- // returned NO. If this function returns |YES|, Cocoa sends the event to
- // |keyDown:| instead of doing other things with it. Ctrl-tab will be sent
- // to us instead of doing key view loop control, ctrl-left/right get handled
- // correctly, etc.
- // (However, there are still some keys that Cocoa swallows, e.g. the key
- // equivalent that Cocoa uses for toggling the input language. In this case,
- // that's actually a good thing, though -- see http://crbug.com/26115 .)
- return YES;
-}
-
-- (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];
- DCHECK(!hasUnhandledKeyDownEvent_);
- keyDownEvent_ = nil;
-}
-
-- (void)keyUp:(NSEvent*)theEvent {
- ui::KeyEvent event(theEvent);
- [self handleKeyEvent:&event];
-}
-
-- (void)flagsChanged:(NSEvent*)theEvent {
- ui::KeyEvent event(theEvent);
- [self handleKeyEvent:&event];
-}
-
-- (void)scrollWheel:(NSEvent*)theEvent {
- if (!bridge_)
- return;
-
- ui::ScrollEvent event(theEvent);
- [self adjustUiEventLocation:&event fromNativeEvent:theEvent];
-
- // Aura updates tooltips with the help of aura::Window::AddPreTargetHandler().
- // Mac hooks in here.
- [self updateTooltipIfRequiredAt:event.location()];
- bridge_->host()->OnScrollEvent(event);
-}
-
-// Called when we get a three-finger swipe, and they're enabled in System
-// Preferences.
-- (void)swipeWithEvent:(NSEvent*)event {
- if (!bridge_)
- return;
-
- // themblsha: In my testing all three-finger swipes send only a single event
- // with a value of +/-1 on either axis. Diagonal swipes are not handled by
- // AppKit.
-
- // We need to invert deltas in order to match GestureEventDetails's
- // directions.
- ui::GestureEventDetails swipeDetails(ui::ET_GESTURE_SWIPE, -[event deltaX],
- -[event deltaY]);
- swipeDetails.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD);
- swipeDetails.set_touch_points(3);
-
- gfx::PointF location = ui::EventLocationFromNative(event);
- // Note this uses the default unique_touch_event_id of 0 (Swipe events do not
- // support -[NSEvent eventNumber]). This doesn't seem like a real omission
- // because the three-finger swipes are instant and can't be tracked anyway.
- ui::GestureEvent gestureEvent(location.x(), location.y(),
- ui::EventFlagsFromNative(event),
- ui::EventTimeFromNative(event), swipeDetails);
- bridge_->host()->OnGestureEvent(gestureEvent);
-}
-
-- (void)quickLookWithEvent:(NSEvent*)theEvent {
- if (!bridge_)
- return;
-
- const gfx::Point locationInContent =
- gfx::ToFlooredPoint(ui::EventLocationFromNative(theEvent));
-
- bool foundWord = false;
- gfx::DecoratedText decoratedWord;
- gfx::Point baselinePoint;
- bridge_->host()->GetWordAt(locationInContent, &foundWord, &decoratedWord,
- &baselinePoint);
- if (!foundWord)
- return;
-
- NSPoint baselinePointAppKit = NSMakePoint(
- baselinePoint.x(), NSHeight([self frame]) - baselinePoint.y());
- [self showDefinitionForAttributedString:
- gfx::GetAttributedStringFromDecoratedText(decoratedWord)
- atPoint:baselinePointAppKit];
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// NSResponder Action Messages. Keep sorted according NSResponder.h (from the
-// 10.9 SDK). The list should eventually be complete. Anything not defined will
-// beep when interpretKeyEvents: would otherwise call it.
-// TODO(tapted): Make this list complete, except for insert* methods which are
-// dispatched as regular key events in doCommandBySelector:.
-
-// views::Textfields are single-line only, map Paragraph and Document commands
-// to Line. Also, Up/Down commands correspond to beginning/end of line.
-
-// The insertText action message forwards to the TextInputClient unless a menu
-// is active. Note that NSResponder's interpretKeyEvents: implementation doesn't
-// direct insertText: through doCommandBySelector:, so this is still needed to
-// handle the case when inputContext: is nil. When inputContext: returns non-nil
-// text goes directly to insertText:replacementRange:.
-- (void)insertText:(id)text {
- DCHECK_EQ(nil, [self inputContext]);
- [self insertTextInternal:text];
-}
-
-// Selection movement and scrolling.
-
-- (void)moveForward:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_FORWARD
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveRight:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_RIGHT
- keyCode:ui::VKEY_RIGHT
- domCode:ui::DomCode::ARROW_RIGHT
- eventFlags:0];
-}
-
-- (void)moveBackward:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_BACKWARD
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveLeft:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_LEFT
- keyCode:ui::VKEY_LEFT
- domCode:ui::DomCode::ARROW_LEFT
- eventFlags:0];
-}
-
-- (void)moveUp:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_UP
- keyCode:ui::VKEY_UP
- domCode:ui::DomCode::ARROW_UP
- eventFlags:0];
-}
-
-- (void)moveDown:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_DOWN
- keyCode:ui::VKEY_DOWN
- domCode:ui::DomCode::ARROW_DOWN
- eventFlags:0];
-}
-
-- (void)moveWordForward:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_FORWARD
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveWordBackward:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_BACKWARD
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveToBeginningOfLine:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE
- keyCode:ui::VKEY_HOME
- domCode:ui::DomCode::HOME
- eventFlags:0];
-}
-
-- (void)moveToEndOfLine:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE
- keyCode:ui::VKEY_END
- domCode:ui::DomCode::END
- eventFlags:0];
-}
-
-- (void)moveToBeginningOfParagraph:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveToEndOfParagraph:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveToEndOfDocument:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT
- keyCode:ui::VKEY_END
- domCode:ui::DomCode::END
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)moveToBeginningOfDocument:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT
- keyCode:ui::VKEY_HOME
- domCode:ui::DomCode::HOME
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)pageDown:(id)sender {
- // The pageDown: action message is bound to the key combination
- // [Option+PageDown].
- [self handleAction:ui::TextEditCommand::MOVE_PAGE_DOWN
- keyCode:ui::VKEY_NEXT
- domCode:ui::DomCode::PAGE_DOWN
- eventFlags:ui::EF_ALT_DOWN];
-}
-
-- (void)pageUp:(id)sender {
- // The pageUp: action message is bound to the key combination [Option+PageUp].
- [self handleAction:ui::TextEditCommand::MOVE_PAGE_UP
- keyCode:ui::VKEY_PRIOR
- domCode:ui::DomCode::PAGE_UP
- eventFlags:ui::EF_ALT_DOWN];
-}
-
-- (void)moveBackwardAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_BACKWARD_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveForwardAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_FORWARD_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveWordForwardAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_FORWARD_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveWordBackwardAndModifySelection:(id)sender {
- [self
- handleAction:ui::TextEditCommand::MOVE_WORD_BACKWARD_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveUpAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UP
- domCode:ui::DomCode::ARROW_UP
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveDownAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_DOWN
- domCode:ui::DomCode::ARROW_DOWN
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveToBeginningOfLineAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_HOME
- domCode:ui::DomCode::HOME
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveToEndOfLineAndModifySelection:(id)sender {
- [self
- handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_END
- domCode:ui::DomCode::END
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveToBeginningOfParagraphAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_PARAGRAPH_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveToEndOfParagraphAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)moveToEndOfDocumentAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_END_OF_DOCUMENT_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_END
- domCode:ui::DomCode::END
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveToBeginningOfDocumentAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_TO_BEGINNING_OF_DOCUMENT_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_HOME
- domCode:ui::DomCode::HOME
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)pageDownAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_NEXT
- domCode:ui::DomCode::PAGE_DOWN
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)pageUpAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_PRIOR
- domCode:ui::DomCode::PAGE_UP
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveParagraphForwardAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_PARAGRAPH_FORWARD_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_DOWN
- domCode:ui::DomCode::ARROW_DOWN
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveParagraphBackwardAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::
- MOVE_PARAGRAPH_BACKWARD_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_UP
- domCode:ui::DomCode::ARROW_UP
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveWordRight:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_RIGHT
- keyCode:ui::VKEY_RIGHT
- domCode:ui::DomCode::ARROW_RIGHT
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)moveWordLeft:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_LEFT
- keyCode:ui::VKEY_LEFT
- domCode:ui::DomCode::ARROW_LEFT
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)moveRightAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_RIGHT
- domCode:ui::DomCode::ARROW_RIGHT
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveLeftAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_LEFT_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_LEFT
- domCode:ui::DomCode::ARROW_LEFT
- eventFlags:ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveWordRightAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_RIGHT_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_RIGHT
- domCode:ui::DomCode::ARROW_RIGHT
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveWordLeftAndModifySelection:(id)sender {
- [self handleAction:ui::TextEditCommand::MOVE_WORD_LEFT_AND_MODIFY_SELECTION
- keyCode:ui::VKEY_LEFT
- domCode:ui::DomCode::ARROW_LEFT
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)moveToLeftEndOfLine:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveToEndOfLine:sender]
- : [self moveToBeginningOfLine:sender];
-}
-
-- (void)moveToRightEndOfLine:(id)sender {
- IsTextRTL(textInputClient_) ? [self moveToBeginningOfLine:sender]
- : [self moveToEndOfLine:sender];
-}
-
-- (void)moveToLeftEndOfLineAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_)
- ? [self moveToEndOfLineAndModifySelection:sender]
- : [self moveToBeginningOfLineAndModifySelection:sender];
-}
-
-- (void)moveToRightEndOfLineAndModifySelection:(id)sender {
- IsTextRTL(textInputClient_)
- ? [self moveToBeginningOfLineAndModifySelection:sender]
- : [self moveToEndOfLineAndModifySelection:sender];
-}
-
-// Graphical Element transposition
-
-- (void)transpose:(id)sender {
- [self handleAction:ui::TextEditCommand::TRANSPOSE
- keyCode:ui::VKEY_T
- domCode:ui::DomCode::US_T
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-// Deletions.
-
-- (void)deleteForward:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_FORWARD
- keyCode:ui::VKEY_DELETE
- domCode:ui::DomCode::DEL
- eventFlags:0];
-}
-
-- (void)deleteBackward:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_BACKWARD
- keyCode:ui::VKEY_BACK
- domCode:ui::DomCode::BACKSPACE
- eventFlags:0];
-}
-
-- (void)deleteWordForward:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_WORD_FORWARD
- keyCode:ui::VKEY_DELETE
- domCode:ui::DomCode::DEL
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)deleteWordBackward:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_WORD_BACKWARD
- keyCode:ui::VKEY_BACK
- domCode:ui::DomCode::BACKSPACE
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-- (void)deleteToBeginningOfLine:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_TO_BEGINNING_OF_LINE
- keyCode:ui::VKEY_BACK
- domCode:ui::DomCode::BACKSPACE
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)deleteToEndOfLine:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_TO_END_OF_LINE
- keyCode:ui::VKEY_DELETE
- domCode:ui::DomCode::DEL
- eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN];
-}
-
-- (void)deleteToBeginningOfParagraph:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)deleteToEndOfParagraph:(id)sender {
- [self handleAction:ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH
- keyCode:ui::VKEY_UNKNOWN
- domCode:ui::DomCode::NONE
- eventFlags:0];
-}
-
-- (void)yank:(id)sender {
- [self handleAction:ui::TextEditCommand::YANK
- keyCode:ui::VKEY_Y
- domCode:ui::DomCode::US_Y
- eventFlags:ui::EF_CONTROL_DOWN];
-}
-
-// Cancellation.
-
-- (void)cancelOperation:(id)sender {
- [self handleAction:ui::TextEditCommand::INVALID_COMMAND
- keyCode:ui::VKEY_ESCAPE
- domCode:ui::DomCode::ESCAPE
- eventFlags:0];
-}
-
-// Support for Services in context menus.
-// Currently we only support reading and writing plain strings.
-- (id)validRequestorForSendType:(NSString*)sendType
- returnType:(NSString*)returnType {
- BOOL canWrite = [sendType isEqualToString:NSStringPboardType] &&
- [self selectedRange].length > 0;
- BOOL canRead = [returnType isEqualToString:NSStringPboardType];
- // Valid if (sendType, returnType) is either (string, nil), (nil, string),
- // or (string, string).
- BOOL valid = textInputClient_ && ((canWrite && (canRead || !returnType)) ||
- (canRead && (canWrite || !sendType)));
- return valid ? self : [super validRequestorForSendType:sendType
- returnType:returnType];
-}
-
-// NSServicesRequests informal protocol.
-
-- (BOOL)writeSelectionToPasteboard:(NSPasteboard*)pboard types:(NSArray*)types {
- DCHECK([types containsObject:NSStringPboardType]);
- if (!textInputClient_)
- return NO;
-
- gfx::Range selectionRange;
- if (!textInputClient_->GetSelectionRange(&selectionRange))
- return NO;
-
- base::string16 text;
- textInputClient_->GetTextFromRange(selectionRange, &text);
- return [pboard writeObjects:@[ base::SysUTF16ToNSString(text) ]];
-}
-
-- (BOOL)readSelectionFromPasteboard:(NSPasteboard*)pboard {
- NSArray* objects =
- [pboard readObjectsForClasses:@[ [NSString class] ] options:0];
- DCHECK([objects count] == 1);
- [self insertText:[objects lastObject]];
- return YES;
-}
-
-// NSTextInputClient protocol implementation.
-
-// IMPORTANT: Always null-check |textInputClient_|. It can change (or be
-// cleared) in -setTextInputClient:, which requires informing AppKit that the
-// -inputContext has changed and to update its raw pointer. However, the AppKit
-// method which does that may also spin a nested run loop communicating with an
-// IME window and cause it to *use* the exact same NSTextInputClient (i.e.,
-// |self|) that we're trying to invalidate in -setTextInputClient:.
-// See https://crbug.com/817097#c12 for further details on this atrocity.
-
-- (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);
- if (actualRange) {
- // To maintain consistency with NSTextView, return range {0,0} for an out of
- // bounds requested range.
- *actualRange =
- actual_range.IsValid() ? actual_range.ToNSRange() : NSMakeRange(0, 0);
- }
- return substring.empty()
- ? nil
- : [[[NSAttributedString alloc]
- initWithString:base::SysUTF16ToNSString(substring)]
- autorelease];
-}
-
-- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
- NOTIMPLEMENTED();
- return 0;
-}
-
-- (void)doCommandBySelector:(SEL)selector {
- // Like the renderer, handle insert action messages as a regular key dispatch.
- // This ensures, e.g., insertTab correctly changes focus between fields.
- if (keyDownEvent_ && [NSStringFromSelector(selector) hasPrefix:@"insert"])
- return; // Handle in -keyDown:.
-
- if ([self respondsToSelector:selector]) {
- [self performSelector:selector withObject:nil];
- hasUnhandledKeyDownEvent_ = NO;
- return;
- }
-
- // For events that AppKit sends via doCommandBySelector:, first attempt to
- // handle as a Widget accelerator. Forward along the responder chain only if
- // the Widget doesn't handle it.
- if (![self handleUnhandledKeyDownAsKeyEvent])
- [[self nextResponder] doCommandBySelector:selector];
-}
-
-- (NSRect)firstRectForCharacterRange:(NSRange)range
- actualRange:(NSRangePointer)actualNSRange {
- gfx::Range actualRange;
- gfx::Rect rect = GetFirstRectForRangeHelper(textInputClient_,
- gfx::Range(range), &actualRange);
- if (actualNSRange)
- *actualNSRange = actualRange.ToNSRange();
- return gfx::ScreenRectToNSRect(rect);
-}
-
-- (BOOL)hasMarkedText {
- return textInputClient_ && textInputClient_->HasCompositionText();
-}
-
-- (void)insertText:(id)text replacementRange:(NSRange)replacementRange {
- if (!bridge_ || !textInputClient_)
- return;
-
- textInputClient_->DeleteRange(gfx::Range(replacementRange));
- [self insertTextInternal:text];
-}
-
-- (NSRange)markedRange {
- if (!textInputClient_)
- return NSMakeRange(NSNotFound, 0);
-
- gfx::Range range;
- textInputClient_->GetCompositionTextRange(&range);
- return range.ToNSRange();
-}
-
-- (NSRange)selectedRange {
- if (!textInputClient_)
- return NSMakeRange(NSNotFound, 0);
-
- gfx::Range range;
- textInputClient_->GetSelectionRange(&range);
- return range.ToNSRange();
-}
-
-- (void)setMarkedText:(id)text
- selectedRange:(NSRange)selectedRange
- replacementRange:(NSRange)replacementRange {
- if (!textInputClient_)
- return;
-
- if ([text isKindOfClass:[NSAttributedString class]])
- text = [text string];
-
- textInputClient_->DeleteRange(gfx::Range(replacementRange));
- ui::CompositionText composition;
- composition.text = base::SysNSStringToUTF16(text);
- composition.selection = gfx::Range(selectedRange);
-
- // Add an underline with text color and a transparent background to the
- // composition text. TODO(karandeepb): On Cocoa textfields, the target clause
- // of the composition has a thick underlines. The composition text also has
- // discontinous underlines for different clauses. This is also supported in
- // the Chrome renderer. Add code to extract underlines from |text| once our
- // render text implementation supports thick underlines and discontinous
- // underlines for consecutive characters. See http://crbug.com/612675.
- composition.ime_text_spans.push_back(
- ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, [text length],
- ui::ImeTextSpan::Thickness::kThin, SK_ColorTRANSPARENT));
- textInputClient_->SetCompositionText(composition);
- hasUnhandledKeyDownEvent_ = NO;
-}
-
-- (void)unmarkText {
- if (!textInputClient_)
- return;
-
- textInputClient_->ConfirmCompositionText();
- hasUnhandledKeyDownEvent_ = NO;
-}
-
-- (NSArray*)validAttributesForMarkedText {
- return @[];
-}
-
-// NSUserInterfaceValidations protocol implementation.
-
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
- ui::TextEditCommand command = GetTextEditCommandForMenuAction([item action]);
-
- if (command == ui::TextEditCommand::INVALID_COMMAND)
- return NO;
-
- if (textInputClient_)
- return textInputClient_->IsTextEditCommandEnabled(command);
-
- // views::Label does not implement the TextInputClient interface but still
- // needs to intercept the Copy and Select All menu actions.
- if (command != ui::TextEditCommand::COPY &&
- command != ui::TextEditCommand::SELECT_ALL)
- return NO;
-
- bool is_textual = false;
- bridge_->host()->GetIsFocusedViewTextual(&is_textual);
- return is_textual;
-}
-
-// NSDraggingSource protocol implementation.
-
-- (NSDragOperation)draggingSession:(NSDraggingSession*)session
- sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
- return NSDragOperationEvery;
-}
-
-- (void)draggingSession:(NSDraggingSession*)session
- endedAtPoint:(NSPoint)screenPoint
- operation:(NSDragOperation)operation {
- views::DragDropClientMac* client = [self dragDropClient];
- if (client)
- client->EndDrag();
-}
-
-// NSAccessibility informal protocol implementation.
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- return @[ bridge_->host()->GetNativeViewAccessible() ];
- }
-
- return [super accessibilityAttributeValue:attribute];
-}
-
-- (id)accessibilityHitTest:(NSPoint)point {
- return
- [bridge_->host()->GetNativeViewAccessible() accessibilityHitTest:point];
-}
-
-- (id)accessibilityFocusedUIElement {
- if (!bridge_)
- return nil;
- 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
deleted file mode 100644
index 6f1d18d11c4..00000000000
--- a/chromium/ui/views/cocoa/bridged_content_view_touch_bar.mm
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/availability.h"
-#import "base/mac/scoped_nsobject.h"
-#import "base/mac/sdk_forward_declarations.h"
-#include "base/strings/sys_string_conversions.h"
-#import "ui/base/cocoa/touch_bar_forward_declarations.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.h"
-
-namespace {
-
-NSString* const kTouchBarDialogButtonsGroupId =
- @"com.google.chrome-DIALOG-BUTTONS-GROUP";
-NSString* const kTouchBarOKId = @"com.google.chrome-OK";
-NSString* const kTouchBarCancelId = @"com.google.chrome-CANCEL";
-
-} // namespace
-
-@interface BridgedContentView (TouchBarAdditions)<NSTouchBarDelegate>
-- (void)touchBarButtonAction:(id)sender;
-@end
-
-@implementation BridgedContentView (TouchBarAdditions)
-
-- (void)touchBarButtonAction:(id)sender {
- ui::DialogButton type = static_cast<ui::DialogButton>([sender tag]);
- if (bridge_)
- bridge_->host()->DoDialogButtonAction(type);
-}
-
-// NSTouchBarDelegate protocol implementation.
-
-- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
- makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
- API_AVAILABLE(macos(10.12.2)) {
- if (!bridge_)
- return nil;
-
- if ([identifier isEqualToString:kTouchBarDialogButtonsGroupId]) {
- NSMutableArray* items = [NSMutableArray arrayWithCapacity:2];
- for (NSTouchBarItemIdentifier i in @[ kTouchBarCancelId, kTouchBarOKId ]) {
- NSTouchBarItem* item = [self touchBar:touchBar makeItemForIdentifier:i];
- if (item)
- [items addObject:item];
- }
- if ([items count] == 0)
- return nil;
- return [NSClassFromString(@"NSGroupTouchBarItem")
- groupItemWithIdentifier:identifier
- items:items];
- }
-
- ui::DialogButton type = ui::DIALOG_BUTTON_NONE;
- if ([identifier isEqualToString:kTouchBarOKId])
- type = ui::DIALOG_BUTTON_OK;
- else if ([identifier isEqualToString:kTouchBarCancelId])
- type = ui::DIALOG_BUTTON_CANCEL;
- else
- return nil;
-
- 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]);
- NSButton* button =
- [NSButton buttonWithTitle:base::SysUTF16ToNSString(buttonLabel)
- target:self
- action:@selector(touchBarButtonAction:)];
- 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.
- [button setBezelColor:[NSColor colorWithSRGBRed:0.168
- green:0.51
- blue:0.843
- alpha:1.0]];
- }
- [button setEnabled:isButtonEnabled];
- [button setTag:type];
- [item setView:button];
- return item.autorelease();
-}
-
-// NSTouchBarProvider protocol implementation (via NSResponder category).
-
-- (NSTouchBar*)makeTouchBar {
- if (!bridge_)
- return nil;
-
- bool buttonsExist = false;
- bridge_->host()->GetDoDialogButtonsExist(&buttonsExist);
- if (!buttonsExist)
- return nil;
-
- base::scoped_nsobject<NSTouchBar> bar(
- [[NSClassFromString(@"NSTouchBar") alloc] init]);
- [bar setDelegate:self];
-
- // Use a group rather than individual items so they can be centered together.
- [bar setDefaultItemIdentifiers:@[ kTouchBarDialogButtonsGroupId ]];
-
- // Setting the group as principal will center it in the TouchBar.
- [bar setPrincipalItemIdentifier:kTouchBarDialogButtonsGroupId];
- return bar.autorelease();
-}
-
-@end
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.h b/chromium/ui/views/cocoa/bridged_native_widget.h
deleted file mode 100644
index 6d2d12e6455..00000000000
--- a/chromium/ui/views/cocoa/bridged_native_widget.h
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
-#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-#include <vector>
-
-#import "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#include "ui/accelerated_widget_mac/ca_transaction_observer.h"
-#include "ui/accelerated_widget_mac/display_ca_layer_tree.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_bridge_mac/mojo/bridged_native_widget.mojom.h"
-
-@class BridgedContentView;
-@class ModalShowAnimationWithLayer;
-@class NativeWidgetMacNSWindow;
-@class ViewsNSWindowDelegate;
-
-namespace views {
-namespace test {
-class BridgedNativeWidgetTestApi;
-}
-
-class BridgedNativeWidgetHost;
-class CocoaMouseCapture;
-class CocoaWindowMoveLoop;
-class DragDropClientMac;
-class NativeWidgetMac;
-class View;
-
-// A bridge to an NSWindow managed by an instance of NativeWidgetMac or
-// 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 views_bridge_mac::mojom::BridgedNativeWidget,
- public display::DisplayObserver,
- public ui::CATransactionCoordinator::PreCommitObserver,
- public CocoaMouseCaptureDelegate,
- public BridgedNativeWidgetOwner {
- public:
- // Contains NativeViewHost->gfx::NativeView associations.
- using AssociatedViews = std::map<const views::View*, NSView*>;
-
- // 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. |host| and |parent| must not be NULL.
- BridgedNativeWidget(BridgedNativeWidgetHost* host, NativeWidgetMac* parent);
- ~BridgedNativeWidget() override;
-
- // 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);
-
- // 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);
-
- // 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,
- // 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& new_bounds);
-
- // 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.
- Widget::MoveLoopResult RunMoveLoop(const gfx::Vector2d& drag_offset);
- void EndMoveLoop();
-
- // See views::Widget.
- void SetNativeWindowProperty(const char* key, void* value);
- void* GetNativeWindowProperty(const char* key) const;
-
- // Sets the cursor associated with the NSWindow. Retains |cursor|.
- void SetCursor(NSCursor* cursor);
-
- // Called internally by the NSWindowDelegate when the window is closing.
- void OnWindowWillClose();
-
- // Called by the NSWindowDelegate when a fullscreen operation begins. If
- // |target_fullscreen_state| is true, the target state is fullscreen.
- // Otherwise, a transition has begun to come out of fullscreen.
- void OnFullscreenTransitionStart(bool target_fullscreen_state);
-
- // Called when a fullscreen transition completes. If target_fullscreen_state()
- // does not match |actual_fullscreen_state|, a new transition will begin.
- void OnFullscreenTransitionComplete(bool actual_fullscreen_state);
-
- // Transition the window into or out of fullscreen. This will immediately
- // invert the value of target_fullscreen_state().
- void ToggleDesiredFullscreenState(bool async = false);
-
- // Called by the NSWindowDelegate when the size of the window changes.
- void OnSizeChanged();
-
- // Called once by the NSWindowDelegate when the position of the window has
- // changed.
- void OnPositionChanged();
-
- // Called by the NSWindowDelegate when the visibility of the window may have
- // changed. For example, due to a (de)miniaturize operation, or the window
- // being reordered in (or out of) the screen list.
- void OnVisibilityChanged();
-
- // Called by the NSWindowDelegate when the system control tint changes.
- void OnSystemControlTintChanged();
-
- // Called by the NSWindowDelegate on a scale factor or color space change.
- void OnBackingPropertiesChanged();
-
- // Called by the NSWindowDelegate when the window becomes or resigns key.
- void OnWindowKeyStatusChangedTo(bool is_key);
-
- // Called by the window show animation when it completes and wants to destroy
- // itself.
- void OnShowAnimationComplete();
-
- // Updates |associated_views_| on NativeViewHost::Attach()/Detach().
- void SetAssociationForView(const views::View* view, NSView* native_view);
- void ClearAssociationForView(const views::View* view);
- // Sorts child NSViews according to NativeViewHosts order in views hierarchy.
- void ReorderChildViews();
-
- NativeWidgetMac* native_widget_mac() { return native_widget_mac_; }
- BridgedContentView* ns_view() { return bridged_view_; }
- 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
- // raised above their parent when window z-order changes.
- BridgedNativeWidgetOwner* parent() { return parent_; }
- const std::vector<BridgedNativeWidget*>& child_windows() {
- return child_windows_;
- }
-
- // Re-parent a |native_view| in this Widget to be a child of |new_parent|.
- // |native_view| must either be |ns_view()| or a descendant of |ns_view()|.
- // |native_view| is added as a subview of |new_parent| unless it is the
- // contentView of a top-level Widget. If |native_view| is |ns_view()|, |this|
- // also becomes a child window of |new_parent|'s NSWindow.
- void ReparentNativeView(NSView* native_view, NSView* new_parent);
-
- bool target_fullscreen_state() const { return target_fullscreen_state_; }
- bool window_visible() const { return window_visible_; }
- bool wants_to_be_visible() const { return wants_to_be_visible_; }
- bool in_fullscreen_transition() const { return in_fullscreen_transition_; }
-
- // Enables or disables all window animations.
- void SetAnimationEnabled(bool animate);
-
- // Sets which transitions will animate. Currently this only affects non-native
- // animations. TODO(tapted): Use scoping to disable native animations at
- // appropriate times as well.
- void set_transitions_to_animate(int transitions) {
- transitions_to_animate_ = transitions;
- }
-
- // Whether to run a custom animation for the provided |transition|.
- bool ShouldRunCustomAnimationFor(
- Widget::VisibilityTransition transition) const;
-
- // display::DisplayObserver:
- void OnDisplayMetricsChanged(const display::Display& display,
- uint32_t metrics) override;
-
- // ui::CATransactionCoordinator::PreCommitObserver:
- bool ShouldWaitInPreCommit() override;
- base::TimeDelta PreCommitTimeout() 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;
-
- // Closes all child windows. BridgedNativeWidget children will be destroyed.
- void RemoveOrDestroyChildren();
-
- // Notify descendants of a visibility change.
- void NotifyVisibilityChangeDown();
-
- // Installs the NSView for hosting the composited layer.
- void AddCompositorSuperview();
-
- // Query the display properties of the monitor that |window_| is on, and
- // forward them to |host_|.
- void UpdateWindowDisplay();
-
- // 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();
-
- // Returns true if capture exists and is currently active.
- bool HasCapture();
-
- // CocoaMouseCaptureDelegate:
- void PostCapturedEvent(NSEvent* event) override;
- void OnMouseCaptureLost() override;
- NSWindow* GetWindow() const override;
-
- // Returns a properties dictionary associated with the NSWindow.
- // Creates and attaches a new instance if not found.
- NSMutableDictionary* GetWindowProperties() const;
-
- // BridgedNativeWidgetOwner:
- NSWindow* GetNSWindow() override;
- gfx::Vector2d GetChildWindowOffset() const override;
- bool IsVisibleParent() const override;
- void RemoveChildWindow(BridgedNativeWidget* child) override;
-
- 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<CocoaMouseCapture> mouse_capture_;
- std::unique_ptr<CocoaWindowMoveLoop> window_move_loop_;
- std::unique_ptr<TooltipManager> tooltip_manager_;
- std::unique_ptr<DragDropClientMac> drag_drop_client_;
- ui::ModalType modal_type_ = ui::MODAL_TYPE_NONE;
- bool is_translucent_window_ = false;
-
- 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_;
-
- // 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_;
-
- // 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_ = false;
-
- // Whether this window is in a fullscreen transition, and the fullscreen state
- // can not currently be changed.
- bool in_fullscreen_transition_ = false;
-
- // Stores the value last read from -[NSWindow isVisible], to detect visibility
- // changes.
- 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_ = false;
-
- // If true, then ignore interactions with CATransactionCoordinator until the
- // first frame arrives.
- bool ca_transaction_sync_suppressed_ = false;
-
- // If true, the window has been made visible or changed shape and the window
- // shadow needs to be invalidated when a frame is received for the new shape.
- bool invalidate_shadow_on_frame_swap_ = false;
-
- AssociatedViews associated_views_;
-
- DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidget);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_H_
diff --git a/chromium/ui/views/cocoa/bridged_native_widget.mm b/chromium/ui/views/cocoa/bridged_native_widget.mm
deleted file mode 100644
index abdbcc45fab..00000000000
--- a/chromium/ui/views/cocoa/bridged_native_widget.mm
+++ /dev/null
@@ -1,1283 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/bridged_native_widget.h"
-
-#import <objc/runtime.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#import "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#import "base/mac/sdk_forward_declarations.h"
-#include "base/single_thread_task_runner.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/layout.h"
-#include "ui/base/ui_base_switches.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/widget/native_widget_mac.h"
-#include "ui/views/widget/widget.h"
-
-using views_bridge_mac::mojom::WindowVisibilityState;
-
-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.
-@interface ViewsCompositorSuperview : NSView
-@end
-
-@implementation ViewsCompositorSuperview
-- (NSView*)hitTest:(NSPoint)aPoint {
- return nil;
-}
-@end
-
-// This class overrides NSAnimation methods to invalidate the shadow for each
-// frame. It is required because the show animation uses CGSSetWindowWarp()
-// which is touchy about the consistency of the points it is given. The show
-// animation includes a translate, which fails to apply properly to the window
-// shadow, when that shadow is derived from a layer-hosting view. So invalidate
-// it. This invalidation is only needed to cater for the translate. It is not
-// required if CGSSetWindowWarp() is used in a way that keeps the center point
-// of the window stationary (e.g. a scale). It's also not required for the hide
-// animation: in that case, the shadow is never invalidated so retains the
-// shadow calculated before a translate is applied.
-@interface ModalShowAnimationWithLayer
- : ConstrainedWindowAnimationShow<NSAnimationDelegate>
-@end
-
-@implementation ModalShowAnimationWithLayer {
- // This is the "real" delegate, but this class acts as the NSAnimationDelegate
- // to avoid a separate object.
- views::BridgedNativeWidget* bridgedNativeWidget_;
-}
-- (instancetype)initWithBridgedNativeWidget:
- (views::BridgedNativeWidget*)widget {
- if ((self = [super initWithWindow:widget->ns_window()])) {
- bridgedNativeWidget_ = widget;
- [self setDelegate:self];
- }
- return self;
-}
-- (void)dealloc {
- DCHECK(!bridgedNativeWidget_);
- [super dealloc];
-}
-- (void)animationDidEnd:(NSAnimation*)animation {
- DCHECK(bridgedNativeWidget_);
- bridgedNativeWidget_->OnShowAnimationComplete();
- bridgedNativeWidget_ = nullptr;
- [self setDelegate:nil];
-}
-- (void)stopAnimation {
- [super stopAnimation];
- [window_ invalidateShadow];
-}
-- (void)setCurrentProgress:(NSAnimationProgress)progress {
- [super setCurrentProgress:progress];
- [window_ invalidateShadow];
-}
-@end
-
-namespace {
-
-using RankMap = std::map<NSView*, int>;
-
-// SDK 10.11 contains incompatible changes of sortSubviewsUsingFunction.
-// It takes (__kindof NSView*) as comparator argument.
-// https://llvm.org/bugs/show_bug.cgi?id=25149
-#if !defined(MAC_OS_X_VERSION_10_11) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
-using NSViewComparatorValue = id;
-#else
-using NSViewComparatorValue = __kindof NSView*;
-#endif
-
-int kWindowPropertiesKey;
-
-// Returns true if the content_view is reparented.
-bool PositionWindowInNativeViewParent(NSView* content_view) {
- return [[content_view window] contentView] != content_view;
-}
-
-// Return the offset of the parent native view from the window.
-gfx::Vector2d GetNativeViewParentOffset(NSView* content_view) {
- NSWindow* window = [content_view window];
- NSView* parent_view = [content_view superview];
- NSPoint p = NSMakePoint(0, NSHeight([parent_view frame]));
- p = [parent_view convertPoint:p toView:nil];
- return gfx::Vector2d(p.x, NSHeight([window frame]) - p.y);
-}
-
-// Return the content size for a minimum or maximum widget size.
-gfx::Size GetClientSizeForWindowSize(NSWindow* window,
- const gfx::Size& window_size) {
- NSRect frame_rect =
- NSMakeRect(0, 0, window_size.width(), window_size.height());
- // Note gfx::Size will prevent dimensions going negative. They are allowed to
- // be zero at this point, because Widget::GetMinimumSize() may later increase
- // the size.
- return gfx::Size([window contentRectForFrameRect:frame_rect].size);
-}
-
-void RankNSViews(views::View* view,
- const views::BridgedNativeWidget::AssociatedViews& hosts,
- RankMap* rank) {
- auto it = hosts.find(view);
- if (it != hosts.end())
- rank->emplace(it->second, rank->size());
- for (int i = 0; i < view->child_count(); ++i)
- RankNSViews(view->child_at(i), hosts, rank);
-}
-
-NSComparisonResult SubviewSorter(NSViewComparatorValue lhs,
- NSViewComparatorValue rhs,
- void* rank_as_void) {
- DCHECK_NE(lhs, rhs);
-
- const RankMap* rank = static_cast<const RankMap*>(rank_as_void);
- auto left_rank = rank->find(lhs);
- auto right_rank = rank->find(rhs);
- bool left_found = left_rank != rank->end();
- bool right_found = right_rank != rank->end();
-
- // Sort unassociated views above associated views.
- if (left_found != right_found)
- return left_found ? NSOrderedAscending : NSOrderedDescending;
-
- if (left_found) {
- return left_rank->second < right_rank->second ? NSOrderedAscending
- : NSOrderedDescending;
- }
-
- // If both are unassociated, consider that order is not important
- return NSOrderedSame;
-}
-
-// Counts windows managed by a BridgedNativeWidget instance in the
-// |child_windows| array ignoring the windows added by AppKit.
-NSUInteger CountBridgedWindows(NSArray* child_windows) {
- NSUInteger count = 0;
- for (NSWindow* child in child_windows)
- if ([[child delegate] isKindOfClass:[ViewsNSWindowDelegate class]])
- ++count;
-
- return count;
-}
-
-} // namespace
-
-namespace views {
-
-// static
-gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize(
- NSWindow* window,
- const gfx::Size& content_size) {
- NSRect content_rect =
- NSMakeRect(0, 0, content_size.width(), content_size.height());
- NSRect frame_rect = [window frameRectForContentRect:content_rect];
- return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
-}
-
-BridgedNativeWidget::BridgedNativeWidget(BridgedNativeWidgetHost* host,
- NativeWidgetMac* parent)
- : host_(host), native_widget_mac_(parent) {
- DCHECK(parent);
- window_delegate_.reset(
- [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
- ui::CATransactionCoordinator::Get().AddPreCommitObserver(this);
-}
-
-BridgedNativeWidget::~BridgedNativeWidget() {
- // The delegate should be cleared already. Note this enforces the precondition
- // that -[NSWindow close] is invoked on the hosted window before the
- // destructor is called.
- DCHECK(![window_ delegate]);
-
- ui::CATransactionCoordinator::Get().RemovePreCommitObserver(this);
- RemoveOrDestroyChildren();
- DCHECK(child_windows_.empty());
- DestroyContentView();
-}
-
-void BridgedNativeWidget::SetWindow(
- base::scoped_nsobject<NativeWidgetMacNSWindow> window) {
- DCHECK(!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
- // tied to the C++ object, rather than the delegate (which may be reference
- // counted). This is required since the application hides do not send an
- // orderOut: to individual windows. Unhide, however, does send an order
- // message.
- [[NSNotificationCenter defaultCenter]
- addObserver:window_delegate_
- selector:@selector(onWindowOrderChanged:)
- name:NSApplicationDidHideNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter]
- addObserver:window_delegate_
- selector:@selector(onSystemControlTintChanged:)
- name:NSControlTintDidChangeNotification
- object:nil];
-
- // Validate the window's initial state, otherwise the bridge's initial
- // tracking state will be incorrect.
- DCHECK(![window_ isVisible]);
- DCHECK_EQ(0u, [window_ styleMask] & NSFullScreenWindowMask);
-
- // Include "regular" windows without the standard frame in the window cycle.
- // These use NSBorderlessWindowMask so do not get it by default.
- if (params->force_into_collection_cycle) {
- [window_
- setCollectionBehavior:[window_ collectionBehavior] |
- NSWindowCollectionBehaviorParticipatesInCycle];
- }
-
- [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(new_bounds.origin().IsOrigin())
- << "Zero-sized windows not supported on Mac.";
-
- // Otherwise, bounds is all zeroes. Cocoa will currently have the window at
- // the bottom left of the screen. To support a client calling SetSize() only
- // (and for consistency across platforms) put it at the top-left instead.
- // 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];
- adjusted_bounds = gfx::Rect(
- gfx::Point(), gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)));
- }
- adjusted_bounds.Offset(bounds_offset_for_parent);
- SetBounds(adjusted_bounds, minimum_content_size);
-}
-
-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(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_ && 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(),
- clamped_content_size.height())];
- return;
- }
- gfx::Rect actual_new_bounds(
- new_bounds.origin(),
- GetWindowSizeForClientSize(window_, clamped_content_size));
-
- if (PositionWindowInNativeViewParent(bridged_view_))
- actual_new_bounds.Offset(GetNativeViewParentOffset(bridged_view_));
-
- [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds)
- display:YES
- animate:NO];
-}
-
-void BridgedNativeWidget::DestroyContentView() {
- if (!bridged_view_)
- return;
- drag_drop_client_.reset();
- [bridged_view_ clearView];
- bridged_view_.reset();
- [window_ setContentView:nil];
-}
-
-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_);
-
- 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.
- [bridged_view_ setWantsLayer:YES];
-
- [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 != WindowVisibilityState::kHideWindow;
-
- [show_animation_ stopAnimation];
- DCHECK(!show_animation_);
-
- 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
- // -setIgnoresMouseEvents:YES on the NSWindow, or dismiss the sheet before
- // hiding.
- //
- // TODO(ellyjones): Sort this entire situation out. This DCHECK doesn't
- // trigger in shipped builds, but it does trigger when the browser exits
- // "abnormally" (not via one of the UI paths to exiting), such as in browser
- // tests, so this breaks a slew of browser tests in MacViews mode. See also
- // https://crbug.com/834926.
- // DCHECK(![window_ attachedSheet]);
-
- [window_ orderOut:nil];
- DCHECK(!window_visible_);
- return;
- }
-
- DCHECK(wants_to_be_visible_);
-
- if (!ca_transaction_sync_suppressed_)
- ui::CATransactionCoordinator::Get().Synchronize();
-
- // If the parent (or an ancestor) is hidden, return and wait for it to become
- // visible.
- if (parent() && !parent()->IsVisibleParent())
- return;
-
- if (IsWindowModalSheet()) {
- ShowAsModalSheet();
- return;
- }
-
- if (new_state == WindowVisibilityState::kShowAndActivateWindow) {
- [window_ makeKeyAndOrderFront:nil];
- [NSApp activateIgnoringOtherApps:YES];
- } else {
- // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a
- // parent window. So, if there's a parent, order above that. Otherwise, this
- // will order above all windows at the same level.
- NSInteger parent_window_number = 0;
- if (parent_) {
- // When there's a parent, check if the window is already visible. If
- // ShowInactive() is called on an already-visible window, there should be
- // no effect: the macOS childWindow mechanism should have already raised
- // the window to the right stacking order. More importantly, invoking
- // -[NSWindow orderWindow:] could cause a Space switch, which defeats the
- // point of ShowInactive(), so avoid it. See https://crbug.com/866760.
-
- // Sanity check: if the window is visible, the prior Show should have
- // hooked it up as a native child window already.
- DCHECK_EQ(window_visible_, !![window_ parentWindow]);
- if (window_visible_)
- return; // Avoid a Spaces transition.
-
- parent_window_number = [parent_->GetNSWindow() windowNumber];
- }
-
- [window_ orderWindow:NSWindowAbove
- relativeTo:parent_window_number];
- }
- DCHECK(window_visible_);
-
- // For non-sheet modal types, use the constrained window animations to make
- // the window appear.
- if (ShouldRunCustomAnimationFor(Widget::ANIMATE_SHOW)) {
- show_animation_.reset(
- [[ModalShowAnimationWithLayer alloc] initWithBridgedNativeWidget:this]);
-
- // The default mode is blocking, which would block the UI thread for the
- // duration of the animation, but would keep it smooth. The window also
- // hasn't yet received a frame from the compositor at this stage, so it is
- // fully transparent until the GPU sends a frame swap IPC. For the blocking
- // option, the animation needs to wait until
- // AcceleratedWidgetCALayerParamsUpdated has been called at least once,
- // otherwise it will animate nothing.
- [show_animation_ setAnimationBlockingMode:NSAnimationNonblocking];
- [show_animation_ startAnimation];
- }
-}
-
-void BridgedNativeWidget::AcquireCapture() {
- 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
- // here will restore what we want. However, it can sometimes cause the cursor
- // to flicker, once, on the initial mouseDown.
- // TODO(tapted): Make this unnecessary by only asking for global mouse capture
- // for the cases that need it (e.g. menus, but not drag and drop).
- [window_ cursorUpdate:[NSApp currentEvent]];
-}
-
-void BridgedNativeWidget::ReleaseCapture() {
- mouse_capture_.reset();
-}
-
-bool BridgedNativeWidget::HasCapture() {
- return mouse_capture_ && mouse_capture_->IsActive();
-}
-
-Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop(
- const gfx::Vector2d& drag_offset) {
- DCHECK(!HasCapture());
- DCHECK(!window_move_loop_);
-
- // RunMoveLoop caller is responsible for updating the window to be under the
- // mouse, but it does this using possibly outdated coordinate from the mouse
- // event, and mouse is very likely moved beyound that point.
-
- // Compensate for mouse drift by shifting the initial mouse position we pass
- // to CocoaWindowMoveLoop, so as it handles incoming move events the window's
- // top left corner will be |drag_offset| from the current mouse position.
-
- const gfx::Rect frame = gfx::ScreenRectFromNSRect([window_ frame]);
- const gfx::Point mouse_in_screen(frame.x() + drag_offset.x(),
- frame.y() + drag_offset.y());
- window_move_loop_.reset(new CocoaWindowMoveLoop(
- this, gfx::ScreenPointToNSPoint(mouse_in_screen)));
-
- return window_move_loop_->Run();
-
- // |this| may be destroyed during the RunLoop, causing it to exit early.
- // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by
- // calling EndMoveLoop(). So window_move_loop_ will always be null before the
- // function returns. But don't DCHECK since |this| might not be valid.
-}
-
-void BridgedNativeWidget::EndMoveLoop() {
- DCHECK(window_move_loop_);
- window_move_loop_->End();
- window_move_loop_.reset();
-}
-
-void BridgedNativeWidget::SetNativeWindowProperty(const char* name,
- void* value) {
- NSString* key = [NSString stringWithUTF8String:name];
- if (value) {
- [GetWindowProperties() setObject:[NSValue valueWithPointer:value]
- forKey:key];
- } else {
- [GetWindowProperties() removeObjectForKey:key];
- }
-}
-
-void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const {
- NSString* key = [NSString stringWithUTF8String:name];
- return [[GetWindowProperties() objectForKey:key] pointerValue];
-}
-
-void BridgedNativeWidget::SetCursor(NSCursor* cursor) {
- [window_delegate_ setCursor:cursor];
-}
-
-void BridgedNativeWidget::OnWindowWillClose() {
- host_->OnWindowWillClose();
-
- // Ensure BridgedNativeWidget does not have capture, otherwise
- // 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();
-
- if (parent_) {
- parent_->RemoveChildWindow(this);
- parent_ = nullptr;
- }
- [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
-
- [show_animation_ stopAnimation]; // If set, calls OnShowAnimationComplete().
- DCHECK(!show_animation_);
-
- [window_ setDelegate:nil];
- host_->OnWindowHasClosed();
- // Note: |this| and its host will be deleted here.
-}
-
-void BridgedNativeWidget::OnFullscreenTransitionStart(
- bool target_fullscreen_state) {
- // Note: This can fail for fullscreen changes started externally, but a user
- // shouldn't be able to do that if the window is invisible to begin with.
- DCHECK(window_visible_);
-
- DCHECK_NE(target_fullscreen_state, target_fullscreen_state_);
- target_fullscreen_state_ = target_fullscreen_state;
- in_fullscreen_transition_ = true;
-
- host_->OnWindowFullscreenTransitionStart(target_fullscreen_state);
-}
-
-void BridgedNativeWidget::OnFullscreenTransitionComplete(
- bool actual_fullscreen_state) {
- in_fullscreen_transition_ = false;
-
- if (target_fullscreen_state_ == actual_fullscreen_state) {
- host_->OnWindowFullscreenTransitionComplete(actual_fullscreen_state);
- return;
- }
-
- // The transition completed, but into the wrong state. This can happen when
- // there are calls to change the fullscreen state whilst mid-transition.
- // First update to reflect reality so that OnTargetFullscreenStateChanged()
- // expects the change.
- target_fullscreen_state_ = actual_fullscreen_state;
- ToggleDesiredFullscreenState(true /* async */);
-}
-
-void BridgedNativeWidget::ToggleDesiredFullscreenState(bool async) {
- // If there is currently an animation into or out of fullscreen, then AppKit
- // emits the string "not in fullscreen state" to stdio and does nothing. For
- // this case, schedule a transition back into the desired state when the
- // animation completes.
- if (in_fullscreen_transition_) {
- target_fullscreen_state_ = !target_fullscreen_state_;
- return;
- }
-
- // Going fullscreen implicitly makes the window visible. AppKit does this.
- // That is, -[NSWindow isVisible] is always true after a call to -[NSWindow
- // toggleFullScreen:]. Unfortunately, this change happens after AppKit calls
- // -[NSWindowDelegate windowWillEnterFullScreen:], and AppKit doesn't send an
- // orderWindow message. So intercepting the implicit change is hard.
- // Luckily, to trigger externally, the window typically needs to be visible in
- // the first place. So we can just ensure the window is visible here instead
- // 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(WindowVisibilityState::kShowInactive);
-
- // Enable fullscreen collection behavior because:
- // 1: -[NSWindow toggleFullscreen:] would otherwise be ignored,
- // 2: the fullscreen button must be enabled so the user can leave fullscreen.
- // This will be reset when a transition out of fullscreen completes.
- gfx::SetNSWindowCanFullscreen(window_, true);
-
- // Until 10.13, AppKit would obey a call to -toggleFullScreen: made inside
- // OnFullscreenTransitionComplete(). Starting in 10.13, it behaves as though
- // the transition is still in progress and just emits "not in a fullscreen
- // state" when trying to exit fullscreen in the same runloop that entered it.
- // To handle this case, invoke -toggleFullScreen: asynchronously.
- if (async) {
- [window_ performSelector:@selector(toggleFullScreen:)
- 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() {
- UpdateWindowGeometry();
-}
-
-void BridgedNativeWidget::OnPositionChanged() {
- UpdateWindowGeometry();
-}
-
-void BridgedNativeWidget::OnVisibilityChanged() {
- const bool window_visible = [window_ isVisible];
- if (window_visible_ == window_visible)
- return;
-
- window_visible_ = window_visible;
-
- // If arriving via SetVisible(), |wants_to_be_visible_| should already be set.
- // If made visible externally (e.g. Cmd+H), just roll with it. Don't try (yet)
- // to distinguish being *hidden* externally from being hidden by a parent
- // window - we might not need that.
- if (window_visible_) {
- wants_to_be_visible_ = true;
-
- // Sheets don't need a parentWindow set, and setting one causes graphical
- // glitches (http://crbug.com/605098).
- if (parent_ && ![window_ isSheet])
- [parent_->GetNSWindow() addChildWindow:window_ ordered:NSWindowAbove];
- } else {
- ReleaseCapture(); // Capture on hidden windows is not permitted.
-
- // When becoming invisible, remove the entry in any parent's childWindow
- // list. Cocoa's childWindow management breaks down when child windows are
- // hidden.
- if (parent_)
- [parent_->GetNSWindow() removeChildWindow:window_];
- }
-
- // Showing a translucent window after hiding it should trigger shadow
- // invalidation.
- if (window_visible && ![window_ isOpaque])
- invalidate_shadow_on_frame_swap_ = true;
-
- NotifyVisibilityChangeDown();
- 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
- // prevents Cocoa drawing just *after* a minimize, resulting in a blank window
- // represented in the deminiaturize animation.
- [window_ setAutodisplay:window_visible_];
-}
-
-void BridgedNativeWidget::OnSystemControlTintChanged() {
- ui::NativeTheme::GetInstanceForNativeUi()->NotifyObservers();
-}
-
-void BridgedNativeWidget::OnBackingPropertiesChanged() {
- UpdateWindowDisplay();
-}
-
-void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) {
- host_->OnWindowKeyStatusChanged(
- is_key, [window_ contentView] == [window_ firstResponder],
- [NSApp isFullKeyboardAccessEnabled]);
-}
-
-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;
-
- bool shows_resize_controls =
- is_resizable && (min_size.IsEmpty() || min_size != max_size);
- bool shows_fullscreen_controls = is_resizable && is_maximizable;
-
- gfx::ApplyNSWindowSizeConstraints(window_, min_size, max_size,
- shows_resize_controls,
- shows_fullscreen_controls);
-}
-
-void BridgedNativeWidget::OnShowAnimationComplete() {
- show_animation_.reset();
-}
-
-void BridgedNativeWidget::InitCompositorView() {
- AddCompositorSuperview();
-
- // 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 (is_translucent_window_ && !IsWindowModalSheet()) {
- [window_ setOpaque:NO];
- [window_ setBackgroundColor:[NSColor clearColor]];
-
- // Don't block waiting for the initial frame of completely transparent
- // windows. This allows us to avoid blocking on the UI thread e.g, while
- // typing in the omnibox. Note window modal sheets _must_ wait: there is no
- // way for a frame to arrive during AppKit's sheet animation.
- // https://crbug.com/712268
- ca_transaction_sync_suppressed_ = true;
- } else {
- DCHECK(!ca_transaction_sync_suppressed_);
- }
-
- // Send the initial window geometry and screen properties. Any future changes
- // will be forwarded.
- UpdateWindowDisplay();
- UpdateWindowGeometry();
-}
-
-void BridgedNativeWidget::SetAssociationForView(const views::View* view,
- NSView* native_view) {
- DCHECK_EQ(0u, associated_views_.count(view));
- associated_views_[view] = native_view;
- native_widget_mac_->GetWidget()->ReorderNativeViews();
-}
-
-void BridgedNativeWidget::ClearAssociationForView(const views::View* view) {
- auto it = associated_views_.find(view);
- DCHECK(it != associated_views_.end());
- associated_views_.erase(it);
-}
-
-void BridgedNativeWidget::ReorderChildViews() {
- // Ignore layer manipulation during a Close(). This can be reached during the
- // orderOut: in Close(), which notifies visibility changes to Views.
- if (!bridged_view_)
- return;
-
- RankMap rank;
- Widget* widget = native_widget_mac_->GetWidget();
- RankNSViews(widget->GetRootView(), associated_views_, &rank);
- // Unassociated NSViews should be ordered above associated ones. The exception
- // is the UI compositor's superview, which should always be on the very
- // bottom, so give it an explicit negative rank.
- if (compositor_superview_)
- rank[compositor_superview_] = -1;
- [bridged_view_ sortSubviewsUsingFunction:&SubviewSorter context:&rank];
-}
-
-void BridgedNativeWidget::ReparentNativeView(NSView* native_view,
- NSView* new_parent) {
- DCHECK([new_parent window]);
- DCHECK([native_view isDescendantOf:bridged_view_]);
- DCHECK(window_ && ![window_ isSheet]);
-
- BridgedNativeWidget* parent_bridge =
- NativeWidgetMac::GetBridgeForNativeWindow([new_parent window]);
- if (native_view == bridged_view_.get() && parent_bridge != 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];
- }
-
- if (!native_widget_mac_->GetWidget()->is_top_level() ||
- native_view != bridged_view_.get()) {
- // Make native_view be a child of new_parent by adding it as a subview.
- // The window_ must remain visible because it controls the bounds and
- // visibility of the ui::Layer. So just hide it by setting alpha value to
- // zero.
- [new_parent addSubview:native_view];
- if (native_view == bridged_view_.get()) {
- [window_ setAlphaValue:0];
- [window_ setIgnoresMouseEvents:YES];
- }
- }
-}
-
-void BridgedNativeWidget::SetAnimationEnabled(bool animate) {
- [window_
- setAnimationBehavior:(animate ? NSWindowAnimationBehaviorDocumentWindow
- : NSWindowAnimationBehaviorNone)];
-}
-
-bool BridgedNativeWidget::ShouldRunCustomAnimationFor(
- Widget::VisibilityTransition transition) const {
- // The logic around this needs to change if new transition types are set.
- // E.g. it would be nice to distinguish "hide" from "close". Mac currently
- // treats "hide" only as "close". Hide (e.g. Cmd+h) should not animate on Mac.
- 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
-
-void BridgedNativeWidget::OnDisplayMetricsChanged(
- const display::Display& display,
- uint32_t metrics) {
- UpdateWindowDisplay();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, ui::CATransactionObserver
-
-bool BridgedNativeWidget::ShouldWaitInPreCommit() {
- if (!window_visible_)
- return false;
- if (ca_transaction_sync_suppressed_)
- return false;
- if (!compositor_superview_)
- return false;
- return content_dip_size_ != compositor_frame_dip_size_;
-}
-
-base::TimeDelta BridgedNativeWidget::PreCommitTimeout() {
- return kUIPaintTimeout;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, CocoaMouseCaptureDelegate:
-
-void BridgedNativeWidget::PostCapturedEvent(NSEvent* event) {
- [bridged_view_ processCapturedMouseEvent:event];
-}
-
-void BridgedNativeWidget::OnMouseCaptureLost() {
- host_->OnMouseCaptureActiveChanged(false);
-}
-
-NSWindow* BridgedNativeWidget::GetWindow() const {
- return window_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// TODO(ccameron): Update class names to:
-// BridgedNativeWidgetImpl, BridgedNativeWidget:
-
-void BridgedNativeWidget::SetVisibleOnAllSpaces(bool always_visible) {
- gfx::SetNSWindowVisibleOnAllWorkspaces(window_, always_visible);
-}
-
-void BridgedNativeWidget::SetFullscreen(bool fullscreen) {
- if (fullscreen == target_fullscreen_state_)
- return;
- ToggleDesiredFullscreenState();
-}
-
-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::SetOpacity(float opacity) {
- [window_ setAlphaValue:opacity];
-}
-
-void BridgedNativeWidget::SetContentAspectRatio(
- const gfx::SizeF& aspect_ratio) {
- [window_ setContentAspectRatio:NSMakeSize(aspect_ratio.width(),
- aspect_ratio.height())];
-}
-
-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.
- 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.
- display_ca_layer_tree_->UpdateCALayerTree(ca_layer_params);
-
- if (ca_transaction_sync_suppressed_)
- ca_transaction_sync_suppressed_ = false;
-
- if (invalidate_shadow_on_frame_swap_) {
- invalidate_shadow_on_frame_swap_ = false;
- [window_ invalidateShadow];
- }
-}
-
-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:
-
-NSWindow* BridgedNativeWidget::GetNSWindow() {
- return window_;
-}
-
-gfx::Vector2d BridgedNativeWidget::GetChildWindowOffset() const {
- return gfx::ScreenRectFromNSRect([window_ frame]).OffsetFromOrigin();
-}
-
-bool BridgedNativeWidget::IsVisibleParent() const {
- return parent_ ? window_visible_ && parent_->IsVisibleParent()
- : window_visible_;
-}
-
-void BridgedNativeWidget::RemoveChildWindow(BridgedNativeWidget* child) {
- auto location = std::find(
- child_windows_.begin(), child_windows_.end(), child);
- DCHECK(location != child_windows_.end());
- child_windows_.erase(location);
-
- // Note the child is sometimes removed already by AppKit. This depends on OS
- // version, and possibly some unpredictable reference counting. Removing it
- // here should be safe regardless.
- [window_ removeChildWindow:child->window_];
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, private:
-
-void BridgedNativeWidget::RemoveOrDestroyChildren() {
- // TODO(tapted): Implement unowned child windows if required.
- while (!child_windows_.empty()) {
- // The NSWindow can only be destroyed after -[NSWindow close] is complete.
- // Retain the window, otherwise the reference count can reach zero when the
- // child calls back into RemoveChildWindow() via its OnWindowWillClose().
- base::scoped_nsobject<NSWindow> child(
- [child_windows_.back()->ns_window() retain]);
- [child close];
- }
-}
-
-void BridgedNativeWidget::NotifyVisibilityChangeDown() {
- // Child windows sometimes like to close themselves in response to visibility
- // changes. That's supported, but only with the asynchronous Widget::Close().
- // Perform a heuristic to detect child removal that would break these loops.
- const size_t child_count = child_windows_.size();
- if (!window_visible_) {
- for (BridgedNativeWidget* child : child_windows_) {
- if (child->window_visible_)
- [child->ns_window() orderOut:nil];
-
- DCHECK(!child->window_visible_);
- CHECK_EQ(child_count, child_windows_.size());
- }
- // The orderOut calls above should result in a call to OnVisibilityChanged()
- // in each child. There, children will remove themselves from the NSWindow
- // childWindow list as well as propagate NotifyVisibilityChangeDown() calls
- // to any children of their own. However this is only true for windows
- // managed by the BridgedNativeWidget i.e. windows which have
- // ViewsNSWindowDelegate as the delegate.
- DCHECK_EQ(0u, CountBridgedWindows([window_ childWindows]));
- return;
- }
-
- NSUInteger visible_bridged_children = 0; // For a DCHECK below.
- NSInteger parent_window_number = [window_ windowNumber];
- for (BridgedNativeWidget* child: child_windows_) {
- // Note: order the child windows on top, regardless of whether or not they
- // are currently visible. They probably aren't, since the parent was hidden
- // prior to this, but they could have been made visible in other ways.
- if (child->wants_to_be_visible_) {
- ++visible_bridged_children;
- // Here -[NSWindow orderWindow:relativeTo:] is used to put the window on
- // screen. However, that by itself is insufficient to guarantee a correct
- // z-order relationship. If this function is being called from a z-order
- // change in the parent, orderWindow turns out to be unreliable (i.e. the
- // ordering doesn't always take effect). What this actually relies on is
- // the resulting call to OnVisibilityChanged() in the child, which will
- // then insert itself into -[NSWindow childWindows] to let Cocoa do its
- // internal layering magic.
- [child->ns_window() orderWindow:NSWindowAbove
- relativeTo:parent_window_number];
- DCHECK(child->window_visible_);
- }
- CHECK_EQ(child_count, child_windows_.size());
- }
- DCHECK_EQ(visible_bridged_children,
- CountBridgedWindows([window_ childWindows]));
-}
-
-void BridgedNativeWidget::AddCompositorSuperview() {
- DCHECK(!compositor_superview_);
- compositor_superview_.reset(
- [[ViewsCompositorSuperview alloc] initWithFrame:[bridged_view_ bounds]]);
-
- // Size and resize automatically with |bridged_view_|.
- [compositor_superview_
- setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-
- // Enable HiDPI backing when supported (only on 10.7+).
- if ([compositor_superview_ respondsToSelector:
- @selector(setWantsBestResolutionOpenGLSurface:)]) {
- [compositor_superview_ setWantsBestResolutionOpenGLSurface:YES];
- }
-
- // Set the layer first to create a layer-hosting view (not layer-backed), and
- // set the compositor output to go to that layer.
- base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
- display_ca_layer_tree_ =
- std::make_unique<ui::DisplayCALayerTree>(background_layer.get());
- [compositor_superview_ setLayer:background_layer];
- [compositor_superview_ setWantsLayer:YES];
-
- // The UI compositor should always be the first subview, to ensure webviews
- // are drawn on top of it.
- DCHECK_EQ(0u, [[bridged_view_ subviews] count]);
- [bridged_view_ addSubview:compositor_superview_];
-}
-
-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();
-
- host_->OnWindowGeometryChanged(window_in_screen, content_in_screen);
-
- 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 (content_resized && ![window_ isOpaque])
- invalidate_shadow_on_frame_swap_ = true;
-}
-
-void BridgedNativeWidget::UpdateWindowDisplay() {
- host_->OnWindowDisplayChanged(
- display::Screen::GetScreen()->GetDisplayNearestWindow(window_));
-}
-
-bool BridgedNativeWidget::IsWindowModalSheet() const {
- return parent_ && modal_type_ == ui::MODAL_TYPE_WINDOW;
-}
-
-void BridgedNativeWidget::ShowAsModalSheet() {
- // -[NSApp beginSheet:] will block the UI thread while the animation runs.
- // 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;
- host_->OnVisibilityChanged(window_visible_);
-
- NSWindow* parent_window = parent_->GetNSWindow();
- DCHECK(parent_window);
-
- // -beginSheet: does not retain |modalDelegate| (and we would not want it to).
- // Since |this| may destroy [window_ delegate], use |window_| itself as the
- // delegate, which will forward to ViewsNSWindowDelegate if |this| is still
- // alive (i.e. it has not set the window delegate to nil).
- [NSApp beginSheet:window_
- modalForWindow:parent_window
- modalDelegate:window_
- didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
- contextInfo:nullptr];
-}
-
-NSMutableDictionary* BridgedNativeWidget::GetWindowProperties() const {
- NSMutableDictionary* properties = objc_getAssociatedObject(
- window_, &kWindowPropertiesKey);
- if (!properties) {
- properties = [NSMutableDictionary dictionary];
- objc_setAssociatedObject(window_, &kWindowPropertiesKey,
- properties, OBJC_ASSOCIATION_RETAIN);
- }
- return properties;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_host.h b/chromium/ui/views/cocoa/bridged_native_widget_host.h
deleted file mode 100644
index 9fa2c68091c..00000000000
--- a/chromium/ui/views/cocoa/bridged_native_widget_host.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// 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
index 561f3553ca6..5451da8d177 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -6,23 +6,27 @@
#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_HOST_IMPL_H_
#include <memory>
+#include <vector>
+#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/associated_binding.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/cocoa/bridge_factory_host.h"
+#include "ui/views/cocoa/drag_drop_client_mac.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"
+#include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
+#include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
+#include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
-namespace views_bridge_mac {
-namespace mojom {
-class BridgedNativeWidget;
-} // namespace mojom
-} // namespace views_bridge_mac
+@class NativeWidgetMacNSWindow;
+@class NSView;
namespace ui {
class RecyclableCompositorMac;
@@ -30,14 +34,16 @@ class RecyclableCompositorMac;
namespace views {
-class BridgedNativeWidget;
+class BridgedNativeWidgetImpl;
class NativeWidgetMac;
// The portion of NativeWidgetMac that lives in the browser process. This
-// communicates to the BridgedNativeWidget, which interacts with the Cocoa
+// communicates to the BridgedNativeWidgetImpl, which interacts with the Cocoa
// APIs, and which may live in an app shim process.
class VIEWS_EXPORT BridgedNativeWidgetHostImpl
- : public BridgedNativeWidgetHost,
+ : public views_bridge_mac::BridgedNativeWidgetHostHelper,
+ public BridgeFactoryHost::Observer,
+ public views_bridge_mac::mojom::BridgedNativeWidgetHost,
public DialogObserver,
public FocusChangeListener,
public ui::internal::InputMethodDelegate,
@@ -45,15 +51,64 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
public ui::LayerOwner,
public ui::AcceleratedWidgetMacNSView {
public:
- // Creates one side of the bridge. |parent| must not be NULL.
- explicit BridgedNativeWidgetHostImpl(NativeWidgetMac* parent);
+ // Retrieves the bridge host associated with the given NSWindow. Returns null
+ // if the supplied handle has no associated Widget.
+ static BridgedNativeWidgetHostImpl* GetFromNativeWindow(
+ gfx::NativeWindow window);
+
+ // Unique integer id handles are used to bridge between the
+ // BridgedNativeWidgetHostImpl in one process and the BridgedNativeWidgetHost
+ // potentially in another.
+ static BridgedNativeWidgetHostImpl* GetFromId(
+ uint64_t bridged_native_widget_id);
+ uint64_t bridged_native_widget_id() const { return widget_id_; }
+
+ // Creates one side of the bridge. |owner| must not be NULL.
+ explicit BridgedNativeWidgetHostImpl(NativeWidgetMac* owner);
~BridgedNativeWidgetHostImpl() override;
- // Provide direct access to the BridgedNativeWidget that this is hosting.
+ // The NativeWidgetMac that owns |this|.
+ views::NativeWidgetMac* native_widget_mac() const {
+ return native_widget_mac_;
+ }
+ BridgedNativeWidgetHostImpl* parent() const { return parent_; }
+ std::vector<BridgedNativeWidgetHostImpl*> children() const {
+ return children_;
+ }
+
+ // The bridge factory that was used to create the true NSWindow for this
+ // widget. This is nullptr for in-process windows.
+ BridgeFactoryHost* bridge_factory_host() const {
+ return bridge_factory_host_;
+ }
+
+ // A NSWindow that is guaranteed to exist in this process. If the bridge
+ // object for this host is in this process, then this points to the bridge's
+ // NSWindow. Otherwise, it mirrors the id and bounds of the child window.
+ NativeWidgetMacNSWindow* GetLocalNSWindow() const;
+
+ // The mojo interface through which to communicate with the underlying
+ // NSWindow and NSView.
+ views_bridge_mac::mojom::BridgedNativeWidget* bridge() const;
+
+ // Direct access to the BridgedNativeWidgetImpl 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;
+ BridgedNativeWidgetImpl* bridge_impl() const { return bridge_impl_.get(); }
+
+ TooltipManager* tooltip_manager() { return tooltip_manager_.get(); }
+
+ DragDropClientMac* drag_drop_client() const {
+ return drag_drop_client_.get();
+ }
+
+ // Create and set the bridge object to be in this process.
+ void CreateLocalBridge(base::scoped_nsobject<NativeWidgetMacNSWindow> window);
+
+ // Create and set the bridge object to be potentially in another process.
+ void CreateRemoteBridge(
+ BridgeFactoryHost* bridge_factory_host,
+ views_bridge_mac::mojom::CreateWindowParamsPtr window_create_params);
void InitWindow(const Widget::InitParams& params);
@@ -75,6 +130,9 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// Set the root view (set during initialization and un-set during teardown).
void SetRootView(views::View* root_view);
+ // Return the id through which the NSView for |root_view_| may be looked up.
+ uint64_t GetRootViewNSViewId() const { return root_view_id_; }
+
// Initialize the ui::Compositor and ui::Layer.
void CreateCompositor(const Widget::InitParams& params);
@@ -93,14 +151,12 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// 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_;
}
@@ -111,42 +167,70 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// fullscreen or transitioning between fullscreen states.
gfx::Rect GetRestoredBounds() const;
+ // Set |parent_| and update the old and new parents' |children_|. It is valid
+ // to set |new_parent| to nullptr. Propagate this to the BridgedNativeWidget.
+ void SetParent(BridgedNativeWidgetHostImpl* new_parent);
+
+ // Properties set and queried by views. Not actually native.
+ void SetNativeWindowProperty(const char* name, void* value);
+ void* GetNativeWindowProperty(const char* name) const;
+
+ // Updates |associated_views_| on NativeViewHost::Attach()/Detach().
+ void SetAssociationForView(const views::View* view, NSView* native_view);
+ void ClearAssociationForView(const views::View* view);
+
+ // Sorts child NSViews according to NativeViewHosts order in views hierarchy.
+ void ReorderChildViews();
+
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_; }
+ // Used by NativeWidgetPrivate::GetGlobalCapture.
+ static NSView* GetGlobalCaptureView();
+
private:
- gfx::Vector2d GetBoundsOffsetForParent() const;
void UpdateCompositorProperties();
void DestroyCompositor();
+ void RankNSViewsRecursive(View* view, std::map<NSView*, int>* rank) const;
- // views::BridgedNativeWidgetHost:
+ // BridgedNativeWidgetHostHelper:
NSView* GetNativeViewAccessible() override;
+ void DispatchKeyEvent(ui::KeyEvent* event) override;
+ bool DispatchKeyEventToMenuController(ui::KeyEvent* event) override;
+ void GetWordAt(const gfx::Point& location_in_content,
+ bool* found_word,
+ gfx::DecoratedText* decorated_word,
+ gfx::Point* baseline_point) override;
+ double SheetPositionY() override;
+ views_bridge_mac::DragDropClient* GetDragDropClient() override;
+
+ // BridgeFactoryHost::Observer:
+ void OnBridgeFactoryHostDestroying(BridgeFactoryHost* host) override;
+
+ // views_bridge_mac::mojom::BridgedNativeWidgetHost:
void OnVisibilityChanged(bool visible) override;
+ void OnWindowNativeThemeChanged() 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,
+ void OnScrollEvent(std::unique_ptr<ui::Event> event) override;
+ void OnMouseEvent(std::unique_ptr<ui::Event> event) override;
+ void OnGestureEvent(std::unique_ptr<ui::Event> event) override;
+ bool DispatchKeyEventRemote(std::unique_ptr<ui::Event> event,
+ bool* event_handled) override;
+ bool DispatchKeyEventToMenuControllerRemote(std::unique_ptr<ui::Event> event,
+ bool* event_swallowed,
+ bool* event_handled) override;
+ bool GetHasMenuController(bool* has_menu_controller) override;
+ bool GetIsDraggableBackgroundAt(const gfx::Point& location_in_content,
bool* is_draggable_background) override;
- void GetTooltipTextAt(const gfx::Point& location_in_content,
+ bool 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;
+ bool GetWidgetIsModal(bool* widget_is_modal) override;
+ bool GetIsFocusedViewTextual(bool* is_textual) override;
void OnWindowGeometryChanged(
const gfx::Rect& window_bounds_in_screen_dips,
const gfx::Rect& content_bounds_in_screen_dips) override;
@@ -161,12 +245,42 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
bool is_content_first_responder,
bool full_keyboard_access_enabled) override;
void DoDialogButtonAction(ui::DialogButton button) override;
- void GetDialogButtonInfo(ui::DialogButton type,
+ bool 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;
+ bool GetDoDialogButtonsExist(bool* buttons_exist) override;
+ bool GetShouldShowWindowTitle(bool* should_show_window_title) override;
+ bool GetCanWindowBecomeKey(bool* can_window_become_key) override;
+ bool GetAlwaysRenderWindowAsKey(bool* always_render_as_key) override;
+ bool GetCanWindowClose(bool* can_window_close) override;
+
+ // views_bridge_mac::mojom::BridgedNativeWidgetHost, synchronous callbacks:
+ void DispatchKeyEventRemote(std::unique_ptr<ui::Event> event,
+ DispatchKeyEventRemoteCallback callback) override;
+ void DispatchKeyEventToMenuControllerRemote(
+ std::unique_ptr<ui::Event> event,
+ DispatchKeyEventToMenuControllerRemoteCallback callback) override;
+ void GetHasMenuController(GetHasMenuControllerCallback callback) override;
+ void GetIsDraggableBackgroundAt(
+ const gfx::Point& location_in_content,
+ GetIsDraggableBackgroundAtCallback callback) override;
+ void GetTooltipTextAt(const gfx::Point& location_in_content,
+ GetTooltipTextAtCallback callback) override;
+ void GetWidgetIsModal(GetWidgetIsModalCallback callback) override;
+ void GetIsFocusedViewTextual(
+ GetIsFocusedViewTextualCallback callback) override;
+ void GetDialogButtonInfo(ui::DialogButton button,
+ GetDialogButtonInfoCallback callback) override;
+ void GetDoDialogButtonsExist(
+ GetDoDialogButtonsExistCallback callback) override;
+ void GetShouldShowWindowTitle(
+ GetShouldShowWindowTitleCallback callback) override;
+ void GetCanWindowBecomeKey(GetCanWindowBecomeKeyCallback callback) override;
+ void GetAlwaysRenderWindowAsKey(
+ GetAlwaysRenderWindowAsKeyCallback callback) override;
+ void GetCanWindowClose(GetCanWindowCloseCallback callback) override;
// DialogObserver:
void OnDialogModelChanged() override;
@@ -176,7 +290,9 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
void OnDidChangeFocus(View* focused_before, View* focused_now) override;
// ui::internal::InputMethodDelegate:
- ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override;
+ ui::EventDispatchDetails DispatchKeyEventPostIME(
+ ui::KeyEvent* key,
+ base::OnceCallback<void(bool)> ack_callback) override;
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override;
@@ -186,17 +302,38 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// ui::AcceleratedWidgetMacNSView:
void AcceleratedWidgetCALayerParamsUpdated() override;
+ // The id that this bridge may be looked up from.
+ const uint64_t widget_id_;
views::NativeWidgetMac* const native_widget_mac_; // Weak. Owns |this_|.
+ // Parent and child widgets.
+ BridgedNativeWidgetHostImpl* parent_ = nullptr;
+ std::vector<BridgedNativeWidgetHostImpl*> children_;
+
+ // The factory that was used to create |bridge_ptr_|. This must be the same
+ // as |parent_->bridge_factory_host_|.
+ BridgeFactoryHost* bridge_factory_host_ = nullptr;
+
Widget::InitParams::Type widget_type_ = Widget::InitParams::TYPE_WINDOW;
+ // The id that may be used to look up the NSView for |root_view_|.
+ const uint64_t root_view_id_;
views::View* root_view_ = nullptr; // Weak. Owned by |native_widget_mac_|.
+ std::unique_ptr<DragDropClientMac> drag_drop_client_;
- // TODO(ccameron): Rather than instantiate a BridgedNativeWidget here,
- // we will instantiate a mojo BridgedNativeWidget interface to a Cocoa
+ // The mojo pointer to a BridgedNativeWidget, which may exist in another
+ // process.
+ views_bridge_mac::mojom::BridgedNativeWidgetAssociatedPtr bridge_ptr_;
+
+ // TODO(ccameron): Rather than instantiate a BridgedNativeWidgetImpl here,
+ // we will instantiate a mojo BridgedNativeWidgetImpl interface to a Cocoa
// instance that may be in another process.
- std::unique_ptr<BridgedNativeWidget> bridge_impl_;
+ std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
+
+ // Window that is guaranteed to exist in this process (see GetLocalNSWindow).
+ base::scoped_nsobject<NativeWidgetMacNSWindow> local_window_;
+ std::unique_ptr<TooltipManager> tooltip_manager_;
std::unique_ptr<ui::InputMethod> input_method_;
FocusManager* focus_manager_ = nullptr; // Weak. Owned by our Widget.
@@ -209,7 +346,6 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
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;
@@ -222,6 +358,14 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
+ // Properties used by Set/GetNativeWindowProperty.
+ std::map<std::string, void*> native_window_properties_;
+
+ // Contains NativeViewHost->gfx::NativeView associations.
+ std::map<const views::View*, NSView*> associated_views_;
+
+ mojo::AssociatedBinding<views_bridge_mac::mojom::BridgedNativeWidgetHost>
+ host_mojo_binding_;
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetHostImpl);
};
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
index 53e6a582b6c..63f9be6db98 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -4,6 +4,8 @@
#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
+#include "base/mac/foundation_util.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_factory.h"
@@ -11,7 +13,9 @@
#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/gfx/mac/coordinate_conversion.h"
+#include "ui/native_theme/native_theme_mac.h"
+#include "ui/views/cocoa/tooltip_manager_mac.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/views_delegate.h"
@@ -21,6 +25,9 @@
#include "ui/views/window/dialog_client_view.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/views/word_lookup_client.h"
+#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#include "ui/views_bridge_mac/cocoa_mouse_capture.h"
+#include "ui/views_bridge_mac/native_widget_mac_nswindow.h"
using views_bridge_mac::mojom::BridgedNativeWidgetInitParams;
using views_bridge_mac::mojom::WindowVisibilityState;
@@ -40,14 +47,61 @@ bool PositionWindowInScreenCoordinates(Widget* widget,
return widget && widget->is_top_level();
}
+std::map<uint64_t, BridgedNativeWidgetHostImpl*>& GetIdToWidgetHostImplMap() {
+ static base::NoDestructor<std::map<uint64_t, BridgedNativeWidgetHostImpl*>>
+ id_map;
+ return *id_map;
+}
+
+uint64_t g_last_bridged_native_widget_id = 0;
+
} // namespace
-BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(
- NativeWidgetMac* parent)
- : native_widget_mac_(parent),
- bridge_impl_(new BridgedNativeWidget(this, parent)) {}
+// static
+BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ gfx::NativeWindow window) {
+ if (NativeWidgetMacNSWindow* widget_window =
+ base::mac::ObjCCast<NativeWidgetMacNSWindow>(window)) {
+ return GetFromId([widget_window bridgedNativeWidgetId]);
+ }
+ return nullptr; // Not created by NativeWidgetMac.
+}
+
+// static
+BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromId(
+ uint64_t bridged_native_widget_id) {
+ auto found = GetIdToWidgetHostImplMap().find(bridged_native_widget_id);
+ if (found == GetIdToWidgetHostImplMap().end())
+ return nullptr;
+ return found->second;
+}
+
+BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(NativeWidgetMac* owner)
+ : widget_id_(++g_last_bridged_native_widget_id),
+ native_widget_mac_(owner),
+ root_view_id_(ui::NSViewIds::GetNewId()),
+ host_mojo_binding_(this) {
+ DCHECK(GetIdToWidgetHostImplMap().find(widget_id_) ==
+ GetIdToWidgetHostImplMap().end());
+ GetIdToWidgetHostImplMap().insert(std::make_pair(widget_id_, this));
+ DCHECK(owner);
+}
BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {
+ DCHECK(children_.empty());
+ if (bridge_factory_host_) {
+ bridge_ptr_.reset();
+ host_mojo_binding_.Unbind();
+ bridge_factory_host_->RemoveObserver(this);
+ bridge_factory_host_ = nullptr;
+ }
+
+ // Ensure that |this| cannot be reached by its id while it is being destroyed.
+ auto found = GetIdToWidgetHostImplMap().find(widget_id_);
+ DCHECK(found != GetIdToWidgetHostImplMap().end());
+ DCHECK_EQ(found->second, this);
+ GetIdToWidgetHostImplMap().erase(found);
+
// Destroy the bridge first to prevent any calls back into this during
// destruction.
// TODO(ccameron): When all communication from |bridge_| to this goes through
@@ -57,26 +111,67 @@ BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {
DestroyCompositor();
}
+NativeWidgetMacNSWindow* BridgedNativeWidgetHostImpl::GetLocalNSWindow() const {
+ return local_window_.get();
+}
+
views_bridge_mac::mojom::BridgedNativeWidget*
BridgedNativeWidgetHostImpl::bridge() const {
- return bridge_impl_.get();
+ if (bridge_ptr_)
+ return bridge_ptr_.get();
+ if (bridge_impl_)
+ return bridge_impl_.get();
+ return nullptr;
+}
+
+void BridgedNativeWidgetHostImpl::CreateLocalBridge(
+ base::scoped_nsobject<NativeWidgetMacNSWindow> window) {
+ local_window_ = window;
+ bridge_impl_ =
+ std::make_unique<BridgedNativeWidgetImpl>(widget_id_, this, this);
+ bridge_impl_->SetWindow(window);
+}
+
+void BridgedNativeWidgetHostImpl::CreateRemoteBridge(
+ BridgeFactoryHost* bridge_factory_host,
+ views_bridge_mac::mojom::CreateWindowParamsPtr window_create_params) {
+ bridge_factory_host_ = bridge_factory_host;
+ bridge_factory_host_->AddObserver(this);
+
+ // Create the local window with the same parameters as will be used in the
+ // other process.
+ local_window_ =
+ BridgedNativeWidgetImpl::CreateNSWindow(window_create_params.get());
+ [local_window_ setBridgedNativeWidgetId:widget_id_];
+
+ // Initialize |bridge_ptr_| to point to a bridge created by |factory|.
+ views_bridge_mac::mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr;
+ host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr),
+ ui::WindowResizeHelperMac::Get()->task_runner());
+ bridge_factory_host_->GetFactory()->CreateBridgedNativeWidget(
+ widget_id_, mojo::MakeRequest(&bridge_ptr_), host_ptr.PassInterface());
+
+ // Create the window in its process, and attach it to its parent window.
+ bridge()->CreateWindow(std::move(window_create_params));
}
void BridgedNativeWidgetHostImpl::InitWindow(const Widget::InitParams& params) {
+ Widget* widget = native_widget_mac_->GetWidget();
// 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);
+ tooltip_manager_.reset(new TooltipManagerMac(bridge()));
// Initialize the window.
{
auto bridge_params = BridgedNativeWidgetInitParams::New();
- bridge_params->modal_type =
- native_widget_mac_->GetWidget()->widget_delegate()->GetModalType();
+ bridge_params->modal_type = widget->widget_delegate()->GetModalType();
bridge_params->is_translucent =
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
+ bridge_params->widget_is_top_level = widget->is_top_level();
+ bridge_params->position_window_in_screen_coords =
+ PositionWindowInScreenCoordinates(widget, widget_type_);
// OSX likes to put shadows on most things. However, frameless windows (with
// styleMask = NSBorderlessWindowMask) default to no shadow. So change that.
@@ -111,9 +206,11 @@ void BridgedNativeWidgetHostImpl::InitWindow(const Widget::InitParams& params) {
// 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());
+ bridge()->SetInitialBounds(params.bounds, widget->GetMinimumSize());
+
+ // TODO(ccameron): Correctly set these based |local_window_|.
+ window_bounds_in_screen_ = params.bounds;
+ content_bounds_in_screen_ = params.bounds;
// Widgets for UI controls (usually layered above web contents) start visible.
if (widget_type_ == Widget::InitParams::TYPE_CONTROL)
@@ -121,21 +218,10 @@ void BridgedNativeWidgetHostImpl::InitWindow(const Widget::InitParams& params) {
}
void BridgedNativeWidgetHostImpl::SetBounds(const gfx::Rect& bounds) {
- gfx::Rect adjusted_bounds = bounds;
- adjusted_bounds.Offset(GetBoundsOffsetForParent());
- bridge()->SetBounds(adjusted_bounds,
+ bridge()->SetBounds(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.
@@ -148,6 +234,15 @@ void BridgedNativeWidgetHostImpl::SetFullscreen(bool fullscreen) {
void BridgedNativeWidgetHostImpl::SetRootView(views::View* root_view) {
root_view_ = root_view;
+ if (root_view_) {
+ // TODO(ccameron): Drag-drop functionality does not yet run over mojo.
+ if (bridge_impl_) {
+ drag_drop_client_.reset(
+ new DragDropClientMac(bridge_impl_.get(), root_view_));
+ }
+ } else {
+ drag_drop_client_.reset();
+ }
}
void BridgedNativeWidgetHostImpl::CreateCompositor(
@@ -202,7 +297,7 @@ 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.
+ // BridgedNativeWidgetImpl.
DCHECK_EQ(this, layer()->owner());
layer()->CompleteAllAnimations();
layer()->SuppressPaint();
@@ -267,13 +362,129 @@ gfx::Rect BridgedNativeWidgetHostImpl::GetRestoredBounds() const {
return window_bounds_in_screen_;
}
+void BridgedNativeWidgetHostImpl::SetNativeWindowProperty(const char* name,
+ void* value) {
+ if (value)
+ native_window_properties_[name] = value;
+ else
+ native_window_properties_.erase(name);
+}
+
+void* BridgedNativeWidgetHostImpl::GetNativeWindowProperty(
+ const char* name) const {
+ auto found = native_window_properties_.find(name);
+ if (found == native_window_properties_.end())
+ return nullptr;
+ return found->second;
+}
+
+void BridgedNativeWidgetHostImpl::SetParent(
+ BridgedNativeWidgetHostImpl* new_parent) {
+ if (new_parent == parent_)
+ return;
+
+ if (parent_) {
+ auto found =
+ std::find(parent_->children_.begin(), parent_->children_.end(), this);
+ DCHECK(found != parent_->children_.end());
+ parent_->children_.erase(found);
+ }
+
+ parent_ = new_parent;
+ if (parent_) {
+ // We can only re-parent to another Widget if that Widget is hosted in the
+ // same process that we were already hosted by.
+ CHECK_EQ(bridge_factory_host_, parent_->bridge_factory_host());
+ parent_->children_.push_back(this);
+ bridge()->SetParent(parent_->bridged_native_widget_id());
+ } else {
+ bridge()->SetParent(0);
+ }
+}
+
+void BridgedNativeWidgetHostImpl::SetAssociationForView(const View* view,
+ NSView* native_view) {
+ DCHECK_EQ(0u, associated_views_.count(view));
+ associated_views_[view] = native_view;
+ native_widget_mac_->GetWidget()->ReorderNativeViews();
+}
+
+void BridgedNativeWidgetHostImpl::ClearAssociationForView(const View* view) {
+ auto it = associated_views_.find(view);
+ DCHECK(it != associated_views_.end());
+ associated_views_.erase(it);
+}
+
+void BridgedNativeWidgetHostImpl::ReorderChildViews() {
+ std::map<NSView*, int> rank;
+ Widget* widget = native_widget_mac_->GetWidget();
+ RankNSViewsRecursive(widget->GetRootView(), &rank);
+ if (bridge_impl_)
+ bridge_impl_->SortSubviews(std::move(rank));
+}
+
+void BridgedNativeWidgetHostImpl::RankNSViewsRecursive(
+ View* view,
+ std::map<NSView*, int>* rank) const {
+ auto it = associated_views_.find(view);
+ if (it != associated_views_.end())
+ rank->emplace(it->second, rank->size());
+ for (int i = 0; i < view->child_count(); ++i)
+ RankNSViewsRecursive(view->child_at(i), rank);
+}
+
+// static
+NSView* BridgedNativeWidgetHostImpl::GetGlobalCaptureView() {
+ // TODO(ccameron): This will not work across process boundaries.
+ return [CocoaMouseCapture::GetGlobalCaptureWindow() contentView];
+}
+
////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidgetHostImpl, views::BridgedNativeWidgetHost:
+// BridgedNativeWidgetHostImpl, views_bridge_mac::BridgedNativeWidgetHostHelper:
NSView* BridgedNativeWidgetHostImpl::GetNativeViewAccessible() {
return root_view_ ? root_view_->GetNativeViewAccessible() : nil;
}
+void BridgedNativeWidgetHostImpl::DispatchKeyEvent(ui::KeyEvent* event) {
+ ignore_result(
+ root_view_->GetWidget()->GetInputMethod()->DispatchKeyEvent(event));
+}
+
+bool BridgedNativeWidgetHostImpl::DispatchKeyEventToMenuController(
+ ui::KeyEvent* event) {
+ MenuController* menu_controller = MenuController::GetActiveInstance();
+ if (menu_controller && root_view_ &&
+ menu_controller->owner() == root_view_->GetWidget()) {
+ return menu_controller->OnWillDispatchKeyEvent(event) ==
+ ui::POST_DISPATCH_NONE;
+ }
+ return false;
+}
+
+double BridgedNativeWidgetHostImpl::SheetPositionY() {
+ return native_widget_mac_->SheetPositionY();
+}
+
+views_bridge_mac::DragDropClient*
+BridgedNativeWidgetHostImpl::GetDragDropClient() {
+ return drag_drop_client_.get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, BridgeFactoryHost::Observer:
+void BridgedNativeWidgetHostImpl::OnBridgeFactoryHostDestroying(
+ BridgeFactoryHost* host) {
+ DCHECK_EQ(host, bridge_factory_host_);
+ bridge_factory_host_->RemoveObserver(this);
+ bridge_factory_host_ = nullptr;
+ // TODO(ccameron): This should be treated as the window closing.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl,
+// views_bridge_mac::mojom::BridgedNativeWidgetHost:
+
void BridgedNativeWidgetHostImpl::OnVisibilityChanged(bool window_visible) {
is_visible_ = window_visible;
if (compositor_) {
@@ -289,54 +500,48 @@ void BridgedNativeWidgetHostImpl::OnVisibilityChanged(bool window_visible) {
window_visible);
}
+void BridgedNativeWidgetHostImpl::OnWindowNativeThemeChanged() {
+ ui::NativeTheme::GetInstanceForNativeUi()->NotifyObservers();
+}
+
void BridgedNativeWidgetHostImpl::OnScrollEvent(
- const ui::ScrollEvent& const_event) {
- ui::ScrollEvent event = const_event;
- root_view_->GetWidget()->OnScrollEvent(&event);
+ std::unique_ptr<ui::Event> event) {
+ root_view_->GetWidget()->OnScrollEvent(event->AsScrollEvent());
}
void BridgedNativeWidgetHostImpl::OnMouseEvent(
- const ui::MouseEvent& const_event) {
- ui::MouseEvent event = const_event;
- root_view_->GetWidget()->OnMouseEvent(&event);
+ std::unique_ptr<ui::Event> event) {
+ root_view_->GetWidget()->OnMouseEvent(event->AsMouseEvent());
}
void BridgedNativeWidgetHostImpl::OnGestureEvent(
- const ui::GestureEvent& const_event) {
- ui::GestureEvent event = const_event;
- root_view_->GetWidget()->OnGestureEvent(&event);
+ std::unique_ptr<ui::Event> event) {
+ root_view_->GetWidget()->OnGestureEvent(event->AsGestureEvent());
}
-void BridgedNativeWidgetHostImpl::DispatchKeyEvent(
- const ui::KeyEvent& const_event,
+bool BridgedNativeWidgetHostImpl::DispatchKeyEventRemote(
+ std::unique_ptr<ui::Event> event,
bool* event_handled) {
- ui::KeyEvent event = const_event;
- ignore_result(
- root_view_->GetWidget()->GetInputMethod()->DispatchKeyEvent(&event));
- *event_handled = event.handled();
+ DispatchKeyEvent(event->AsKeyEvent());
+ *event_handled = event->handled();
+ return true;
}
-void BridgedNativeWidgetHostImpl::DispatchKeyEventToMenuController(
- const ui::KeyEvent& const_event,
+bool BridgedNativeWidgetHostImpl::DispatchKeyEventToMenuControllerRemote(
+ std::unique_ptr<ui::Event> 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();
+ *event_swallowed = DispatchKeyEventToMenuController(event->AsKeyEvent());
+ *event_handled = event->handled();
+ return true;
}
-void BridgedNativeWidgetHostImpl::GetHasMenuController(
+bool BridgedNativeWidgetHostImpl::GetHasMenuController(
bool* has_menu_controller) {
MenuController* menu_controller = MenuController::GetActiveInstance();
*has_menu_controller = menu_controller && root_view_ &&
menu_controller->owner() == root_view_->GetWidget();
+ return true;
}
void BridgedNativeWidgetHostImpl::SetViewSize(const gfx::Size& new_size) {
@@ -364,15 +569,16 @@ void BridgedNativeWidgetHostImpl::OnMouseCaptureActiveChanged(bool is_active) {
native_widget_mac_->GetWidget()->OnMouseCaptureLost();
}
-void BridgedNativeWidgetHostImpl::GetIsDraggableBackgroundAt(
+bool 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;
+ return true;
}
-void BridgedNativeWidgetHostImpl::GetTooltipTextAt(
+bool BridgedNativeWidgetHostImpl::GetTooltipTextAt(
const gfx::Point& location_in_content,
base::string16* new_tooltip_text) {
views::View* view =
@@ -384,6 +590,7 @@ void BridgedNativeWidgetHostImpl::GetTooltipTextAt(
if (!view->GetTooltipText(view_point, new_tooltip_text))
DCHECK(new_tooltip_text->empty());
}
+ return true;
}
void BridgedNativeWidgetHostImpl::GetWordAt(
@@ -414,22 +621,32 @@ void BridgedNativeWidgetHostImpl::GetWordAt(
*found_word = true;
}
-void BridgedNativeWidgetHostImpl::GetWidgetIsModal(bool* widget_is_modal) {
+bool BridgedNativeWidgetHostImpl::GetWidgetIsModal(bool* widget_is_modal) {
*widget_is_modal = native_widget_mac_->GetWidget()->IsModal();
+ return true;
}
-void BridgedNativeWidgetHostImpl::GetIsFocusedViewTextual(bool* is_textual) {
+bool 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;
+ return true;
}
void BridgedNativeWidgetHostImpl::OnWindowGeometryChanged(
const gfx::Rect& new_window_bounds_in_screen,
const gfx::Rect& new_content_bounds_in_screen) {
- has_received_window_geometry_ = true;
+ // If we are accessing the BridgedNativeWidget through mojo, then
+ // |local_window_| is not the true window that was just resized. Update
+ // the frame of |local_window_| to keep it in sync for any native calls
+ // that may use it (e.g, for context menu positioning).
+ if (bridge_ptr_) {
+ [local_window_ setFrame:gfx::ScreenRectToNSRect(new_window_bounds_in_screen)
+ display:NO
+ animate:NO];
+ }
bool window_has_moved =
new_window_bounds_in_screen.origin() != window_bounds_in_screen_.origin();
@@ -478,6 +695,8 @@ void BridgedNativeWidgetHostImpl::OnWindowFullscreenTransitionComplete(
void BridgedNativeWidgetHostImpl::OnWindowMiniaturizedChanged(
bool miniaturized) {
is_miniaturized_ = miniaturized;
+ if (native_widget_mac_)
+ native_widget_mac_->GetWidget()->OnNativeWidgetWindowShowStateChanged();
}
void BridgedNativeWidgetHostImpl::OnWindowDisplayChanged(
@@ -486,7 +705,7 @@ void BridgedNativeWidgetHostImpl::OnWindowDisplayChanged(
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_) {
+ if (scale_factor_changed && compositor_) {
compositor_->UpdateSurface(
ConvertSizeToPixel(display_.device_scale_factor(),
content_bounds_in_screen_.size()),
@@ -507,9 +726,14 @@ void BridgedNativeWidgetHostImpl::OnWindowWillClose() {
if (DialogDelegate* dialog = widget->widget_delegate()->AsDialogDelegate())
dialog->RemoveObserver(this);
native_widget_mac_->WindowDestroying();
+ // Remove |this| from the parent's list of children.
+ SetParent(nullptr);
}
void BridgedNativeWidgetHostImpl::OnWindowHasClosed() {
+ // OnWindowHasClosed will be called only after all child windows have had
+ // OnWindowWillClose called on them.
+ DCHECK(children_.empty());
native_widget_mac_->WindowDestroyed();
}
@@ -551,7 +775,7 @@ void BridgedNativeWidgetHostImpl::DoDialogButtonAction(
}
}
-void BridgedNativeWidgetHostImpl::GetDialogButtonInfo(
+bool BridgedNativeWidgetHostImpl::GetDialogButtonInfo(
ui::DialogButton button,
bool* button_exists,
base::string16* button_label,
@@ -561,17 +785,154 @@ void BridgedNativeWidgetHostImpl::GetDialogButtonInfo(
ui::DialogModel* model =
root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
if (!model || !(model->GetDialogButtons() & button))
- return;
+ return true;
*button_exists = true;
*button_label = model->GetDialogButtonLabel(button);
*is_button_enabled = model->IsDialogButtonEnabled(button);
*is_button_default = button == model->GetDefaultDialogButton();
+ return true;
}
-void BridgedNativeWidgetHostImpl::GetDoDialogButtonsExist(bool* buttons_exist) {
+bool BridgedNativeWidgetHostImpl::GetDoDialogButtonsExist(bool* buttons_exist) {
ui::DialogModel* model =
root_view_->GetWidget()->widget_delegate()->AsDialogDelegate();
*buttons_exist = model && model->GetDialogButtons();
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::GetShouldShowWindowTitle(
+ bool* should_show_window_title) {
+ *should_show_window_title =
+ root_view_
+ ? root_view_->GetWidget()->widget_delegate()->ShouldShowWindowTitle()
+ : true;
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::GetCanWindowBecomeKey(
+ bool* can_window_become_key) {
+ *can_window_become_key =
+ root_view_ ? root_view_->GetWidget()->CanActivate() : false;
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::GetAlwaysRenderWindowAsKey(
+ bool* always_render_as_key) {
+ *always_render_as_key =
+ root_view_ ? root_view_->GetWidget()->IsAlwaysRenderAsActive() : false;
+ return true;
+}
+
+bool BridgedNativeWidgetHostImpl::GetCanWindowClose(bool* can_window_close) {
+ *can_window_close = true;
+ views::NonClientView* non_client_view =
+ root_view_ ? root_view_->GetWidget()->non_client_view() : nullptr;
+ if (non_client_view)
+ *can_window_close = non_client_view->CanClose();
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl,
+// views_bridge_mac::mojom::BridgedNativeWidgetHost synchronous callbacks:
+
+void BridgedNativeWidgetHostImpl::DispatchKeyEventRemote(
+ std::unique_ptr<ui::Event> event,
+ DispatchKeyEventRemoteCallback callback) {
+ bool event_handled = false;
+ DispatchKeyEventRemote(std::move(event), &event_handled);
+ std::move(callback).Run(event_handled);
+}
+
+void BridgedNativeWidgetHostImpl::DispatchKeyEventToMenuControllerRemote(
+ std::unique_ptr<ui::Event> event,
+ DispatchKeyEventToMenuControllerRemoteCallback callback) {
+ ui::KeyEvent* key_event = event->AsKeyEvent();
+ bool event_swallowed = DispatchKeyEventToMenuController(key_event);
+ std::move(callback).Run(event_swallowed, key_event->handled());
+}
+
+void BridgedNativeWidgetHostImpl::GetHasMenuController(
+ GetHasMenuControllerCallback callback) {
+ bool has_menu_controller = false;
+ GetHasMenuController(&has_menu_controller);
+ std::move(callback).Run(has_menu_controller);
+}
+
+void BridgedNativeWidgetHostImpl::GetIsDraggableBackgroundAt(
+ const gfx::Point& location_in_content,
+ GetIsDraggableBackgroundAtCallback callback) {
+ bool is_draggable_background = false;
+ GetIsDraggableBackgroundAt(location_in_content, &is_draggable_background);
+ std::move(callback).Run(is_draggable_background);
+}
+
+void BridgedNativeWidgetHostImpl::GetTooltipTextAt(
+ const gfx::Point& location_in_content,
+ GetTooltipTextAtCallback callback) {
+ base::string16 new_tooltip_text;
+ GetTooltipTextAt(location_in_content, &new_tooltip_text);
+ std::move(callback).Run(new_tooltip_text);
+}
+
+void BridgedNativeWidgetHostImpl::GetIsFocusedViewTextual(
+ GetIsFocusedViewTextualCallback callback) {
+ bool is_textual = false;
+ GetIsFocusedViewTextual(&is_textual);
+ std::move(callback).Run(is_textual);
+}
+
+void BridgedNativeWidgetHostImpl::GetWidgetIsModal(
+ GetWidgetIsModalCallback callback) {
+ bool widget_is_modal = false;
+ GetWidgetIsModal(&widget_is_modal);
+ std::move(callback).Run(widget_is_modal);
+}
+
+void BridgedNativeWidgetHostImpl::GetDialogButtonInfo(
+ ui::DialogButton button,
+ GetDialogButtonInfoCallback callback) {
+ bool exists = false;
+ base::string16 label;
+ bool is_enabled = false;
+ bool is_default = false;
+ GetDialogButtonInfo(button, &exists, &label, &is_enabled, &is_default);
+ std::move(callback).Run(exists, label, is_enabled, is_default);
+}
+
+void BridgedNativeWidgetHostImpl::GetDoDialogButtonsExist(
+ GetDoDialogButtonsExistCallback callback) {
+ bool buttons_exist = false;
+ GetDoDialogButtonsExist(&buttons_exist);
+ std::move(callback).Run(buttons_exist);
+}
+
+void BridgedNativeWidgetHostImpl::GetShouldShowWindowTitle(
+ GetShouldShowWindowTitleCallback callback) {
+ bool should_show_window_title = false;
+ GetShouldShowWindowTitle(&should_show_window_title);
+ std::move(callback).Run(should_show_window_title);
+}
+
+void BridgedNativeWidgetHostImpl::GetCanWindowBecomeKey(
+ GetCanWindowBecomeKeyCallback callback) {
+ bool can_window_become_key = false;
+ GetCanWindowBecomeKey(&can_window_become_key);
+ std::move(callback).Run(can_window_become_key);
+}
+
+void BridgedNativeWidgetHostImpl::GetAlwaysRenderWindowAsKey(
+ GetAlwaysRenderWindowAsKeyCallback callback) {
+ bool always_render_as_key = false;
+ GetAlwaysRenderWindowAsKey(&always_render_as_key);
+ std::move(callback).Run(always_render_as_key);
+}
+
+void BridgedNativeWidgetHostImpl::GetCanWindowClose(
+ GetCanWindowCloseCallback callback) {
+ bool can_window_close = false;
+ GetCanWindowClose(&can_window_close);
+ std::move(callback).Run(can_window_close);
}
////////////////////////////////////////////////////////////////////////////////
@@ -598,20 +959,25 @@ void BridgedNativeWidgetHostImpl::OnDidChangeFocus(View* focused_before,
// 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);
+ // TODO(ccameron): TextInputClient is not handled across process borders
+ // yet.
+ if (bridge_impl_)
+ bridge_impl_->SetTextInputClient(input_client);
}
}
////////////////////////////////////////////////////////////////////////////////
-// BridgedNativeWidget, internal::InputMethodDelegate:
+// BridgedNativeWidgetImpl, internal::InputMethodDelegate:
ui::EventDispatchDetails BridgedNativeWidgetHostImpl::DispatchKeyEventPostIME(
- ui::KeyEvent* key) {
+ ui::KeyEvent* key,
+ base::OnceCallback<void(bool)> ack_callback) {
DCHECK(focus_manager_);
if (!focus_manager_->OnKeyEvent(*key))
key->StopPropagation();
else
native_widget_mac_->GetWidget()->OnKeyEvent(key);
+ CallDispatchKeyEventPostIMEAck(key, std::move(ack_callback));
return ui::EventDispatchDetails();
}
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 53c32814537..38f71672f2e 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
#import <Cocoa/Cocoa.h>
@@ -251,7 +251,7 @@ void WaitForEvent(NSUInteger mask) {
} // namespace
// This is used to inject test versions of NativeFrameView and
-// BridgedNativeWidget.
+// BridgedNativeWidgetImpl.
class HitTestNativeWidgetMac : public NativeWidgetMac {
public:
HitTestNativeWidgetMac(internal::NativeWidgetDelegate* delegate,
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_owner.h b/chromium/ui/views/cocoa/bridged_native_widget_owner.h
deleted file mode 100644
index 9869ed5a938..00000000000
--- a/chromium/ui/views/cocoa/bridged_native_widget_owner.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_OWNER_H_
-#define UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_OWNER_H_
-
-namespace gfx {
-class Vector2d;
-}
-
-@class NSWindow;
-
-namespace views {
-
-class BridgedNativeWidget;
-
-// An abstract interface wrapping an NSWindow that ties the lifetime of one or
-// more child BridgedNativeWidgets to the lifetime of that NSWindow. This is not
-// simply an NSWindow, because the child window API provided by NSWindow
-// requires child windows to always be visible.
-class BridgedNativeWidgetOwner {
- public:
- // The NSWindow parent.
- virtual NSWindow* GetNSWindow() = 0;
-
- // The offset in screen pixels for positioning child windows owned by |this|.
- virtual gfx::Vector2d GetChildWindowOffset() const = 0;
-
- // Return false if |this| is hidden, or has a hidden ancestor.
- virtual bool IsVisibleParent() const = 0;
-
- // Removes a child window. Note |this| may be deleted after calling, so the
- // caller should immediately null out the pointer used to make the call.
- virtual void RemoveChildWindow(BridgedNativeWidget* child) = 0;
-
- protected:
- // Instances of this class may be self-deleting.
- virtual ~BridgedNativeWidgetOwner() {}
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_COCOA_BRIDGED_NATIVE_WIDGET_OWNER_H_
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
index 8f3abc65650..3a2248849fd 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
#import <Cocoa/Cocoa.h>
+#include <objc/runtime.h>
#include <memory>
@@ -25,10 +26,7 @@
#include "ui/base/test/material_design_controller_test_api.h"
#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/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"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/controls/textfield/textfield_model.h"
@@ -38,6 +36,9 @@
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
using base::ASCIIToUTF16;
using base::SysNSStringToUTF8;
@@ -121,8 +122,8 @@ NSArray* const kDeleteActions = @[
@"deleteToBeginningOfParagraph:", @"deleteToEndOfParagraph:"
];
-NSArray* const kMiscActions =
- @[ @"insertText:", @"cancelOperation:", @"transpose:", @"yank:" ];
+// This omits @"insertText:":. See BridgedNativeWidgetTest.NilTextInputClient.
+NSArray* const kMiscActions = @[ @"cancelOperation:", @"transpose:", @"yank:" ];
// Empty range shortcut for readibility.
NSRange EmptyRange() {
@@ -293,12 +294,12 @@ NSTextInputContext* g_fake_current_input_context = nullptr;
namespace views {
namespace test {
-// Provides the |parent| argument to construct a BridgedNativeWidget.
+// Provides the |parent| argument to construct a BridgedNativeWidgetImpl.
class MockNativeWidgetMac : public NativeWidgetMac {
public:
explicit MockNativeWidgetMac(internal::NativeWidgetDelegate* delegate)
: NativeWidgetMac(delegate) {}
- using NativeWidgetMac::bridge;
+ using NativeWidgetMac::bridge_impl;
using NativeWidgetMac::bridge_host_for_testing;
// internal::NativeWidgetPrivate:
@@ -311,7 +312,12 @@ class MockNativeWidgetMac : public NativeWidgetMac {
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO]);
- bridge()->SetWindow(window);
+ bridge_host_for_testing()->CreateLocalBridge(window);
+ if (BridgedNativeWidgetHostImpl* parent =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ [params.parent window])) {
+ bridge_host_for_testing()->SetParent(parent);
+ }
bridge_host_for_testing()->InitWindow(params);
// Usually the bridge gets initialized here. It is skipped to run extra
@@ -330,7 +336,7 @@ class MockNativeWidgetMac : public NativeWidgetMac {
DISALLOW_COPY_AND_ASSIGN(MockNativeWidgetMac);
};
-// Helper test base to construct a BridgedNativeWidget with a valid parent.
+// Helper test base to construct a BridgedNativeWidgetImpl with a valid parent.
class BridgedNativeWidgetTestBase : public ui::CocoaTest {
public:
struct SkipInitialization {};
@@ -342,11 +348,27 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
explicit BridgedNativeWidgetTestBase(SkipInitialization tag)
: native_widget_mac_(nullptr) {}
- BridgedNativeWidget* bridge() { return native_widget_mac_->bridge(); }
+ BridgedNativeWidgetImpl* bridge() {
+ return native_widget_mac_->bridge_impl();
+ }
BridgedNativeWidgetHostImpl* bridge_host() {
return native_widget_mac_->bridge_host_for_testing();
}
+ // Generate an autoreleased KeyDown NSEvent* in |widget_| for pressing the
+ // corresponding |key_code|.
+ NSEvent* VkeyKeyDown(ui::KeyboardCode key_code) {
+ return cocoa_test_event_utils::SynthesizeKeyEvent(
+ widget_->GetNativeWindow(), true /* keyDown */, key_code, 0);
+ }
+
+ // Generate an autoreleased KeyDown NSEvent* using the given keycode, and
+ // representing the first unicode character of |chars|.
+ NSEvent* UnicodeKeyDown(int key_code, NSString* chars) {
+ return cocoa_test_event_utils::KeyEventWithKeyCode(
+ key_code, [chars characterAtIndex:0], NSKeyDown, 0);
+ }
+
// Overridden from testing::Test:
void SetUp() override {
ui::CocoaTest::SetUp();
@@ -385,7 +407,9 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
}
NSWindow* bridge_window() const {
- return native_widget_mac_->bridge()->ns_window();
+ if (native_widget_mac_->bridge_impl())
+ return native_widget_mac_->bridge_impl()->ns_window();
+ return nil;
}
protected:
@@ -614,7 +638,8 @@ void BridgedNativeWidgetTest::SetUp() {
// The delegate should exist before setting the root view.
EXPECT_TRUE([window delegate]);
bridge_host()->SetRootView(view_.get());
- bridge()->CreateContentView(view_->bounds());
+ bridge()->CreateContentView(bridge_host()->GetRootViewNSViewId(),
+ view_->bounds());
ns_view_ = bridge()->ns_view();
// Pretend it has been shown via NativeWidgetMac::Show().
@@ -853,7 +878,7 @@ class BridgedNativeWidgetInitTest : public BridgedNativeWidgetTestBase {
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetInitTest);
};
-// Test that BridgedNativeWidget remains sane if Init() is never called.
+// Test that BridgedNativeWidgetImpl remains sane if Init() is never called.
TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) {
// Don't use a Widget* as the delegate. ~Widget() checks for Widget::
// |native_widget_destroyed_| being set to true. That can only happen with a
@@ -862,8 +887,8 @@ TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) {
std::unique_ptr<MockNativeWidgetMac> native_widget(
new MockNativeWidgetMac(nullptr));
native_widget_mac_ = native_widget.get();
- EXPECT_FALSE(bridge()->ns_view());
- EXPECT_FALSE(bridge()->ns_window());
+ EXPECT_FALSE(bridge());
+ EXPECT_FALSE(bridge_host()->GetLocalNSWindow());
}
// Tests the shadow type given in InitParams.
@@ -1323,10 +1348,16 @@ TEST_F(BridgedNativeWidgetTest, NilTextInputClient) {
[selectors addObjectsFromArray:kMoveActions];
[selectors addObjectsFromArray:kSelectActions];
[selectors addObjectsFromArray:kDeleteActions];
+
+ // -insertText: is omitted from this list to avoid a DCHECK in
+ // doCommandBySelector:. AppKit never passes -insertText: to
+ // doCommandBySelector: (it calls -insertText: directly instead).
[selectors addObjectsFromArray:kMiscActions];
for (NSString* selector in selectors)
[ns_view_ doCommandBySelector:NSSelectorFromString(selector)];
+
+ [ns_view_ insertText:@""];
}
// Test transpose command against expectations set by |dummy_text_view_|.
@@ -1434,27 +1465,22 @@ TEST_F(BridgedNativeWidgetTest, TextInput_SimulatePhoneticIme) {
// Sequence of calls (and corresponding keyDown events) obtained via tracing
// with 2-Set Korean IME and pressing q, o, then Enter on the keyboard.
- NSEvent* q_in_ime = cocoa_test_event_utils::KeyEventWithKeyCode(
- 12, [@"ㅂ" characterAtIndex:0], NSKeyDown, 0);
+ NSEvent* q_in_ime = UnicodeKeyDown(12, @"ㅂ");
InterpretKeyEventsCallback handle_q_in_ime = base::BindRepeating([](id view) {
[view insertText:@"ㅂ" replacementRange:NSMakeRange(NSNotFound, 0)];
});
- NSEvent* o_in_ime = cocoa_test_event_utils::KeyEventWithKeyCode(
- 31, [@"ㅐ" characterAtIndex:0], NSKeyDown, 0);
+ NSEvent* o_in_ime = UnicodeKeyDown(31, @"ㅐ");
InterpretKeyEventsCallback handle_o_in_ime = base::BindRepeating([](id view) {
[view insertText:@"배" replacementRange:NSMakeRange(0, 1)];
});
- NSEvent* return_in_ime = cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0);
InterpretKeyEventsCallback handle_return_in_ime =
base::BindRepeating([](id view) {
// When confirming the composition, AppKit repeats itself.
[view insertText:@"배" replacementRange:NSMakeRange(0, 1)];
[view insertText:@"배" replacementRange:NSMakeRange(0, 1)];
- // Note: there is no insertText:@"\r", which we would normally see when
- // not in an IME context for VKEY_RETURN.
+ [view doCommandBySelector:@selector(insertNewLine:)];
});
// Add a hook for the KeyEvent being received by the TextfieldController. E.g.
@@ -1486,7 +1512,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_SimulatePhoneticIme) {
// Note the "Enter" should not replace the replacement range, even though a
// replacement range was set.
g_fake_interpret_key_events = &handle_return_in_ime;
- [ns_view_ keyDown:return_in_ime];
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_RETURN)];
EXPECT_EQ(base::SysNSStringToUTF16(@"배"), textfield->text());
// VKEY_RETURN should be seen by via the unhandled key event handler (but not
@@ -1496,6 +1522,76 @@ TEST_F(BridgedNativeWidgetTest, TextInput_SimulatePhoneticIme) {
g_fake_interpret_key_events = nullptr;
}
+// Test simulated codepaths for typing 'm', 'o', 'o', Enter in the Telex IME.
+// This IME does not mark text, but, unlike 2-set Korean, it re-inserts the
+// entire word on each keypress, even though only the last character in the word
+// can be modified. This prevents the keypress being treated as a "character"
+// event (which is unavoidably unfortunate for the Undo buffer), but also led to
+// a codepath that suppressed a VKEY_RETURN when it should not, since there is
+// no candidate IME window to dismiss for this IME.
+TEST_F(BridgedNativeWidgetTest, TextInput_SimulateTelexMoo) {
+ 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 Telex IME and pressing 'm', 'o', 'o', then Enter on the keyboard.
+ // Note that without the leading 'm', only one character changes, which could
+ // allow the keypress to be treated as a character event, which would not
+ // produce the bug.
+ NSEvent* m_in_ime = UnicodeKeyDown(46, @"m");
+ InterpretKeyEventsCallback handle_m_in_ime = base::BindRepeating([](id view) {
+ [view insertText:@"m" replacementRange:NSMakeRange(NSNotFound, 0)];
+ });
+
+ // Note that (unlike Korean IME), Telex generates a latin "o" for both events:
+ // it doesn't associate a unicode character on the second NSEvent.
+ NSEvent* o_in_ime = UnicodeKeyDown(31, @"o");
+ InterpretKeyEventsCallback handle_first_o_in_ime =
+ base::BindRepeating([](id view) {
+ // Note the whole word is replaced, not just the last character.
+ [view insertText:@"mo" replacementRange:NSMakeRange(0, 1)];
+ });
+ InterpretKeyEventsCallback handle_second_o_in_ime =
+ base::BindRepeating([](id view) {
+ [view insertText:@"mô" replacementRange:NSMakeRange(0, 2)];
+ });
+
+ InterpretKeyEventsCallback handle_return_in_ime =
+ base::BindRepeating([](id view) {
+ // Note the previous -insertText: repeats, even though it is unchanged.
+ // But the IME also follows with an -insertNewLine:.
+ [view insertText:@"mô" replacementRange:NSMakeRange(0, 2)];
+ [view doCommandBySelector:@selector(insertNewLine:)];
+ });
+
+ EXPECT_EQ(base::UTF8ToUTF16(""), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ object_setClass(ns_view_, [InterpretKeyEventMockedBridgedContentView class]);
+ g_fake_interpret_key_events = &handle_m_in_ime;
+ [ns_view_ keyDown:m_in_ime];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"m"), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ g_fake_interpret_key_events = &handle_first_o_in_ime;
+ [ns_view_ keyDown:o_in_ime];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"mo"), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ g_fake_interpret_key_events = &handle_second_o_in_ime;
+ [ns_view_ keyDown:o_in_ime];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"mô"), textfield->text());
+ EXPECT_EQ(0, enter_view->count());
+
+ g_fake_interpret_key_events = &handle_return_in_ime;
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_RETURN)];
+ EXPECT_EQ(base::SysNSStringToUTF16(@"mô"), textfield->text()); // No change.
+ EXPECT_EQ(1, enter_view->count()); // Now we see the accelerator.
+}
+
// Simulate 'a', Enter in Hiragana. This should just insert "あ", suppressing
// accelerators.
TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorEnterComposition) {
@@ -1507,8 +1603,8 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorEnterComposition) {
// 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);
+ // Note 0 is the actual keyCode for 'a', not a placeholder.
+ NSEvent* a_in_ime = UnicodeKeyDown(0, @"a");
InterpretKeyEventsCallback handle_a_in_ime = base::BindRepeating([](id view) {
// TODO(crbug/612675): |text| should be an NSAttributedString.
[view setMarkedText:@"あ"
@@ -1516,12 +1612,13 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorEnterComposition) {
replacementRange:NSMakeRange(NSNotFound, 0)];
});
- NSEvent* return_event = cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0);
- InterpretKeyEventsCallback handle_return_in_ime =
+ InterpretKeyEventsCallback handle_first_return_in_ime =
base::BindRepeating([](id view) {
[view insertText:@"あ" replacementRange:NSMakeRange(NSNotFound, 0)];
+ // Note there is no call to -insertNewLine: here.
});
+ InterpretKeyEventsCallback handle_second_return_in_ime = base::BindRepeating(
+ [](id view) { [view doCommandBySelector:@selector(insertNewLine:)]; });
EXPECT_EQ(base::UTF8ToUTF16(""), textfield->text());
EXPECT_EQ(0, enter_view->count());
@@ -1532,16 +1629,14 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorEnterComposition) {
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];
+ g_fake_interpret_key_events = &handle_first_return_in_ime;
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_RETURN)];
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.
+ g_fake_interpret_key_events = &handle_second_return_in_ime;
+ [ns_view_
+ keyDown:VkeyKeyDown(ui::VKEY_RETURN)]; // Sanity check: send Enter again.
EXPECT_EQ(base::SysNSStringToUTF16(@"あ"), textfield->text()); // No change.
EXPECT_EQ(1, enter_view->count()); // Now we see the accelerator.
}
@@ -1557,8 +1652,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorTabEnterComposition) {
// 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);
+ NSEvent* a_in_ime = UnicodeKeyDown(0, @"a");
InterpretKeyEventsCallback handle_a_in_ime = base::BindRepeating([](id view) {
// TODO(crbug/612675): |text| should have an underline.
[view setMarkedText:@"あ"
@@ -1566,8 +1660,6 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorTabEnterComposition) {
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
@@ -1575,10 +1667,9 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorTabEnterComposition) {
[view setMarkedText:@"a"
selectedRange:NSMakeRange(0, 1)
replacementRange:NSMakeRange(NSNotFound, 0)];
+ // Note there is no -insertTab: generated.
});
- 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
@@ -1589,6 +1680,11 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorTabEnterComposition) {
// The second return will confirm the composition.
[view insertText:@"a" replacementRange:NSMakeRange(NSNotFound, 0)];
});
+ InterpretKeyEventsCallback handle_third_return_in_ime =
+ base::BindRepeating([](id view) {
+ // Only the third return will generate -insertNewLine:.
+ [view doCommandBySelector:@selector(insertNewLine:)];
+ });
EXPECT_EQ(base::UTF8ToUTF16(""), textfield->text());
EXPECT_EQ(0, enter_view->count());
@@ -1600,28 +1696,26 @@ TEST_F(BridgedNativeWidgetTest, TextInput_NoAcceleratorTabEnterComposition) {
EXPECT_EQ(0, enter_view->count());
g_fake_interpret_key_events = &handle_tab_in_ime;
- [ns_view_ keyDown:tab_in_ime];
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_TAB)];
// 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];
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_RETURN)];
// 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];
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_RETURN)];
// 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.
+ g_fake_interpret_key_events = &handle_third_return_in_ime;
+ [ns_view_ keyDown:VkeyKeyDown(ui::VKEY_RETURN)]; // 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.
}
@@ -1754,8 +1848,8 @@ TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
object:window];
// On a failure, Cocoa starts by sending an unexpected *exit* fullscreen, and
- // BridgedNativeWidget will think it's just a delayed transition and try to go
- // back into fullscreen but get ignored by Cocoa.
+ // BridgedNativeWidgetImpl will think it's just a delayed transition and try
+ // to go back into fullscreen but get ignored by Cocoa.
EXPECT_EQ(0, [window ignoredToggleFullScreenCount]);
EXPECT_TRUE(bridge()->target_fullscreen_state());
[center postNotificationName:NSWindowDidExitFullScreenNotification
diff --git a/chromium/ui/views/cocoa/cocoa_mouse_capture.h b/chromium/ui/views/cocoa/cocoa_mouse_capture.h
deleted file mode 100644
index 9b170e4a7e9..00000000000
--- a/chromium/ui/views/cocoa/cocoa_mouse_capture.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_H_
-#define UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "ui/views/views_export.h"
-
-@class NSWindow;
-
-namespace views {
-
-class CocoaMouseCaptureDelegate;
-
-// Basic mouse capture to simulate ::SetCapture() from Windows. This is used to
-// support menu widgets (e.g. on Combo boxes). Clicking anywhere other than the
-// menu should dismiss the menu and "swallow" the mouse event. All events are
-// forwarded, but only events to the same application are "swallowed", which is
-// consistent with how native NSMenus behave.
-class VIEWS_EXPORT CocoaMouseCapture {
- public:
- explicit CocoaMouseCapture(CocoaMouseCaptureDelegate* delegate);
- ~CocoaMouseCapture();
-
- // Returns the NSWindow with capture or nil if no window has capture
- // currently.
- static NSWindow* GetGlobalCaptureWindow();
-
- // True if the event tap is active (i.e. not stolen by a later instance).
- bool IsActive() const { return !!active_handle_; }
-
- private:
- class ActiveEventTap;
-
- // Deactivates the event tap if still active.
- void OnOtherClientGotCapture();
-
- CocoaMouseCaptureDelegate* delegate_; // Weak. Owns this.
-
- // The active event tap for this capture. Owned by this, but can be cleared
- // out early if another instance of CocoaMouseCapture is created.
- std::unique_ptr<ActiveEventTap> active_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(CocoaMouseCapture);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_H_
diff --git a/chromium/ui/views/cocoa/cocoa_mouse_capture.mm b/chromium/ui/views/cocoa/cocoa_mouse_capture.mm
deleted file mode 100644
index b1f3cb216de..00000000000
--- a/chromium/ui/views/cocoa/cocoa_mouse_capture.mm
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/cocoa_mouse_capture.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "ui/base/cocoa/weak_ptr_nsobject.h"
-#import "ui/views/cocoa/cocoa_mouse_capture_delegate.h"
-
-namespace views {
-
-// The ActiveEventTap is a RAII handle on the resources being used to capture
-// events. There is either 0 or 1 active instance of this class. If a second
-// instance is created, it will destroy the other instance before returning from
-// its constructor.
-class CocoaMouseCapture::ActiveEventTap {
- public:
- explicit ActiveEventTap(CocoaMouseCapture* owner);
- ~ActiveEventTap();
-
- // Returns the NSWindow with capture or nil if no window has capture
- // currently.
- static NSWindow* GetGlobalCaptureWindow();
-
- void Init();
-
- private:
- // Returns the associated NSWindow with capture.
- NSWindow* GetCaptureWindow() const;
-
- // The currently active event tap, or null if there is none.
- static ActiveEventTap* g_active_event_tap;
-
- CocoaMouseCapture* owner_; // Weak. Owns this.
- id local_monitor_;
- id global_monitor_;
- ui::WeakPtrNSObjectFactory<CocoaMouseCapture> factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ActiveEventTap);
-};
-
-CocoaMouseCapture::ActiveEventTap*
- CocoaMouseCapture::ActiveEventTap::g_active_event_tap = nullptr;
-
-CocoaMouseCapture::ActiveEventTap::ActiveEventTap(CocoaMouseCapture* owner)
- : owner_(owner),
- local_monitor_(nil),
- global_monitor_(nil),
- factory_(owner) {
- if (g_active_event_tap)
- g_active_event_tap->owner_->OnOtherClientGotCapture();
- DCHECK(!g_active_event_tap);
- g_active_event_tap = this;
-}
-
-CocoaMouseCapture::ActiveEventTap::~ActiveEventTap() {
- DCHECK_EQ(g_active_event_tap, this);
- [NSEvent removeMonitor:global_monitor_];
- [NSEvent removeMonitor:local_monitor_];
- g_active_event_tap = nullptr;
- owner_->delegate_->OnMouseCaptureLost();
-}
-
-// static
-NSWindow* CocoaMouseCapture::ActiveEventTap::GetGlobalCaptureWindow() {
- return g_active_event_tap ? g_active_event_tap->GetCaptureWindow() : nil;
-}
-
-void CocoaMouseCapture::ActiveEventTap::Init() {
- // Consume most things, but not NSMouseEntered/Exited: The Widget doing
- // capture will still see its own Entered/Exit events, but not those for other
- // NSViews, since consuming those would break their tracking area logic.
- NSEventMask event_mask =
- NSLeftMouseDownMask | NSLeftMouseUpMask | NSRightMouseDownMask |
- NSRightMouseUpMask | NSMouseMovedMask | NSLeftMouseDraggedMask |
- NSRightMouseDraggedMask | NSScrollWheelMask | NSOtherMouseDownMask |
- NSOtherMouseUpMask | NSOtherMouseDraggedMask;
-
- // Capture a WeakPtr via NSObject. This allows the block to detect another
- // event monitor for the same event deleting |owner_|.
- WeakPtrNSObject* handle = factory_.handle();
-
- auto local_block = ^NSEvent*(NSEvent* event) {
- CocoaMouseCapture* owner =
- ui::WeakPtrNSObjectFactory<CocoaMouseCapture>::Get(handle);
- if (owner)
- owner->delegate_->PostCapturedEvent(event);
- return nil; // Swallow all local events.
- };
- auto global_block = ^void(NSEvent* event) {
- CocoaMouseCapture* owner =
- ui::WeakPtrNSObjectFactory<CocoaMouseCapture>::Get(handle);
- if (owner)
- owner->delegate_->PostCapturedEvent(event);
- };
- local_monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:event_mask
- handler:local_block];
- global_monitor_ =
- [NSEvent addGlobalMonitorForEventsMatchingMask:event_mask
- handler:global_block];
-}
-
-NSWindow* CocoaMouseCapture::ActiveEventTap::GetCaptureWindow() const {
- return owner_->delegate_->GetWindow();
-}
-
-CocoaMouseCapture::CocoaMouseCapture(CocoaMouseCaptureDelegate* delegate)
- : delegate_(delegate), active_handle_(new ActiveEventTap(this)) {
- active_handle_->Init();
-}
-
-CocoaMouseCapture::~CocoaMouseCapture() {}
-
-// static
-NSWindow* CocoaMouseCapture::GetGlobalCaptureWindow() {
- return ActiveEventTap::GetGlobalCaptureWindow();
-}
-
-void CocoaMouseCapture::OnOtherClientGotCapture() {
- DCHECK(active_handle_);
- active_handle_.reset();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/cocoa/cocoa_mouse_capture_delegate.h b/chromium/ui/views/cocoa/cocoa_mouse_capture_delegate.h
deleted file mode 100644
index 9e6d2a0e4ea..00000000000
--- a/chromium/ui/views/cocoa/cocoa_mouse_capture_delegate.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_DELEGATE_H_
-#define UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_DELEGATE_H_
-
-@class NSEvent;
-@class NSWindow;
-
-namespace views {
-
-// Delegate for receiving captured events from a CocoaMouseCapture.
-class CocoaMouseCaptureDelegate {
- public:
- // Called when an event has been captured. This may be an event local to the
- // application, or a global event (sent to another application). If it is a
- // local event, regular event handling will be suppressed.
- virtual void PostCapturedEvent(NSEvent* event) = 0;
-
- // Called once. When another window acquires capture, or when the
- // CocoaMouseCapture is destroyed.
- virtual void OnMouseCaptureLost() = 0;
-
- // Returns the associated NSWindow.
- virtual NSWindow* GetWindow() const = 0;
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_COCOA_COCOA_MOUSE_CAPTURE_DELEGATE_H_
diff --git a/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm b/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm
index 47235a7fcff..295e0617cd8 100644
--- a/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm
+++ b/chromium/ui/views/cocoa/cocoa_mouse_capture_unittest.mm
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import "ui/views/cocoa/cocoa_mouse_capture.h"
+#import "ui/views_bridge_mac/cocoa_mouse_capture.h"
#import <Cocoa/Cocoa.h>
@@ -10,7 +10,7 @@
#include "base/macros.h"
#import "ui/base/test/cocoa_helper.h"
#import "ui/events/test/cocoa_test_event_utils.h"
-#import "ui/views/cocoa/cocoa_mouse_capture_delegate.h"
+#import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h"
// Simple test view that counts calls to -[NSView mouseDown:].
@interface CocoaMouseCaptureTestView : NSView {
@@ -30,7 +30,7 @@
@end
-namespace views {
+namespace views_bridge_mac {
namespace {
// Simple capture delegate that just counts events forwarded.
@@ -128,4 +128,4 @@ TEST_F(CocoaMouseCaptureTest, CaptureEvents) {
EXPECT_EQ(2, [view mouseDownCount]);
}
-} // namespace views
+} // namespace views_bridge_mac
diff --git a/chromium/ui/views/cocoa/cocoa_window_move_loop.h b/chromium/ui/views/cocoa/cocoa_window_move_loop.h
deleted file mode 100644
index e688884facb..00000000000
--- a/chromium/ui/views/cocoa/cocoa_window_move_loop.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
-#define UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-class BridgedNativeWidget;
-
-// Used by views::BridgedNativeWidget when dragging detached tabs.
-class CocoaWindowMoveLoop {
- public:
- CocoaWindowMoveLoop(BridgedNativeWidget* owner,
- const NSPoint& initial_mouse_in_screen);
- ~CocoaWindowMoveLoop();
-
- // Initiates the drag until a mouse up event is observed, or End() is called.
- Widget::MoveLoopResult Run();
- void End();
-
- private:
- enum LoopExitReason {
- ENDED_EXTERNALLY,
- MOUSE_UP,
- WINDOW_DESTROYED,
- };
-
- BridgedNativeWidget* owner_; // Weak. Owns this.
-
- // Initial mouse location at the time before the CocoaWindowMoveLoop is
- // created.
- NSPoint initial_mouse_in_screen_;
-
- // Pointer to a stack variable holding the exit reason.
- LoopExitReason* exit_reason_ref_ = nullptr;
- base::Closure quit_closure_;
-
- // WeakPtrFactory for event monitor safety.
- base::WeakPtrFactory<CocoaWindowMoveLoop> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(CocoaWindowMoveLoop);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
diff --git a/chromium/ui/views/cocoa/cocoa_window_move_loop.mm b/chromium/ui/views/cocoa/cocoa_window_move_loop.mm
deleted file mode 100644
index a306f9cfb5c..00000000000
--- a/chromium/ui/views/cocoa/cocoa_window_move_loop.mm
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/cocoa/cocoa_window_move_loop.h"
-
-#include "base/run_loop.h"
-#include "ui/display/screen.h"
-#import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
-
-// When event monitors process the events the full list of monitors is cached,
-// and if we unregister the event monitor that's at the end of the list while
-// processing the first monitor's handler -- the callback for the unregistered
-// monitor will still be called even though it's unregistered. This will result
-// in dereferencing an invalid pointer.
-//
-// WeakCocoaWindowMoveLoop is retained by the event monitor and stores weak
-// pointer for the CocoaWindowMoveLoop, so there will be no invalid memory
-// access.
-@interface WeakCocoaWindowMoveLoop : NSObject {
- @private
- base::WeakPtr<views::CocoaWindowMoveLoop> weak_;
-}
-@end
-
-@implementation WeakCocoaWindowMoveLoop
-- (id)initWithWeakPtr:(const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
- if ((self = [super init])) {
- weak_ = weak;
- }
- return self;
-}
-
-- (base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
- return weak_;
-}
-@end
-
-namespace views {
-
-CocoaWindowMoveLoop::CocoaWindowMoveLoop(
- BridgedNativeWidget* owner,
- const NSPoint& initial_mouse_in_screen)
- : owner_(owner),
- initial_mouse_in_screen_(initial_mouse_in_screen),
- weak_factory_(this) {
-}
-
-CocoaWindowMoveLoop::~CocoaWindowMoveLoop() {
- // Handle the pathological case, where |this| is destroyed while running.
- if (exit_reason_ref_) {
- *exit_reason_ref_ = WINDOW_DESTROYED;
- quit_closure_.Run();
- }
-
- owner_ = nullptr;
-}
-
-Widget::MoveLoopResult CocoaWindowMoveLoop::Run() {
- LoopExitReason exit_reason = ENDED_EXTERNALLY;
- exit_reason_ref_ = &exit_reason;
- NSWindow* window = owner_->ns_window();
- const NSRect initial_frame = [window frame];
-
- base::RunLoop run_loop;
- quit_closure_ = run_loop.QuitClosure();
-
- // Will be retained by the monitor handler block.
- WeakCocoaWindowMoveLoop* weak_cocoa_window_move_loop =
- [[[WeakCocoaWindowMoveLoop alloc]
- initWithWeakPtr:weak_factory_.GetWeakPtr()] autorelease];
-
- // Esc keypress is handled by EscapeTracker, which is installed by
- // TabDragController.
- NSEventMask mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
- auto handler = ^NSEvent*(NSEvent* event) {
- CocoaWindowMoveLoop* strong = [weak_cocoa_window_move_loop weak].get();
- if (!strong || !strong->exit_reason_ref_) {
- // By this point CocoaWindowMoveLoop was deleted while processing this
- // same event, and this event monitor was not unregistered in time. See
- // the WeakCocoaWindowMoveLoop comment above.
- // Continue processing the event.
- return event;
- }
-
- if ([event type] == NSLeftMouseDragged) {
- const NSPoint mouse_in_screen = [NSEvent mouseLocation];
-
- const NSRect ns_frame = NSOffsetRect(
- initial_frame, mouse_in_screen.x - initial_mouse_in_screen_.x,
- mouse_in_screen.y - initial_mouse_in_screen_.y);
- [window setFrame:ns_frame display:NO animate:NO];
-
- return event;
- }
-
- DCHECK_EQ([event type], NSLeftMouseUp);
- *strong->exit_reason_ref_ = MOUSE_UP;
- strong->quit_closure_.Run();
- return event; // Process the MouseUp.
- };
- id monitor =
- [NSEvent addLocalMonitorForEventsMatchingMask:mask handler:handler];
-
- run_loop.Run();
- [NSEvent removeMonitor:monitor];
-
- if (exit_reason != WINDOW_DESTROYED && exit_reason != ENDED_EXTERNALLY) {
- exit_reason_ref_ = nullptr; // Ensure End() doesn't replace the reason.
- owner_->EndMoveLoop(); // Deletes |this|.
- }
-
- return exit_reason != MOUSE_UP ? Widget::MOVE_LOOP_CANCELED
- : Widget::MOVE_LOOP_SUCCESSFUL;
-}
-
-void CocoaWindowMoveLoop::End() {
- if (exit_reason_ref_) {
- DCHECK_EQ(*exit_reason_ref_, ENDED_EXTERNALLY);
- // Ensure the destructor doesn't replace the reason.
- exit_reason_ref_ = nullptr;
- quit_closure_.Run();
- }
-}
-
-} // namespace views
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac.h b/chromium/ui/views/cocoa/drag_drop_client_mac.h
index 2e1129957b4..e93d8a09441 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac.h
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac.h
@@ -14,6 +14,7 @@
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/drop_helper.h"
+#include "ui/views_bridge_mac/drag_drop_client.h"
// This class acts as a bridge between NSPasteboardItem and OSExchangeData by
// implementing NSPasteboardItemDataProvider and writing data from
@@ -32,16 +33,16 @@ namespace test {
class DragDropClientMacTest;
}
-class BridgedNativeWidget;
+class BridgedNativeWidgetImpl;
class View;
// Implements drag and drop on MacViews. This class acts as a bridge between
// the Views and native system's drag and drop. This class mimics
// DesktopDragDropClientAuraX11.
-class VIEWS_EXPORT DragDropClientMac {
+class VIEWS_EXPORT DragDropClientMac : public views_bridge_mac::DragDropClient {
public:
- explicit DragDropClientMac(BridgedNativeWidget* bridge, View* root_view);
- ~DragDropClientMac();
+ DragDropClientMac(BridgedNativeWidgetImpl* bridge, View* root_view);
+ ~DragDropClientMac() override;
// Initiates a drag and drop session. Returns the drag operation that was
// applied at the end of the drag drop session.
@@ -50,20 +51,14 @@ class VIEWS_EXPORT DragDropClientMac {
int operation,
ui::DragDropTypes::DragEventSource source);
- // Called when mouse is dragged during a drag and drop.
- NSDragOperation DragUpdate(id<NSDraggingInfo>);
-
- // Called when mouse is released during a drag and drop.
- NSDragOperation Drop(id<NSDraggingInfo> sender);
-
- // Called when the drag and drop session has ended.
- void EndDrag();
-
- // Called when mouse leaves the drop area.
- void DragExit();
-
DropHelper* drop_helper() { return &drop_helper_; }
+ // views_bridge_mac::DragDropClient:
+ NSDragOperation DragUpdate(id<NSDraggingInfo>) override;
+ NSDragOperation Drop(id<NSDraggingInfo> sender) override;
+ void EndDrag() override;
+ void DragExit() override;
+
private:
friend class test::DragDropClientMacTest;
@@ -80,7 +75,7 @@ class VIEWS_EXPORT DragDropClientMac {
int operation_;
// The bridge between the content view and the drag drop client.
- BridgedNativeWidget* bridge_; // Weak. Owns |this|.
+ BridgedNativeWidgetImpl* bridge_; // Weak. Owns |this|.
// The closure for the drag and drop's run loop.
base::Closure quit_closure_;
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac.mm b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
index 78e7b0b3226..2df33355f9e 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
@@ -10,9 +10,9 @@
#import "ui/base/dragdrop/os_exchange_data_provider_mac.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#include "ui/views/drag_utils.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
#include "ui/views/widget/native_widget_mac.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
@interface CocoaDragDropDataProvider ()
- (id)initWithData:(const ui::OSExchangeData&)data;
@@ -57,7 +57,7 @@
namespace views {
-DragDropClientMac::DragDropClientMac(BridgedNativeWidget* bridge,
+DragDropClientMac::DragDropClientMac(BridgedNativeWidgetImpl* bridge,
View* root_view)
: drop_helper_(root_view),
operation_(0),
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 9f3559de2ef..4202d53a348 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -13,12 +13,12 @@
#include "base/threading/thread_task_runner_handle.h"
#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"
#include "ui/views/widget/widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
using base::ASCIIToUTF16;
@@ -156,7 +156,9 @@ class DragDropClientMacTest : public WidgetTest {
public:
DragDropClientMacTest() : widget_(new Widget) {}
- DragDropClientMac* drag_drop_client() { return bridge_->drag_drop_client(); }
+ DragDropClientMac* drag_drop_client() {
+ return bridge_host_->drag_drop_client();
+ }
NSDragOperation DragUpdate(NSPasteboard* pasteboard) {
DragDropClientMac* client = drag_drop_client();
@@ -186,9 +188,9 @@ class DragDropClientMacTest : public WidgetTest {
gfx::Rect bounds(0, 0, 100, 100);
widget_->SetBounds(bounds);
- bridge_ =
- NativeWidgetMac::GetBridgeForNativeWindow(widget_->GetNativeWindow());
- bridge_host_ = NativeWidgetMac::GetBridgeHostImplForNativeWindow(
+ bridge_ = BridgedNativeWidgetImpl::GetFromNativeWindow(
+ widget_->GetNativeWindow());
+ bridge_host_ = BridgedNativeWidgetHostImpl::GetFromNativeWindow(
widget_->GetNativeWindow());
widget_->Show();
@@ -207,7 +209,7 @@ class DragDropClientMacTest : public WidgetTest {
protected:
Widget* widget_ = nullptr;
- BridgedNativeWidget* bridge_ = nullptr;
+ BridgedNativeWidgetImpl* bridge_ = nullptr;
BridgedNativeWidgetHostImpl* bridge_host_ = nullptr;
DragDropView* target_ = nullptr;
base::scoped_nsobject<MockDraggingInfo> dragging_info_;
diff --git a/chromium/ui/views/cocoa/native_widget_mac_nswindow.h b/chromium/ui/views/cocoa/native_widget_mac_nswindow.h
deleted file mode 100644
index 8a0f51b791b..00000000000
--- a/chromium/ui/views/cocoa/native_widget_mac_nswindow.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
-#define UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "ui/base/cocoa/command_dispatcher.h"
-#include "ui/views/views_export.h"
-#include "ui/views/widget/util_mac.h"
-
-@protocol WindowTouchBarDelegate;
-
-// Weak lets Chrome launch even if a future macOS doesn't have the below classes
-
-WEAK_IMPORT_ATTRIBUTE
-@interface NSNextStepFrame : NSView
-@end
-
-@class NSThemeFrame;
-
-VIEWS_EXPORT
-@interface NativeWidgetMacNSWindowBorderlessFrame : NSNextStepFrame
-@end
-
-VIEWS_EXPORT
-@interface NativeWidgetMacNSWindowTitledFrame : NSThemeFrame
-@end
-
-// The NSWindow used by BridgedNativeWidget. Provides hooks into AppKit that
-// can only be accomplished by overriding methods.
-VIEWS_EXPORT
-@interface NativeWidgetMacNSWindow : NSWindow<CommandDispatchingWindow>
-
-// Set a CommandDispatcherDelegate, i.e. to implement key event handling.
-- (void)setCommandDispatcherDelegate:(id<CommandDispatcherDelegate>)delegate;
-
-// Selector passed to [NSApp beginSheet:]. Forwards to [self delegate], if set.
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)contextInfo;
-
-// Set a WindowTouchBarDelegate to allow creation of a custom TouchBar when
-// AppKit follows the responder chain and reaches the NSWindow when trying to
-// create one.
-- (void)setWindowTouchBarDelegate:(id<WindowTouchBarDelegate>)delegate;
-
-@end
-
-#endif // UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
diff --git a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm b/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
deleted file mode 100644
index 3e5775bc184..00000000000
--- a/chromium/ui/views/cocoa/native_widget_mac_nswindow.mm
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
-
-#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"
-#include "ui/views/controls/menu/menu_controller.h"
-#include "ui/views/widget/native_widget_mac.h"
-#include "ui/views/widget/widget_delegate.h"
-
-@interface NSWindow (Private)
-+ (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle;
-- (BOOL)hasKeyAppearance;
-- (long long)_resizeDirectionForMouseLocation:(CGPoint)location;
-
-// Available in later point releases of 10.10. On 10.11+, use the public
-// -performWindowDragWithEvent: instead.
-- (void)beginWindowDragWithEvent:(NSEvent*)event;
-@end
-
-@interface NativeWidgetMacNSWindow ()
-- (ViewsNSWindowDelegate*)viewsNSWindowDelegate;
-- (views::Widget*)viewsWidget;
-- (BOOL)hasViewsMenuActive;
-- (id)rootAccessibilityObject;
-
-// Private API on NSWindow, determines whether the title is drawn on the title
-// bar. The title is still visible in menus, Expose, etc.
-- (BOOL)_isTitleHidden;
-@end
-
-// Use this category to implement mouseDown: on multiple frame view classes
-// with different superclasses.
-@interface NSView (CRFrameViewAdditions)
-- (void)cr_mouseDownOnFrameView:(NSEvent*)event;
-@end
-
-@implementation NSView (CRFrameViewAdditions)
-// If a mouseDown: falls through to the frame view, turn it into a window drag.
-- (void)cr_mouseDownOnFrameView:(NSEvent*)event {
- if ([self.window _resizeDirectionForMouseLocation:event.locationInWindow] !=
- -1)
- return;
- if (@available(macOS 10.11, *))
- [self.window performWindowDragWithEvent:event];
- else if ([self.window
- respondsToSelector:@selector(beginWindowDragWithEvent:)])
- [self.window beginWindowDragWithEvent:event];
- else
- NOTREACHED();
-}
-@end
-
-@implementation NativeWidgetMacNSWindowTitledFrame
-- (void)mouseDown:(NSEvent*)event {
- [self cr_mouseDownOnFrameView:event];
- [super mouseDown:event];
-}
-- (BOOL)usesCustomDrawing {
- return NO;
-}
-@end
-
-@implementation NativeWidgetMacNSWindowBorderlessFrame
-- (void)mouseDown:(NSEvent*)event {
- [self cr_mouseDownOnFrameView:event];
- [super mouseDown:event];
-}
-- (BOOL)usesCustomDrawing {
- return NO;
-}
-@end
-
-@implementation NativeWidgetMacNSWindow {
- @private
- base::scoped_nsobject<CommandDispatcher> commandDispatcher_;
- base::scoped_nsprotocol<id<UserInterfaceItemCommandHandler>> commandHandler_;
- id<WindowTouchBarDelegate> touchBarDelegate_; // Weak.
-}
-
-- (instancetype)initWithContentRect:(NSRect)contentRect
- styleMask:(NSUInteger)windowStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)deferCreation {
- DCHECK(NSEqualRects(contentRect, ui::kWindowSizeDeterminedLater));
- if ((self = [super initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:windowStyle
- backing:bufferingType
- defer:deferCreation])) {
- commandDispatcher_.reset([[CommandDispatcher alloc] initWithOwner:self]);
- }
- return self;
-}
-
-// This override doesn't do anything, but keeping it helps diagnose lifetime
-// issues in crash stacktraces by inserting a symbol on NativeWidgetMacNSWindow.
-- (void)dealloc {
- [super dealloc];
-}
-
-// Public methods.
-
-- (void)setCommandDispatcherDelegate:(id<CommandDispatcherDelegate>)delegate {
- [commandDispatcher_ setDelegate:delegate];
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)contextInfo {
- // Note BridgedNativeWidget may have cleared [self delegate], in which case
- // this will no-op. This indirection is necessary to handle AppKit invoking
- // this selector via a posted task. See https://crbug.com/851376.
- [[self viewsNSWindowDelegate] sheetDidEnd:sheet
- returnCode:returnCode
- contextInfo:contextInfo];
-}
-
-- (void)setWindowTouchBarDelegate:(id<WindowTouchBarDelegate>)delegate {
- touchBarDelegate_ = delegate;
-}
-
-// Private methods.
-
-- (ViewsNSWindowDelegate*)viewsNSWindowDelegate {
- return base::mac::ObjCCastStrict<ViewsNSWindowDelegate>([self delegate]);
-}
-
-- (views::Widget*)viewsWidget {
- return [[self viewsNSWindowDelegate] nativeWidgetMac]->GetWidget();
-}
-
-- (BOOL)hasViewsMenuActive {
- views::MenuController* menuController =
- views::MenuController::GetActiveInstance();
- return menuController && menuController->owner() == [self viewsWidget];
-}
-
-- (id)rootAccessibilityObject {
- views::Widget* widget = [self viewsWidget];
- return widget ? widget->GetRootView()->GetNativeViewAccessible() : nil;
-}
-
-// NSWindow overrides.
-
-+ (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle {
- if (windowStyle & NSWindowStyleMaskTitled) {
- if (Class customFrame = [NativeWidgetMacNSWindowTitledFrame class])
- return customFrame;
- } else if (Class customFrame =
- [NativeWidgetMacNSWindowBorderlessFrame class]) {
- return customFrame;
- }
- return [super frameViewClassForStyleMask:windowStyle];
-}
-
-- (BOOL)_isTitleHidden {
- if (![self delegate])
- return NO;
-
- return ![self viewsWidget]->widget_delegate()->ShouldShowWindowTitle();
-}
-
-// The base implementation returns YES if the window's frame view is a custom
-// class, which causes undesirable changes in behavior. AppKit NSWindow
-// subclasses are known to override it and return NO.
-- (BOOL)_usesCustomDrawing {
- return NO;
-}
-
-// Ignore [super canBecome{Key,Main}Window]. The default is NO for windows with
-// NSBorderlessWindowMask, which is not the desired behavior.
-// Note these can be called via -[NSWindow close] while the widget is being torn
-// down, so check for a delegate.
-- (BOOL)canBecomeKeyWindow {
- return [self delegate] && [self viewsWidget]->CanActivate();
-}
-
-- (BOOL)canBecomeMainWindow {
- if (![self delegate])
- return NO;
-
- // Dialogs and bubbles shouldn't take large shadows away from their parent.
- views::Widget* widget = [self viewsWidget];
- return widget->CanActivate() &&
- !views::NativeWidgetMac::GetBridgeForNativeWindow(self)->parent();
-}
-
-// Lets the traffic light buttons on the parent window keep their active state.
-- (BOOL)hasKeyAppearance {
- if ([self delegate] && [self viewsWidget]->IsAlwaysRenderAsActive())
- return YES;
- return [super hasKeyAppearance];
-}
-
-// Override sendEvent to intercept window drag events and allow key events to be
-// forwarded to a toolkit-views menu while it is active, and while still
-// allowing any native subview to retain firstResponder status.
-- (void)sendEvent:(NSEvent*)event {
- // Let CommandDispatcher check if this is a redispatched event.
- if ([commandDispatcher_ preSendEvent:event])
- return;
-
- NSEventType type = [event type];
- if ((type != NSKeyDown && type != NSKeyUp) || ![self hasViewsMenuActive]) {
- [super sendEvent:event];
- return;
- }
-
- // Send to the menu, after converting the event into an action message using
- // the content view.
- if (type == NSKeyDown)
- [[self contentView] keyDown:event];
- else
- [[self contentView] keyUp:event];
-}
-
-// Override window order functions to intercept other visibility changes. This
-// is needed in addition to the -[NSWindow display] override because Cocoa
-// hardly ever calls display, and reports -[NSWindow isVisible] incorrectly
-// when ordering in a window for the first time.
-- (void)orderWindow:(NSWindowOrderingMode)orderingMode
- relativeTo:(NSInteger)otherWindowNumber {
- [super orderWindow:orderingMode relativeTo:otherWindowNumber];
- [[self viewsNSWindowDelegate] onWindowOrderChanged:nil];
-}
-
-// NSResponder implementation.
-
-- (BOOL)performKeyEquivalent:(NSEvent*)event {
- return [commandDispatcher_ performKeyEquivalent:event];
-}
-
-- (void)cursorUpdate:(NSEvent*)theEvent {
- // The cursor provided by the delegate should only be applied within the
- // content area. This is because we rely on the contentView to track the
- // mouse cursor and forward cursorUpdate: messages up the responder chain.
- // The cursorUpdate: isn't handled in BridgedContentView because views-style
- // SetCapture() conflicts with the way tracking events are processed for
- // the view during a drag. Since the NSWindow is still in the responder chain
- // overriding cursorUpdate: here handles both cases.
- if (!NSPointInRect([theEvent locationInWindow], [[self contentView] frame])) {
- [super cursorUpdate:theEvent];
- return;
- }
-
- NSCursor* cursor = [[self viewsNSWindowDelegate] cursor];
- if (cursor)
- [cursor set];
- else
- [super cursorUpdate:theEvent];
-}
-
-- (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2)) {
- return touchBarDelegate_ ? [touchBarDelegate_ makeTouchBar] : nil;
-}
-
-// CommandDispatchingWindow implementation.
-
-- (void)setCommandHandler:(id<UserInterfaceItemCommandHandler>)commandHandler {
- commandHandler_.reset([commandHandler retain]);
-}
-
-- (CommandDispatcher*)commandDispatcher {
- return commandDispatcher_.get();
-}
-
-- (BOOL)defaultPerformKeyEquivalent:(NSEvent*)event {
- return [super performKeyEquivalent:event];
-}
-
-- (BOOL)defaultValidateUserInterfaceItem:
- (id<NSValidatedUserInterfaceItem>)item {
- return [super validateUserInterfaceItem:item];
-}
-
-- (void)commandDispatch:(id)sender {
- [commandDispatcher_ dispatch:sender forHandler:commandHandler_];
-}
-
-- (void)commandDispatchUsingKeyModifiers:(id)sender {
- [commandDispatcher_ dispatchUsingKeyModifiers:sender
- forHandler:commandHandler_];
-}
-
-// NSWindow overrides (NSUserInterfaceItemValidations implementation)
-
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
- return [commandDispatcher_ validateUserInterfaceItem:item
- forHandler:commandHandler_];
-}
-
-// NSWindow overrides (NSAccessibility informal protocol implementation).
-
-- (id)accessibilityFocusedUIElement {
- if (![self delegate])
- return [super accessibilityFocusedUIElement];
-
- // The SDK documents this as "The deepest descendant of the accessibility
- // hierarchy that has the focus" and says "if a child element does not have
- // the focus, either return self or, if available, invoke the superclass's
- // implementation."
- // The behavior of NSWindow is usually to return null, except when the window
- // is first shown, when it returns self. But in the second case, we can
- // provide richer a11y information by reporting the views::RootView instead.
- // Additionally, if we don't do this, VoiceOver reads out the partial a11y
- // properties on the NSWindow and repeats them when focusing an item in the
- // RootView's a11y group. See http://crbug.com/748221.
- views::Widget* widget = [self viewsWidget];
- id superFocus = [super accessibilityFocusedUIElement];
- if (!widget || superFocus != self)
- return superFocus;
-
- return widget->GetRootView()->GetNativeViewAccessible();
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- // Check when NSWindow is asked for its title to provide the title given by
- // the views::RootView (and WidgetDelegate::GetAccessibleWindowTitle()). For
- // all other attributes, use what NSWindow provides by default since diverging
- // from NSWindow's behavior can easily break VoiceOver integration.
- if (![attribute isEqualToString:NSAccessibilityTitleAttribute])
- return [super accessibilityAttributeValue:attribute];
-
- id viewsValue =
- [[self rootAccessibilityObject] accessibilityAttributeValue:attribute];
- return viewsValue ? viewsValue
- : [super accessibilityAttributeValue:attribute];
-}
-
-@end
diff --git a/chromium/ui/views/cocoa/tooltip_manager_mac.h b/chromium/ui/views/cocoa/tooltip_manager_mac.h
index 208fb4e948a..7fa612ca843 100644
--- a/chromium/ui/views/cocoa/tooltip_manager_mac.h
+++ b/chromium/ui/views/cocoa/tooltip_manager_mac.h
@@ -8,13 +8,19 @@
#include "base/macros.h"
#include "ui/views/widget/tooltip_manager.h"
-namespace views {
+namespace views_bridge_mac {
+namespace mojom {
class BridgedNativeWidget;
+} // namespace mojom
+} // namespace views_bridge_mac
+
+namespace views {
-// Manages native Cocoa tooltips for the given BridgedNativeWidget.
+// Manages native Cocoa tooltips for the given BridgedNativeWidgetHostImpl.
class TooltipManagerMac : public TooltipManager {
public:
- explicit TooltipManagerMac(BridgedNativeWidget* widget);
+ explicit TooltipManagerMac(
+ views_bridge_mac::mojom::BridgedNativeWidget* bridge);
~TooltipManagerMac() override;
// TooltipManager:
@@ -24,7 +30,8 @@ class TooltipManagerMac : public TooltipManager {
void TooltipTextChanged(View* view) override;
private:
- BridgedNativeWidget* widget_; // Weak. Owns this.
+ views_bridge_mac::mojom::BridgedNativeWidget*
+ bridge_; // Weak. Owned by the owner of this.
DISALLOW_COPY_AND_ASSIGN(TooltipManagerMac);
};
diff --git a/chromium/ui/views/cocoa/tooltip_manager_mac.mm b/chromium/ui/views/cocoa/tooltip_manager_mac.mm
index 99a1fb5d906..cbf12b14fda 100644
--- a/chromium/ui/views/cocoa/tooltip_manager_mac.mm
+++ b/chromium/ui/views/cocoa/tooltip_manager_mac.mm
@@ -4,11 +4,12 @@
#include "ui/views/cocoa/tooltip_manager_mac.h"
+#include "base/no_destructor.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/gfx/font_list.h"
#import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_content_view.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
namespace {
@@ -19,9 +20,9 @@ const int kTooltipMaxWidthPixels = 250;
namespace views {
-TooltipManagerMac::TooltipManagerMac(BridgedNativeWidget* widget)
- : widget_(widget) {
-}
+TooltipManagerMac::TooltipManagerMac(
+ views_bridge_mac::mojom::BridgedNativeWidget* bridge)
+ : bridge_(bridge) {}
TooltipManagerMac::~TooltipManagerMac() {
}
@@ -31,20 +32,13 @@ int TooltipManagerMac::GetMaxWidth(const gfx::Point& location) const {
}
const gfx::FontList& TooltipManagerMac::GetFontList() const {
- CR_DEFINE_STATIC_LOCAL(gfx::FontList, font_list,
- (gfx::Font([NSFont toolTipsFontOfSize:0])));
- return font_list;
+ static base::NoDestructor<gfx::FontList> font_list(
+ []() { return gfx::Font([NSFont toolTipsFontOfSize:0]); }());
+ return *font_list;
}
void TooltipManagerMac::UpdateTooltip() {
- NSWindow* window = widget_->ns_window();
- BridgedContentView* view = widget_->ns_view();
-
- NSPoint nspoint =
- ui::ConvertPointFromScreenToWindow(window, [NSEvent mouseLocation]);
- // Note: flip in the view's frame, which matches the window's contentRect.
- gfx::Point point(nspoint.x, NSHeight([view frame]) - nspoint.y);
- [view updateTooltipIfRequiredAt:point];
+ bridge_->UpdateTooltip();
}
void TooltipManagerMac::TooltipTextChanged(View* view) {
diff --git a/chromium/ui/views/cocoa/views_nswindow_delegate.h b/chromium/ui/views/cocoa/views_nswindow_delegate.h
deleted file mode 100644
index 00c2e13bbab..00000000000
--- a/chromium/ui/views/cocoa/views_nswindow_delegate.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
-#define UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-class NativeWidgetMac;
-class BridgedNativeWidget;
-}
-
-// The delegate set on the NSWindow when a views::BridgedNativeWidget is
-// initialized.
-VIEWS_EXPORT
-@interface ViewsNSWindowDelegate : NSObject<NSWindowDelegate> {
- @private
- views::BridgedNativeWidget* parent_; // Weak. Owns this.
- base::scoped_nsobject<NSCursor> cursor_;
-}
-
-// The NativeWidgetMac that created the window this is attached to. Returns
-// NULL if not created by NativeWidgetMac.
-@property(nonatomic, readonly) views::NativeWidgetMac* nativeWidgetMac;
-
-// If set, the cursor set in -[NSResponder updateCursor:] when the window is
-// reached along the responder chain.
-@property(retain, nonatomic) NSCursor* cursor;
-
-// Initialize with the given |parent|.
-- (id)initWithBridgedNativeWidget:(views::BridgedNativeWidget*)parent;
-
-// Notify that the window has been reordered in (or removed from) the window
-// server's screen list. This is a substitute for -[NSWindowDelegate
-// windowDidExpose:], which is only sent for nonretained windows (those without
-// a backing store). |notification| is optional and can be set when redirecting
-// a notification such as NSApplicationDidHideNotification.
-- (void)onWindowOrderChanged:(NSNotification*)notification;
-
-// Notify that the system control tint changed.
-- (void)onSystemControlTintChanged:(NSNotification*)notification;
-
-// Called on the delegate of a modal sheet when its modal session ends.
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)contextInfo;
-
-@end
-
-#endif // UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
diff --git a/chromium/ui/views/cocoa/views_nswindow_delegate.mm b/chromium/ui/views/cocoa/views_nswindow_delegate.mm
deleted file mode 100644
index bce74956126..00000000000
--- a/chromium/ui/views/cocoa/views_nswindow_delegate.mm
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/views_nswindow_delegate.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#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
-
-- (id)initWithBridgedNativeWidget:(views::BridgedNativeWidget*)parent {
- DCHECK(parent);
- if ((self = [super init])) {
- parent_ = parent;
- }
- return self;
-}
-
-- (views::NativeWidgetMac*)nativeWidgetMac {
- return parent_->native_widget_mac();
-}
-
-- (NSCursor*)cursor {
- return cursor_.get();
-}
-
-- (void)setCursor:(NSCursor*)newCursor {
- if (cursor_.get() == newCursor)
- return;
-
- cursor_.reset([newCursor retain]);
-
- // The window has a tracking rect that was installed in -[BridgedContentView
- // initWithView:] that uses the NSTrackingCursorUpdate option. In the case
- // where the window is the key window, that tracking rect will cause
- // -cursorUpdate: to be sent up the responder chain, which will cause the
- // cursor to be set when the message gets to the NativeWidgetMacNSWindow.
- NSWindow* window = parent_->ns_window();
- [window resetCursorRects];
-
- // However, if this window isn't the key window, that tracking area will have
- // no effect. This is good if this window is just some top-level window that
- // isn't key, but isn't so good if this window isn't key but is a child window
- // of a window that is key. To handle that case, the case where the
- // -cursorUpdate: message will never be sent, just set the cursor here.
- //
- // Only do this for non-key windows so that there will be no flickering
- // between cursors set here and set elsewhere.
- //
- // (This is a known issue; see https://stackoverflow.com/questions/45712066/.)
- if (![window isKeyWindow]) {
- NSWindow* currentWindow = window;
- // Walk up the window chain. If there is a key window in the window parent
- // chain, then work around the issue and set the cursor.
- while (true) {
- NSWindow* parentWindow = [currentWindow parentWindow];
- if (!parentWindow)
- break;
- currentWindow = parentWindow;
- if ([currentWindow isKeyWindow]) {
- [(newCursor ? newCursor : [NSCursor arrowCursor]) set];
- break;
- }
- }
- }
-}
-
-- (void)onWindowOrderChanged:(NSNotification*)notification {
- parent_->OnVisibilityChanged();
-}
-
-- (void)onSystemControlTintChanged:(NSNotification*)notification {
- parent_->OnSystemControlTintChanged();
-}
-
-- (void)sheetDidEnd:(NSWindow*)sheet
- returnCode:(NSInteger)returnCode
- contextInfo:(void*)contextInfo {
- [sheet orderOut:nil];
- parent_->OnWindowWillClose();
-}
-
-// NSWindowDelegate implementation.
-
-- (void)windowDidFailToEnterFullScreen:(NSWindow*)window {
- // Cocoa should already have sent an (unexpected) windowDidExitFullScreen:
- // notification, and the attempt to get back into fullscreen should fail.
- // Nothing to do except verify |parent_| is no longer trying to fullscreen.
- DCHECK(!parent_->target_fullscreen_state());
-}
-
-- (void)windowDidFailToExitFullScreen:(NSWindow*)window {
- // Unlike entering fullscreen, windowDidFailToExitFullScreen: is sent *before*
- // windowDidExitFullScreen:. Also, failing to exit fullscreen just dumps the
- // window out of fullscreen without an animation; still sending the expected,
- // windowDidExitFullScreen: notification. So, again, nothing to do here.
- DCHECK(!parent_->target_fullscreen_state());
-}
-
-- (void)windowDidResize:(NSNotification*)notification {
- parent_->OnSizeChanged();
-}
-
-- (void)windowDidMove:(NSNotification*)notification {
- // Note: windowDidMove: is sent only once at the end of a window drag. There
- // is also windowWillMove: sent at the start, also once. When the window is
- // being moved by the WindowServer live updates are not provided.
- parent_->OnPositionChanged();
-}
-
-- (void)windowDidBecomeKey:(NSNotification*)notification {
- parent_->OnWindowKeyStatusChangedTo(true);
-}
-
-- (void)windowDidResignKey:(NSNotification*)notification {
- parent_->OnWindowKeyStatusChangedTo(false);
-}
-
-- (BOOL)windowShouldClose:(id)sender {
- views::NonClientView* nonClientView =
- [self nativeWidgetMac]->GetWidget()->non_client_view();
- return !nonClientView || nonClientView->CanClose();
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- NSWindow* window = parent_->ns_window();
- if (NSWindow* sheetParent = [window sheetParent]) {
- // On no! Something called -[NSWindow close] on a sheet rather than calling
- // -[NSWindow endSheet:] on its parent. If the modal session is not ended
- // then the parent will never be able to show another sheet. But calling
- // -endSheet: here will block the thread with an animation, so post a task.
- // Use a block: The argument to -endSheet: must be retained, since it's the
- // window that is closing and -performSelector: won't retain the argument
- // (putting |window| on the stack above causes this block to retain it).
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(base::RetainBlock(^{
- [sheetParent endSheet:window];
- })));
- }
- DCHECK([window isEqual:[notification object]]);
- parent_->OnWindowWillClose();
- // |self| may be deleted here (it's NSObject, so who really knows).
- // |parent_| _will_ be deleted for sure.
-
- // Note OnWindowWillClose() will clear the NSWindow delegate. That is, |self|.
- // That guarantees that the task possibly-posted above will never call into
- // our -sheetDidEnd:. (The task's purpose is just to unblock the modal session
- // on the parent window.)
- DCHECK(![window delegate]);
-}
-
-- (void)windowDidMiniaturize:(NSNotification*)notification {
- parent_->host()->OnWindowMiniaturizedChanged(true);
- parent_->OnVisibilityChanged();
-}
-
-- (void)windowDidDeminiaturize:(NSNotification*)notification {
- parent_->host()->OnWindowMiniaturizedChanged(false);
- parent_->OnVisibilityChanged();
-}
-
-- (void)windowDidChangeBackingProperties:(NSNotification*)notification {
- parent_->OnBackingPropertiesChanged();
-}
-
-- (void)windowWillEnterFullScreen:(NSNotification*)notification {
- parent_->OnFullscreenTransitionStart(true);
-}
-
-- (void)windowDidEnterFullScreen:(NSNotification*)notification {
- parent_->OnFullscreenTransitionComplete(true);
-}
-
-- (void)windowWillExitFullScreen:(NSNotification*)notification {
- parent_->OnFullscreenTransitionStart(false);
-}
-
-- (void)windowDidExitFullScreen:(NSNotification*)notification {
- parent_->OnFullscreenTransitionComplete(false);
-}
-
-// Allow non-resizable windows (without NSResizableWindowMask) to fill the
-// screen in fullscreen mode. This only happens when
-// -[NSWindow toggleFullscreen:] is called since non-resizable windows have no
-// fullscreen button. Without this they would only enter fullscreen at their
-// current size.
-- (NSSize)window:(NSWindow*)window
- willUseFullScreenContentSize:(NSSize)proposedSize {
- return proposedSize;
-}
-
-// Override to correctly position modal dialogs.
-- (NSRect)window:(NSWindow*)window
- willPositionSheet:(NSWindow*)sheet
- usingRect:(NSRect)defaultSheetLocation {
- // As per NSWindowDelegate documentation, the origin indicates the top left
- // point of the host frame in window coordinates. The width changes the
- // animation from vertical to trapezoid if it is smaller than the width of the
- // dialog. The height is ignored but should be set to zero.
- return NSMakeRect(0, [self nativeWidgetMac]->SheetPositionY(),
- NSWidth(defaultSheetLocation), 0);
-}
-
-@end
diff --git a/chromium/ui/views/cocoa/views_scrollbar_bridge.h b/chromium/ui/views/cocoa/views_scrollbar_bridge.h
deleted file mode 100644
index eb070a161c5..00000000000
--- a/chromium/ui/views/cocoa/views_scrollbar_bridge.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_VIEWS_SCROLLBAR_BRIDGE_DELEGATE_H_
-#define UI_VIEWS_COCOA_VIEWS_SCROLLBAR_BRIDGE_DELEGATE_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#include "ui/views/views_export.h"
-
-// The delegate set to ViewsScrollbarBridge.
-class ViewsScrollbarBridgeDelegate {
- public:
- // Invoked by ViewsScrollbarBridge when the system informs the process that
- // the preferred scroller style has changed
- virtual void OnScrollerStyleChanged() = 0;
-};
-
-// A bridge to NSScroller managed by NativeCocoaScrollbar. Serves as a helper
-// class to bridge NSScroller notifications and functions to CocoaScrollbar.
-@interface ViewsScrollbarBridge : NSObject {
- @private
- ViewsScrollbarBridgeDelegate* delegate_; // Weak. Owns this.
-}
-
-// Initializes with the given delegate and registers for notifications on
-// scroller style changes.
-- (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate;
-
-// Sets |delegate_| to nullptr.
--(void)clearDelegate;
-
-// Returns the style of scrollers that OSX is using.
-+ (NSScrollerStyle)getPreferredScrollerStyle;
-
-@end
-
-#endif \ No newline at end of file
diff --git a/chromium/ui/views/cocoa/views_scrollbar_bridge.mm b/chromium/ui/views/cocoa/views_scrollbar_bridge.mm
deleted file mode 100644
index d80dece0e7b..00000000000
--- a/chromium/ui/views/cocoa/views_scrollbar_bridge.mm
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/views_scrollbar_bridge.h"
-
-#import "base/mac/sdk_forward_declarations.h"
-
-@interface ViewsScrollbarBridge ()
-
-// Called when we receive a NSPreferredScrollerStyleDidChangeNotification.
-- (void)onScrollerStyleChanged:(NSNotification*)notification;
-
-@end
-
-@implementation ViewsScrollbarBridge
-
-- (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate {
- if ((self = [super init])) {
- delegate_ = delegate;
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(onScrollerStyleChanged:)
- name:NSPreferredScrollerStyleDidChangeNotification
- object:nil];
- }
- return self;
-}
-
-- (void)dealloc {
- DCHECK(!delegate_);
- [super dealloc];
-}
-
-- (void)clearDelegate {
- delegate_ = nullptr;
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
-- (void)onScrollerStyleChanged:(NSNotification*)notification {
- if (delegate_)
- delegate_->OnScrollerStyleChanged();
-}
-
-+ (NSScrollerStyle)getPreferredScrollerStyle {
- return [NSScroller preferredScrollerStyle];
-}
-
-@end
diff --git a/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.h b/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.h
deleted file mode 100644
index 8240bead793..00000000000
--- a/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_COCOA_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
-#define UI_VIEWS_COCOA_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
-
-#import "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#import "ui/views/cocoa/bridged_native_widget_owner.h"
-
-@class NSView;
-@class NSWindow;
-@class WidgetOwnerNSWindowAdapterBridge;
-
-namespace views {
-
-// An adapter that allows a views::Widget to be owned by an NSWindow that is not
-// backed by another BridgedNativeWidget.
-class WidgetOwnerNSWindowAdapter : public BridgedNativeWidgetOwner {
- public:
- // Create an adapter that will own |child|, tying its lifetime with the
- // NSWindow containing |anchor_view|. The object is self-deleting, via a call
- // to RemoveChildWindow() made in child->OnWindowWillClose().
- WidgetOwnerNSWindowAdapter(BridgedNativeWidget* child, NSView* anchor_view);
-
- // Called when the owning window is closing.
- void OnWindowWillClose();
-
- // Called when the owning window is hidden or shown.
- void OnWindowDidChangeOcclusionState();
-
- // Overridden from BridgedNativeWidgetOwner:
- NSWindow* GetNSWindow() override;
- gfx::Vector2d GetChildWindowOffset() const override;
- bool IsVisibleParent() const override;
- void RemoveChildWindow(BridgedNativeWidget* child) override;
-
- private:
- // Self-deleting.
- ~WidgetOwnerNSWindowAdapter() override;
-
- BridgedNativeWidget* child_; // Weak. Owned by its NativeWidgetMac.
- base::scoped_nsobject<NSView> anchor_view_;
- base::scoped_nsobject<NSWindow> anchor_window_;
- base::scoped_nsobject<WidgetOwnerNSWindowAdapterBridge> observer_bridge_;
-
- DISALLOW_COPY_AND_ASSIGN(WidgetOwnerNSWindowAdapter);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_COCOA_WIDGET_OWNER_NSWINDOW_ADAPTER_H_
diff --git a/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm b/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm
deleted file mode 100644
index 3585b78344e..00000000000
--- a/chromium/ui/views/cocoa/widget_owner_nswindow_adapter.mm
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/logging.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/vector2d.h"
-#import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
-
-// Bridges an AppKit observer to observe when the (non-views) NSWindow owning a
-// views::Widget will close or change occlusion state.
-@interface WidgetOwnerNSWindowAdapterBridge : NSObject {
- @private
- views::WidgetOwnerNSWindowAdapter* adapter_; // Weak. Owns us.
-}
-- (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter;
-- (void)windowWillClose:(NSNotification*)notification;
-- (void)windowDidChangeOcclusionState:(NSNotification*)notification;
-@end
-
-@implementation WidgetOwnerNSWindowAdapterBridge
-
-- (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter {
- if ((self = [super init]))
- adapter_ = adapter;
- return self;
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
- adapter_->OnWindowWillClose();
-}
-
-- (void)windowDidChangeOcclusionState:(NSNotification*)notification {
- adapter_->OnWindowDidChangeOcclusionState();
-}
-
-@end
-
-namespace views {
-
-WidgetOwnerNSWindowAdapter::WidgetOwnerNSWindowAdapter(
- BridgedNativeWidget* child,
- NSView* anchor_view)
- : child_(child),
- anchor_view_([anchor_view retain]),
- observer_bridge_(
- [[WidgetOwnerNSWindowAdapterBridge alloc] initWithAdapter:this]) {
-
- // Although the |anchor_view| must be in an NSWindow when the child dialog is
- // created, it's permitted for the |anchor_view| to be removed from its view
- // hierarchy before the child dialog window is fully removed from screen. When
- // this happens, [anchor_view_ window] will become nil, so retain both.
- anchor_window_.reset([[anchor_view_ window] retain]);
- DCHECK(anchor_window_);
-
- [[NSNotificationCenter defaultCenter]
- addObserver:observer_bridge_
- selector:@selector(windowWillClose:)
- name:NSWindowWillCloseNotification
- object:anchor_window_];
-
- // BridgedNativeWidget removes NSWindow parent/child relationships for hidden
- // windows. Observe when the parent's visibility changes so they can be
- // reconnected.
- [[NSNotificationCenter defaultCenter]
- addObserver:observer_bridge_
- selector:@selector(windowDidChangeOcclusionState:)
- name:NSWindowDidChangeOcclusionStateNotification
- object:anchor_window_];
-
- // On a deminiaturize, the occlusion state change may occur before -[NSWindow
- // isVisible] returns YES. So observe NSWindowDidDeminiaturizeNotification.
- // This allows the adapter to check again at the end of the deminiaturize.
- [[NSNotificationCenter defaultCenter]
- addObserver:observer_bridge_
- selector:@selector(windowDidChangeOcclusionState:)
- name:NSWindowDidDeminiaturizeNotification
- object:anchor_window_];
-}
-
-void WidgetOwnerNSWindowAdapter::OnWindowWillClose() {
- // Retain the child window before closing it. If the last reference to the
- // NSWindow goes away inside -[NSWindow close], then bad stuff can happen.
- // See e.g. http://crbug.com/616701.
- base::scoped_nsobject<NSWindow> child_window(child_->ns_window(),
- base::scoped_policy::RETAIN);
-
- // AppKit child window relationships break when the windows are not visible,
- // so if the child is not visible, it won't currently be a child.
- if (![child_window isVisible])
- DCHECK(![child_window parentWindow] && ![child_window sheetParent]);
- DCHECK([child_window delegate]);
-
- [child_window close];
- // Note: |this| will be deleted here.
-
- DCHECK(![child_window parentWindow]);
- DCHECK(![child_window delegate]);
-}
-
-void WidgetOwnerNSWindowAdapter::OnWindowDidChangeOcclusionState() {
- // The adapter only needs to handle a parent "show", since the only way it
- // should be hidden is via -[NSApp hide], and all BridgedNativeWidgets
- // subscribe to NSApplicationDidHideNotification already.
- if (![anchor_window_ isVisible])
- return;
-
- if (child_->window_visible()) {
- // A sheet should never have a parentWindow, otherwise dismissing the sheet
- // causes graphical glitches (http://crbug.com/605098). Non-sheets should
- // always have a parentWindow.
- DCHECK([child_->ns_window() isSheet] !=
- !![child_->ns_window() parentWindow]);
- DCHECK(child_->wants_to_be_visible());
- return;
- }
-
- // The parent relationship should have been removed when the child was hidden.
- DCHECK(![child_->ns_window() parentWindow]);
- if (!child_->wants_to_be_visible())
- return;
-
- [child_->ns_window() orderWindow:NSWindowAbove
- relativeTo:[anchor_window_ windowNumber]];
-
- // Ordering the window should add back the relationship (unless it's a sheet).
- DCHECK([child_->ns_window() isSheet] != !![child_->ns_window() parentWindow]);
- DCHECK(child_->window_visible());
-}
-
-NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() {
- return anchor_window_;
-}
-
-gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const {
- NSRect rect_in_window =
- [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil];
- NSRect rect_in_screen = [anchor_window_ convertRectToScreen:rect_in_window];
- // Ensure we anchor off the top-left of |anchor_view_| (rect_in_screen.origin
- // is the bottom-left of the view).
- NSPoint anchor_in_screen =
- NSMakePoint(NSMinX(rect_in_screen), NSMaxY(rect_in_screen));
- return gfx::ScreenPointFromNSPoint(anchor_in_screen).OffsetFromOrigin();
-}
-
-bool WidgetOwnerNSWindowAdapter::IsVisibleParent() const {
- return [anchor_window_ isVisible];
-}
-
-void WidgetOwnerNSWindowAdapter::RemoveChildWindow(BridgedNativeWidget* child) {
- DCHECK_EQ(child, child_);
- [GetNSWindow() removeChildWindow:child->ns_window()];
- delete this;
-}
-
-WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() {
- [[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_];
-}
-
-} // namespace views
diff --git a/chromium/ui/views/cocoa/window_touch_bar_delegate.h b/chromium/ui/views/cocoa/window_touch_bar_delegate.h
deleted file mode 100644
index daef5466ed6..00000000000
--- a/chromium/ui/views/cocoa/window_touch_bar_delegate.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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_WINDOW_TOUCH_BAR_DELEGATE_H_
-#define UI_VIEWS_COCOA_WINDOW_TOUCH_BAR_DELEGATE_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/availability.h"
-
-// Bridge delegate class for NativeWidgetMacNSWindow and
-// BrowserWindowTouchBarMac.
-@protocol WindowTouchBarDelegate<NSObject>
-
-// Creates and returns a touch bar for the browser window.
-- (NSTouchBar*)makeTouchBar API_AVAILABLE(macos(10.12.2));
-
-@end
-
-#endif // UI_VIEWS_COCOA_WINDOW_TOUCH_BAR_DELEGATE_H_ \ No newline at end of file
diff --git a/chromium/ui/views/color_chooser/color_chooser_view.cc b/chromium/ui/views/color_chooser/color_chooser_view.cc
index d844b6a58f2..19eab2ec3d5 100644
--- a/chromium/ui/views/color_chooser/color_chooser_view.cc
+++ b/chromium/ui/views/color_chooser/color_chooser_view.cc
@@ -15,10 +15,12 @@
#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/strings/grit/ui_strings.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/color_chooser/color_chooser_listener.h"
@@ -389,6 +391,8 @@ ColorChooserView::ColorChooserView(ColorChooserListener* listener,
textfield_ = new Textfield();
textfield_->set_controller(this);
textfield_->SetDefaultWidthInChars(kTextfieldLengthInChars);
+ textfield_->SetAccessibleName(
+ l10n_util::GetStringUTF16(IDS_APP_ACCNAME_COLOR_CHOOSER_HEX_INPUT));
layout->AddView(textfield_);
selected_color_patch_ = new SelectedColorPatchView();
layout->AddView(selected_color_patch_);
diff --git a/chromium/ui/views/controls/animated_image_view.cc b/chromium/ui/views/controls/animated_image_view.cc
new file mode 100644
index 00000000000..2d56a88b440
--- /dev/null
+++ b/chromium/ui/views/controls/animated_image_view.cc
@@ -0,0 +1,139 @@
+// 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/animated_image_view.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/skottie_wrapper.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace {
+
+bool AreAnimatedImagesEqual(const gfx::SkiaVectorAnimation& animation_1,
+ const gfx::SkiaVectorAnimation& animation_2) {
+ // In rare cases this may return false, even if the animated images are backed
+ // by the same resource file.
+ return animation_1.skottie() == animation_2.skottie();
+}
+
+} // namespace
+
+AnimatedImageView::AnimatedImageView() = default;
+
+AnimatedImageView::~AnimatedImageView() = default;
+
+void AnimatedImageView::SetAnimatedImage(
+ std::unique_ptr<gfx::SkiaVectorAnimation> animated_image) {
+ if (animated_image_ &&
+ AreAnimatedImagesEqual(*animated_image, *animated_image_)) {
+ Stop();
+ return;
+ }
+
+ gfx::Size preferred_size(GetPreferredSize());
+ animated_image_ = std::move(animated_image);
+
+ // Stop the animation to reset it.
+ Stop();
+
+ if (preferred_size != GetPreferredSize())
+ PreferredSizeChanged();
+ SchedulePaint();
+}
+
+void AnimatedImageView::Play() {
+ DCHECK(animated_image_);
+ DCHECK_EQ(state_, State::kStopped);
+
+ state_ = State::kPlaying;
+
+ // We cannot play the animation unless we have a valid compositor.
+ if (!compositor_)
+ return;
+
+ // Ensure the class is added as an observer to receive clock ticks.
+ if (!compositor_->HasAnimationObserver(this))
+ compositor_->AddAnimationObserver(this);
+
+ animated_image_->Start();
+}
+
+void AnimatedImageView::Stop() {
+ DCHECK(animated_image_);
+ if (compositor_)
+ compositor_->RemoveAnimationObserver(this);
+
+ animated_image_->Stop();
+ state_ = State::kStopped;
+}
+
+gfx::Size AnimatedImageView::GetImageSize() const {
+ return image_size_.value_or(
+ animated_image_ ? animated_image_->GetOriginalSize() : gfx::Size());
+}
+
+void AnimatedImageView::OnPaint(gfx::Canvas* canvas) {
+ View::OnPaint(canvas);
+ if (!animated_image_)
+ return;
+ canvas->Save();
+ canvas->Translate(GetImageBounds().origin().OffsetFromOrigin());
+
+ // OnPaint may be called before clock tick was received; in that case just
+ // paint the first frame.
+ if (!previous_timestamp_.is_null() && state_ != State::kStopped)
+ animated_image_->Paint(canvas, previous_timestamp_, GetImageSize());
+ else
+ animated_image_->PaintFrame(canvas, 0, GetImageSize());
+
+ canvas->Restore();
+}
+
+const char* AnimatedImageView::GetClassName() const {
+ return "AnimatedImageView";
+}
+
+void AnimatedImageView::NativeViewHierarchyChanged() {
+ // When switching a window from one display to another, the compositor
+ // associated with the widget changes.
+ AddedToWidget();
+}
+
+void AnimatedImageView::AddedToWidget() {
+ ui::Compositor* compositor = GetWidget()->GetCompositor();
+ DCHECK(compositor);
+ if (compositor_ != compositor) {
+ if (compositor_ && compositor_->HasAnimationObserver(this))
+ compositor_->RemoveAnimationObserver(this);
+ compositor_ = compositor;
+ }
+}
+
+void AnimatedImageView::RemovedFromWidget() {
+ if (compositor_) {
+ Stop();
+ if (compositor_->HasAnimationObserver(this))
+ compositor_->RemoveAnimationObserver(this);
+ compositor_ = nullptr;
+ }
+}
+
+void AnimatedImageView::OnAnimationStep(base::TimeTicks timestamp) {
+ previous_timestamp_ = timestamp;
+ SchedulePaint();
+}
+
+void AnimatedImageView::OnCompositingShuttingDown(ui::Compositor* compositor) {
+ if (compositor_ == compositor) {
+ Stop();
+ compositor_->RemoveAnimationObserver(this);
+ compositor_ = nullptr;
+ }
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/animated_image_view.h b/chromium/ui/views/controls/animated_image_view.h
new file mode 100644
index 00000000000..c62fe5c3723
--- /dev/null
+++ b/chromium/ui/views/controls/animated_image_view.h
@@ -0,0 +1,91 @@
+// 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_ANIMATED_IMAGE_VIEW_H_
+#define UI_VIEWS_CONTROLS_ANIMATED_IMAGE_VIEW_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "ui/gfx/skia_vector_animation.h"
+#include "ui/views/controls/image_view_base.h"
+
+namespace gfx {
+class SkiaVectorAnimation;
+class Canvas;
+} // namespace gfx
+
+namespace ui {
+class Compositor;
+}
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AnimatedImageView class.
+//
+// An AnimatedImageView can display a skia vector animation. The animation paint
+// size can be set via SetImageSize. The animation is stopped by default.
+// Use this over AnimatedIconView if you want to play a skottie animation file.
+//
+/////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT AnimatedImageView : public ImageViewBase,
+ public ui::CompositorAnimationObserver {
+ public:
+ enum class State {
+ kPlaying, // The animation is currently playing.
+ kStopped // The animation is stopped and paint will raster the first
+ // frame.
+ };
+
+ AnimatedImageView();
+ ~AnimatedImageView() override;
+
+ // Set the animated image that should be displayed. Setting an animated image
+ // will result in stopping the current animation.
+ void SetAnimatedImage(
+ std::unique_ptr<gfx::SkiaVectorAnimation> animated_image);
+
+ // Plays the animation in loop.
+ void Play();
+
+ // Stops any animation and resets it to the start frame.
+ void Stop();
+
+ private:
+ friend class AnimatedImageViewTest;
+
+ // Overridden from View:
+ void OnPaint(gfx::Canvas* canvas) override;
+ const char* GetClassName() const override;
+ void NativeViewHierarchyChanged() override;
+ void AddedToWidget() override;
+ void RemovedFromWidget() override;
+
+ // Overridden from ui::CompositorAnimationObserver:
+ void OnAnimationStep(base::TimeTicks timestamp) override;
+ void OnCompositingShuttingDown(ui::Compositor* compositor) override;
+
+ // Overridden from ImageViewBase:
+ gfx::Size GetImageSize() const override;
+
+ // The current state of the animation.
+ State state_ = State::kStopped;
+
+ // The compositor associated with the widget of this view.
+ ui::Compositor* compositor_ = nullptr;
+
+ // The most recent timestamp at which a paint was scheduled for this view.
+ base::TimeTicks previous_timestamp_;
+
+ // The underlying skia vector animation.
+ std::unique_ptr<gfx::SkiaVectorAnimation> animated_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(AnimatedImageView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_ANIMATED_IMAGE_VIEW_H_
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index 9656e5dc4a3..ebf086404e3 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -170,6 +170,12 @@ void Button::SetFocusPainter(std::unique_ptr<Painter> focus_painter) {
focus_painter_ = std::move(focus_painter);
}
+void Button::SetHighlighted(bool bubble_visible) {
+ AnimateInkDrop(bubble_visible ? views::InkDropState::ACTIVATED
+ : views::InkDropState::DEACTIVATED,
+ nullptr);
+}
+
////////////////////////////////////////////////////////////////////////////////
// Button, View overrides:
diff --git a/chromium/ui/views/controls/button/button.h b/chromium/ui/views/controls/button/button.h
index b5347ff0e00..050512ffa34 100644
--- a/chromium/ui/views/controls/button/button.h
+++ b/chromium/ui/views/controls/button/button.h
@@ -151,6 +151,9 @@ class VIEWS_EXPORT Button : public InkDropHostView,
void SetFocusPainter(std::unique_ptr<Painter> focus_painter);
+ // Highlights the ink drop for the button.
+ void SetHighlighted(bool bubble_visible);
+
// Overridden from View:
void OnEnabledChanged() override;
const char* GetClassName() const override;
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index 91e398ebfe3..1a84d97ab26 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -55,7 +55,10 @@ Checkbox::~Checkbox() {
}
void Checkbox::SetChecked(bool checked) {
- checked_ = checked;
+ if (checked_ != checked) {
+ checked_ = checked;
+ NotifyAccessibilityEvent(ax::mojom::Event::kCheckedStateChanged, true);
+ }
UpdateImage();
}
diff --git a/chromium/ui/views/controls/button/image_button_factory.cc b/chromium/ui/views/controls/button/image_button_factory.cc
index 649002d85ad..baf33d4ef8d 100644
--- a/chromium/ui/views/controls/button/image_button_factory.cc
+++ b/chromium/ui/views/controls/button/image_button_factory.cc
@@ -31,7 +31,8 @@ void SetImageFromVectorIcon(ImageButton* button,
SkColor related_text_color) {
const SkColor icon_color =
color_utils::DeriveDefaultIconColor(related_text_color);
- const SkColor disabled_color = SkColorSetA(icon_color, 0xff / 2);
+ const SkColor disabled_color =
+ SkColorSetA(icon_color, gfx::kDisabledControlAlpha);
button->SetImage(Button::STATE_NORMAL,
gfx::CreateVectorIcon(icon, icon_color));
button->SetImage(Button::STATE_DISABLED,
diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc
index 4a1ac7683d6..966ab6fec75 100644
--- a/chromium/ui/views/controls/button/label_button_unittest.cc
+++ b/chromium/ui/views/controls/button/label_button_unittest.cc
@@ -543,8 +543,6 @@ class InkDropLabelButtonTest : public ViewsTestBase {
// ViewsTestBase:
void SetUp() override {
- base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kTopChromeMD, switches::kTopChromeMDMaterial);
ViewsTestBase::SetUp();
// Create a widget so that the Button can query the hover state
@@ -568,7 +566,6 @@ class InkDropLabelButtonTest : public ViewsTestBase {
void TearDown() override {
widget_.reset();
ViewsTestBase::TearDown();
- ui::test::MaterialDesignControllerTestAPI::Uninitialize();
}
protected:
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index 4e6011dc24e..0d9f69cab39 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -7,7 +7,6 @@
#include "base/i18n/case_conversion.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.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"
@@ -197,12 +196,9 @@ void MdTextButton::UpdatePadding() {
style::GetFont(style::CONTEXT_BUTTON_MD, style::STYLE_PRIMARY)
.GetFontSize();
// TODO(tapted): This should get |target_height| using LayoutProvider::
- // GetControlHeightForFont(). It can't because that only returns a correct
- // result with --secondary-ui-md, and MdTextButtons appear in top chrome
- // without that.
- const int base_height =
- ui::MaterialDesignController::IsNewerMaterialUi() ? 32 : 28;
- int target_height = std::max(base_height + size_delta * 2,
+ // GetControlHeightForFont().
+ constexpr int kBaseHeight = 32;
+ int target_height = std::max(kBaseHeight + size_delta * 2,
label()->font_list().GetFontSize() * 2);
int label_height = label()->GetPreferredSize().height();
diff --git a/chromium/ui/views/controls/button/radio_button.cc b/chromium/ui/views/controls/button/radio_button.cc
index 9adf4949221..6113742ab7f 100644
--- a/chromium/ui/views/controls/button/radio_button.cc
+++ b/chromium/ui/views/controls/button/radio_button.cc
@@ -99,7 +99,7 @@ void RadioButton::SetChecked(bool checked) {
if (container) {
Views other;
container->GetViewsInGroup(GetGroup(), &other);
- for (Views::iterator i(other.begin()); i != other.end(); ++i) {
+ for (auto i(other.begin()); i != other.end(); ++i) {
if (*i != this) {
if (strcmp((*i)->GetClassName(), kViewClassName)) {
NOTREACHED() << "radio-button-nt has same group as other non "
diff --git a/chromium/ui/views/controls/focus_ring.cc b/chromium/ui/views/controls/focus_ring.cc
index 148c22ae909..bc9597596ce 100644
--- a/chromium/ui/views/controls/focus_ring.cc
+++ b/chromium/ui/views/controls/focus_ring.cc
@@ -7,6 +7,7 @@
#include "ui/gfx/canvas.h"
#include "ui/views/controls/focusable_border.h"
#include "ui/views/style/platform_style.h"
+#include "ui/views/view_properties.h"
namespace {
@@ -79,6 +80,11 @@ void FocusRing::OnPaint(gfx::Canvas* canvas) {
paint.setStrokeWidth(PlatformStyle::kFocusHaloThickness);
SkPath path = path_;
+ if (path.isEmpty()) {
+ gfx::Path* highlight_path = parent()->GetProperty(kHighlightPathKey);
+ if (highlight_path)
+ path = *highlight_path;
+ }
if (path.isEmpty())
path.addRect(RectToSkRect(parent()->GetLocalBounds()));
diff --git a/chromium/ui/views/controls/focus_ring.h b/chromium/ui/views/controls/focus_ring.h
index a608042b24f..1627eda9347 100644
--- a/chromium/ui/views/controls/focus_ring.h
+++ b/chromium/ui/views/controls/focus_ring.h
@@ -58,6 +58,9 @@ class VIEWS_EXPORT FocusRing : public View, public ViewObserver {
// view's coordinate system, *not* in the FocusRing's coordinate system. Note
// that this path will not be mirrored in RTL, so your View's computation of
// it should take RTL into account.
+ // Note: This method should only be used if the focus ring needs to differ
+ // from the highlight shape used for inkdrops. Otherwise set kHighlightPathKey
+ // on the parent and FocusRing will use it as well.
void SetPath(const SkPath& path);
// Sets whether the FocusRing should show an invalid state for the View it
diff --git a/chromium/ui/views/controls/image_view.cc b/chromium/ui/views/controls/image_view.cc
index b1abacf1e0d..2e9c4062526 100644
--- a/chromium/ui/views/controls/image_view.cc
+++ b/chromium/ui/views/controls/image_view.cc
@@ -7,12 +7,9 @@
#include <utility>
#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
#include "cc/paint/paint_flags.h"
#include "skia/ext/image_operations.h"
-#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/insets.h"
namespace views {
@@ -21,7 +18,7 @@ namespace {
// Returns the pixels for the bitmap in |image| at scale |image_scale|.
void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) {
DCHECK_NE(0.0f, image_scale);
- return img.GetRepresentation(image_scale).sk_bitmap().getPixels();
+ return img.GetRepresentation(image_scale).GetBitmap().getPixels();
}
} // namespace
@@ -29,13 +26,9 @@ void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) {
// static
const char ImageView::kViewClassName[] = "ImageView";
-ImageView::ImageView()
- : horizontal_alignment_(CENTER),
- vertical_alignment_(CENTER),
- last_paint_scale_(0.f),
- last_painted_bitmap_pixels_(nullptr) {}
+ImageView::ImageView() = default;
-ImageView::~ImageView() {}
+ImageView::~ImageView() = default;
void ImageView::SetImage(const gfx::ImageSkia& img) {
if (IsImageEqual(img))
@@ -63,20 +56,6 @@ const gfx::ImageSkia& ImageView::GetImage() const {
return image_;
}
-void ImageView::SetImageSize(const gfx::Size& image_size) {
- image_size_ = image_size;
- PreferredSizeChanged();
-}
-
-gfx::Rect ImageView::GetImageBounds() const {
- gfx::Size image_size = GetImageSize();
- return gfx::Rect(ComputeImageOrigin(image_size), image_size);
-}
-
-void ImageView::ResetImageSize() {
- image_size_.reset();
-}
-
bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const {
// Even though we copy ImageSkia in SetImage() the backing store
// (ImageSkiaStorage) is not copied and may have changed since the last call
@@ -92,119 +71,15 @@ gfx::Size ImageView::GetImageSize() const {
return image_size_.value_or(image_.size());
}
-gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const {
- gfx::Insets insets = GetInsets();
-
- int x = 0;
- // In order to properly handle alignment of images in RTL locales, we need
- // to flip the meaning of trailing and leading. For example, if the
- // horizontal alignment is set to trailing, then we'll use left alignment for
- // the image instead of right alignment if the UI layout is RTL.
- Alignment actual_horizontal_alignment = horizontal_alignment_;
- if (base::i18n::IsRTL() && (horizontal_alignment_ != CENTER)) {
- actual_horizontal_alignment =
- (horizontal_alignment_ == LEADING) ? TRAILING : LEADING;
- }
- switch (actual_horizontal_alignment) {
- case LEADING:
- x = insets.left();
- break;
- case TRAILING:
- x = width() - insets.right() - image_size.width();
- break;
- case CENTER:
- x = (width() - insets.width() - image_size.width()) / 2 + insets.left();
- break;
- }
-
- int y = 0;
- switch (vertical_alignment_) {
- case LEADING:
- y = insets.top();
- break;
- case TRAILING:
- y = height() - insets.bottom() - image_size.height();
- break;
- case CENTER:
- y = (height() - insets.height() - image_size.height()) / 2 + insets.top();
- break;
- }
-
- return gfx::Point(x, y);
-}
-
void ImageView::OnPaint(gfx::Canvas* canvas) {
View::OnPaint(canvas);
OnPaintImage(canvas);
}
-void ImageView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- node_data->role = ax::mojom::Role::kImage;
- node_data->SetName(tooltip_text_);
-}
-
const char* ImageView::GetClassName() const {
return kViewClassName;
}
-void ImageView::SetHorizontalAlignment(Alignment alignment) {
- if (alignment != horizontal_alignment_) {
- horizontal_alignment_ = alignment;
- SchedulePaint();
- }
-}
-
-ImageView::Alignment ImageView::GetHorizontalAlignment() const {
- return horizontal_alignment_;
-}
-
-void ImageView::SetVerticalAlignment(Alignment alignment) {
- if (alignment != vertical_alignment_) {
- vertical_alignment_ = alignment;
- SchedulePaint();
- }
-}
-
-ImageView::Alignment ImageView::GetVerticalAlignment() const {
- return vertical_alignment_;
-}
-
-void ImageView::SetTooltipText(const base::string16& tooltip) {
- tooltip_text_ = tooltip;
-}
-
-base::string16 ImageView::GetTooltipText() const {
- return tooltip_text_;
-}
-
-bool ImageView::GetTooltipText(const gfx::Point& p,
- base::string16* tooltip) const {
- if (tooltip_text_.empty())
- return false;
-
- *tooltip = GetTooltipText();
- return true;
-}
-
-gfx::Size ImageView::CalculatePreferredSize() const {
- gfx::Size size = GetImageSize();
- size.Enlarge(GetInsets().width(), GetInsets().height());
- return size;
-}
-
-views::PaintInfo::ScaleType ImageView::GetPaintScaleType() const {
- // ImageView contains an image which is rastered at the device scale factor.
- // By default, the paint commands are recorded at a scale factor slightly
- // different from the device scale factor. Re-rastering the image at this
- // paint recording scale will result in a distorted image. Paint recording
- // scale might also not be uniform along the x & y axis, thus resulting in
- // further distortion in the aspect ratio of the final image.
- // |kUniformScaling| ensures that the paint recording scale is uniform along
- // the x & y axis and keeps the scale equal to the device scale factor.
- // See http://crbug.com/754010 for more details.
- return views::PaintInfo::ScaleType::kUniformScaling;
-}
-
void ImageView::OnPaintImage(gfx::Canvas* canvas) {
last_paint_scale_ = canvas->image_scale();
last_painted_bitmap_pixels_ = nullptr;
@@ -248,7 +123,7 @@ gfx::ImageSkia ImageView::GetPaintImage(float scale) {
gfx::Size scaled_size =
gfx::ScaleToCeiledSize(rep.pixel_size(), scale / rep.scale());
scaled_image_.AddRepresentation(gfx::ImageSkiaRep(
- skia::ImageOperations::Resize(rep.sk_bitmap(),
+ skia::ImageOperations::Resize(rep.GetBitmap(),
skia::ImageOperations::RESIZE_BEST,
scaled_size.width(), scaled_size.height()),
scale));
diff --git a/chromium/ui/views/controls/image_view.h b/chromium/ui/views/controls/image_view.h
index c3adf654e36..e80a97a34a1 100644
--- a/chromium/ui/views/controls/image_view.h
+++ b/chromium/ui/views/controls/image_view.h
@@ -6,9 +6,8 @@
#define UI_VIEWS_CONTROLS_IMAGE_VIEW_H_
#include "base/macros.h"
-#include "base/optional.h"
#include "ui/gfx/image/image_skia.h"
-#include "ui/views/view.h"
+#include "ui/views/controls/image_view_base.h"
namespace gfx {
class Canvas;
@@ -26,17 +25,11 @@ namespace views {
// provided image size.
//
/////////////////////////////////////////////////////////////////////////////
-class VIEWS_EXPORT ImageView : public View {
+class VIEWS_EXPORT ImageView : public ImageViewBase {
public:
// Internal class name.
static const char kViewClassName[];
- enum Alignment {
- LEADING = 0,
- CENTER,
- TRAILING
- };
-
ImageView();
~ImageView() override;
@@ -52,35 +45,13 @@ class VIEWS_EXPORT ImageView : public View {
// The returned image is still owned by the ImageView.
const gfx::ImageSkia& GetImage() const;
- // Set the desired image size for the receiving ImageView.
- void SetImageSize(const gfx::Size& image_size);
-
- // Returns the actual bounds of the visible image inside the view.
- gfx::Rect GetImageBounds() const;
-
- // Reset the image size to the current image dimensions.
- void ResetImageSize();
-
- // Set / Get the horizontal alignment.
- void SetHorizontalAlignment(Alignment ha);
- Alignment GetHorizontalAlignment() const;
-
- // Set / Get the vertical alignment.
- void SetVerticalAlignment(Alignment va);
- Alignment GetVerticalAlignment() const;
-
- // Set / Get the tooltip text.
- void SetTooltipText(const base::string16& tooltip);
- base::string16 GetTooltipText() const;
-
- // Overriden from View:
+ // Overridden from View:
void OnPaint(gfx::Canvas* canvas) override;
- void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
const char* GetClassName() const override;
- bool GetTooltipText(const gfx::Point& p,
- base::string16* tooltip) const override;
- gfx::Size CalculatePreferredSize() const override;
- views::PaintInfo::ScaleType GetPaintScaleType() const override;
+
+ protected:
+ // Overridden from ImageViewBase:
+ gfx::Size GetImageSize() const override;
private:
friend class ImageViewTest;
@@ -95,37 +66,18 @@ class VIEWS_EXPORT ImageView : public View {
// for this to return false even though the images are in fact equal.
bool IsImageEqual(const gfx::ImageSkia& img) const;
- // Returns the size the image will be painted.
- gfx::Size GetImageSize() const;
-
- // Compute the image origin given the desired size and the receiver alignment
- // properties.
- gfx::Point ComputeImageOrigin(const gfx::Size& image_size) const;
-
- // The actual image size.
- base::Optional<gfx::Size> image_size_;
-
// The underlying image.
gfx::ImageSkia image_;
// Caches the scaled image reps.
gfx::ImageSkia scaled_image_;
- // Horizontal alignment.
- Alignment horizontal_alignment_;
-
- // Vertical alignment.
- Alignment vertical_alignment_;
-
- // The current tooltip text.
- base::string16 tooltip_text_;
-
// Scale last painted at.
- float last_paint_scale_;
+ float last_paint_scale_ = 0.f;
// Address of bytes we last painted. This is used only for comparison, so its
// safe to cache.
- void* last_painted_bitmap_pixels_;
+ void* last_painted_bitmap_pixels_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ImageView);
};
diff --git a/chromium/ui/views/controls/image_view_base.cc b/chromium/ui/views/controls/image_view_base.cc
new file mode 100644
index 00000000000..d898798239f
--- /dev/null
+++ b/chromium/ui/views/controls/image_view_base.cc
@@ -0,0 +1,160 @@
+// 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/image_view_base.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/gfx/geometry/insets.h"
+
+namespace views {
+
+ImageViewBase::ImageViewBase() = default;
+
+ImageViewBase::~ImageViewBase() = default;
+
+void ImageViewBase::SetImageSize(const gfx::Size& image_size) {
+ image_size_ = image_size;
+ PreferredSizeChanged();
+}
+
+gfx::Rect ImageViewBase::GetImageBounds() const {
+ return gfx::Rect(image_origin_, GetImageSize());
+}
+
+void ImageViewBase::ResetImageSize() {
+ image_size_.reset();
+ PreferredSizeChanged();
+}
+
+void ImageViewBase::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ node_data->role = ax::mojom::Role::kImage;
+ node_data->SetName(accessible_name_);
+}
+
+void ImageViewBase::SetHorizontalAlignment(Alignment alignment) {
+ if (alignment != horizontal_alignment_) {
+ horizontal_alignment_ = alignment;
+ UpdateImageOrigin();
+ SchedulePaint();
+ }
+}
+
+ImageViewBase::Alignment ImageViewBase::GetHorizontalAlignment() const {
+ return horizontal_alignment_;
+}
+
+void ImageViewBase::SetVerticalAlignment(Alignment alignment) {
+ if (alignment != vertical_alignment_) {
+ vertical_alignment_ = alignment;
+ UpdateImageOrigin();
+ SchedulePaint();
+ }
+}
+
+ImageViewBase::Alignment ImageViewBase::GetVerticalAlignment() const {
+ return vertical_alignment_;
+}
+
+void ImageViewBase::SetAccessibleName(const base::string16& accessible_name) {
+ accessible_name_ = accessible_name;
+}
+
+base::string16 ImageViewBase::GetAccessibleName() const {
+ return accessible_name_;
+}
+
+// TODO(crbug.com/890465): Update the duplicate code here and in views::Button.
+void ImageViewBase::SetTooltipText(const base::string16& tooltip) {
+ tooltip_text_ = tooltip;
+ if (accessible_name_.empty())
+ accessible_name_ = tooltip_text_;
+}
+
+base::string16 ImageViewBase::GetTooltipText() const {
+ return tooltip_text_;
+}
+
+bool ImageViewBase::GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const {
+ if (tooltip_text_.empty())
+ return false;
+
+ *tooltip = GetTooltipText();
+ return true;
+}
+
+gfx::Size ImageViewBase::CalculatePreferredSize() const {
+ gfx::Size size = GetImageSize();
+ size.Enlarge(GetInsets().width(), GetInsets().height());
+ return size;
+}
+
+views::PaintInfo::ScaleType ImageViewBase::GetPaintScaleType() const {
+ // ImageViewBase contains an image which is rastered at the device scale
+ // factor. By default, the paint commands are recorded at a scale factor
+ // slightly different from the device scale factor. Re-rastering the image at
+ // this paint recording scale will result in a distorted image. Paint
+ // recording scale might also not be uniform along the x & y axis, thus
+ // resulting in further distortion in the aspect ratio of the final image.
+ // |kUniformScaling| ensures that the paint recording scale is uniform along
+ // the x & y axis and keeps the scale equal to the device scale factor.
+ // See http://crbug.com/754010 for more details.
+ return views::PaintInfo::ScaleType::kUniformScaling;
+}
+
+void ImageViewBase::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ UpdateImageOrigin();
+}
+
+void ImageViewBase::UpdateImageOrigin() {
+ gfx::Size image_size = GetImageSize();
+ gfx::Insets insets = GetInsets();
+
+ int x = 0;
+ // In order to properly handle alignment of images in RTL locales, we need
+ // to flip the meaning of trailing and leading. For example, if the
+ // horizontal alignment is set to trailing, then we'll use left alignment for
+ // the image instead of right alignment if the UI layout is RTL.
+ Alignment actual_horizontal_alignment = horizontal_alignment_;
+ if (base::i18n::IsRTL() && (horizontal_alignment_ != CENTER)) {
+ actual_horizontal_alignment =
+ (horizontal_alignment_ == LEADING) ? TRAILING : LEADING;
+ }
+ switch (actual_horizontal_alignment) {
+ case LEADING:
+ x = insets.left();
+ break;
+ case TRAILING:
+ x = width() - insets.right() - image_size.width();
+ break;
+ case CENTER:
+ x = (width() - insets.width() - image_size.width()) / 2 + insets.left();
+ break;
+ }
+
+ int y = 0;
+ switch (vertical_alignment_) {
+ case LEADING:
+ y = insets.top();
+ break;
+ case TRAILING:
+ y = height() - insets.bottom() - image_size.height();
+ break;
+ case CENTER:
+ y = (height() - insets.height() - image_size.height()) / 2 + insets.top();
+ break;
+ }
+
+ image_origin_ = gfx::Point(x, y);
+}
+
+void ImageViewBase::PreferredSizeChanged() {
+ View::PreferredSizeChanged();
+ UpdateImageOrigin();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/image_view_base.h b/chromium/ui/views/controls/image_view_base.h
new file mode 100644
index 00000000000..4764f2f4c47
--- /dev/null
+++ b/chromium/ui/views/controls/image_view_base.h
@@ -0,0 +1,94 @@
+// 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_IMAGE_VIEW_BASE_H_
+#define UI_VIEWS_CONTROLS_IMAGE_VIEW_BASE_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "ui/views/view.h"
+
+namespace gfx {
+class Canvas;
+}
+
+namespace views {
+
+class VIEWS_EXPORT ImageViewBase : public View {
+ public:
+ enum Alignment { LEADING, CENTER, TRAILING };
+
+ ImageViewBase();
+ ~ImageViewBase() override;
+
+ // Set the desired image size for the receiving ImageView.
+ void SetImageSize(const gfx::Size& image_size);
+
+ // Returns the actual bounds of the visible image inside the view.
+ gfx::Rect GetImageBounds() const;
+
+ // Reset the image size to the current image dimensions.
+ void ResetImageSize();
+
+ // Set / Get the horizontal alignment.
+ void SetHorizontalAlignment(Alignment ha);
+ Alignment GetHorizontalAlignment() const;
+
+ // Set / Get the vertical alignment.
+ void SetVerticalAlignment(Alignment va);
+ Alignment GetVerticalAlignment() const;
+
+ // Set / Get the tooltip text.
+ void SetTooltipText(const base::string16& tooltip);
+ base::string16 GetTooltipText() const;
+
+ // Set / Get the accessible name text.
+ void SetAccessibleName(const base::string16& name);
+ base::string16 GetAccessibleName() const;
+
+ // Overridden from View:
+ void OnPaint(gfx::Canvas* canvas) override = 0;
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+ const char* GetClassName() const override = 0;
+ bool GetTooltipText(const gfx::Point& p,
+ base::string16* tooltip) const override;
+ gfx::Size CalculatePreferredSize() const override;
+ views::PaintInfo::ScaleType GetPaintScaleType() const override;
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+ void PreferredSizeChanged() override;
+
+ protected:
+ // Returns the size the image will be painted.
+ virtual gfx::Size GetImageSize() const = 0;
+
+ // The requested image size.
+ base::Optional<gfx::Size> image_size_;
+
+ private:
+ friend class ImageViewTest;
+
+ // Recomputes and updates the |image_origin_|.
+ void UpdateImageOrigin();
+
+ // The origin of the image.
+ gfx::Point image_origin_;
+
+ // Horizontal alignment.
+ Alignment horizontal_alignment_ = Alignment::CENTER;
+
+ // Vertical alignment.
+ Alignment vertical_alignment_ = Alignment::CENTER;
+
+ // The current tooltip text.
+ base::string16 tooltip_text_;
+
+ // The current accessible name text.
+ base::string16 accessible_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageViewBase);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_IMAGE_VIEW_BASE_H_
diff --git a/chromium/ui/views/controls/image_view_unittest.cc b/chromium/ui/views/controls/image_view_unittest.cc
index 28cbb21460a..5e4d4a5576a 100644
--- a/chromium/ui/views/controls/image_view_unittest.cc
+++ b/chromium/ui/views/controls/image_view_unittest.cc
@@ -69,8 +69,8 @@ class ImageViewTest : public ViewsTestBase,
}
int CurrentImageOriginForParam() {
- gfx::Point origin =
- image_view()->ComputeImageOrigin(image_view()->GetImageSize());
+ image_view()->UpdateImageOrigin();
+ gfx::Point origin = image_view()->GetImageBounds().origin();
return GetParam() == Axis::kHorizontal ? origin.x() : origin.y();
}
@@ -126,6 +126,21 @@ TEST_P(ImageViewTest, CenterAlignment) {
EXPECT_EQ(kLeadingInset, CurrentImageOriginForParam());
}
+TEST_P(ImageViewTest, ImageOriginForCustomViewBounds) {
+ gfx::Rect image_view_bounds(10, 10, 80, 80);
+ image_view()->SetHorizontalAlignment(ImageView::CENTER);
+ image_view()->SetBoundsRect(image_view_bounds);
+
+ SkBitmap bitmap;
+ constexpr int kImageSkiaSize = 20;
+ bitmap.allocN32Pixels(kImageSkiaSize, kImageSkiaSize);
+ gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+ image_view()->SetImage(image_skia);
+
+ EXPECT_EQ(gfx::Point(30, 30), image_view()->GetImageBounds().origin());
+ EXPECT_EQ(image_view_bounds, image_view()->bounds());
+}
+
INSTANTIATE_TEST_CASE_P(,
ImageViewTest,
::testing::Values(Axis::kHorizontal, Axis::kVertical));
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index d87acf7c42d..1ee2b444c42 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -20,7 +20,6 @@
#include "ui/events/test/event_generator.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/render_text.h"
-#include "ui/gfx/switches.h"
#include "ui/gfx/text_elider.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/border.h"
@@ -163,14 +162,6 @@ class LabelSelectionTest : public LabelTest {
// LabelTest overrides:
void SetUp() override {
-#if defined(OS_MACOSX)
- // On Mac, by default RenderTextMac is used for labels which does not
- // support text selection. Instead use RenderTextHarfBuzz for selection
- // related tests. TODO(crbug.com/661394): Remove this once Mac also uses
- // RenderTextHarfBuzz for Labels.
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableHarfBuzzRenderText);
-#endif
LabelTest::SetUp();
event_generator_ =
std::make_unique<ui::test::EventGenerator>(widget()->GetNativeWindow());
diff --git a/chromium/ui/views/controls/menu/menu_closure_animation_mac.h b/chromium/ui/views/controls/menu/menu_closure_animation_mac.h
index 5c3b6d69aff..e966edd9888 100644
--- a/chromium/ui/views/controls/menu/menu_closure_animation_mac.h
+++ b/chromium/ui/views/controls/menu/menu_closure_animation_mac.h
@@ -14,6 +14,7 @@
namespace views {
class MenuItemView;
+class SubmenuView;
// This class implements the Mac menu closure animation:
// 1) For 100ms, the selected item is drawn as unselected
@@ -24,11 +25,19 @@ class MenuItemView;
// will stop the timer or animation (if they are running), so the callback will
// *not* be run - which is good, since the MenuController that would have
// received it is being deleted.
+//
+// This class also supports animating a menu away without animating the
+// selection effect, which is achieved by passing nullptr for the item to
+// animate. In this case, the animation skips straight to step 3 above.
class VIEWS_EXPORT MenuClosureAnimationMac : public gfx::AnimationDelegate {
public:
- // After this closure animation is done, |callback| is run to finally accept
- // |item|.
- MenuClosureAnimationMac(MenuItemView* item, base::OnceClosure callback);
+ // After this closure animation is done, |callback| is run to finish
+ // dismissing the menu. If |item| is given, this will animate the item being
+ // accepted before animating the menu closing; if |item| is nullptr, only the
+ // menu closure will be animated.
+ MenuClosureAnimationMac(MenuItemView* item,
+ SubmenuView* menu,
+ base::OnceClosure callback);
~MenuClosureAnimationMac() override;
// Start the animation.
@@ -37,6 +46,9 @@ class VIEWS_EXPORT MenuClosureAnimationMac : public gfx::AnimationDelegate {
// Returns the MenuItemView this animation targets.
MenuItemView* item() { return item_; }
+ // Returns the SubmenuView this animation targets.
+ SubmenuView* menu() { return menu_; }
+
// Causes animations to take no time for testing purposes. Note that this
// still causes the completion callback to be run asynchronously, so test
// situations have the same control flow as non-test situations.
@@ -51,7 +63,7 @@ class VIEWS_EXPORT MenuClosureAnimationMac : public gfx::AnimationDelegate {
kFinish,
};
- static constexpr AnimationStep NextStepFor(AnimationStep step);
+ AnimationStep NextStepFor(AnimationStep step) const;
void AdvanceAnimation();
@@ -64,6 +76,7 @@ class VIEWS_EXPORT MenuClosureAnimationMac : public gfx::AnimationDelegate {
base::OneShotTimer timer_;
std::unique_ptr<gfx::Animation> fade_animation_;
MenuItemView* item_;
+ SubmenuView* menu_;
AnimationStep step_;
DISALLOW_COPY_AND_ASSIGN(MenuClosureAnimationMac);
diff --git a/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
index 2bec6d31087..32127db42d9 100644
--- a/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
@@ -10,6 +10,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/widget/widget.h"
namespace {
@@ -19,9 +20,11 @@ static bool g_disable_animations_for_testing = false;
namespace views {
MenuClosureAnimationMac::MenuClosureAnimationMac(MenuItemView* item,
+ SubmenuView* menu,
base::OnceClosure callback)
: callback_(std::move(callback)),
item_(item),
+ menu_(menu),
step_(AnimationStep::kStart) {}
MenuClosureAnimationMac::~MenuClosureAnimationMac() {}
@@ -42,12 +45,11 @@ void MenuClosureAnimationMac::Start() {
}
// static
-constexpr MenuClosureAnimationMac::AnimationStep
-MenuClosureAnimationMac::NextStepFor(
- MenuClosureAnimationMac::AnimationStep step) {
+MenuClosureAnimationMac::AnimationStep MenuClosureAnimationMac::NextStepFor(
+ MenuClosureAnimationMac::AnimationStep step) const {
switch (step) {
case AnimationStep::kStart:
- return AnimationStep::kUnselected;
+ return item_ ? AnimationStep::kUnselected : AnimationStep::kFading;
case AnimationStep::kUnselected:
return AnimationStep::kSelected;
case AnimationStep::kSelected:
@@ -84,7 +86,7 @@ void MenuClosureAnimationMac::DisableAnimationsForTesting() {
void MenuClosureAnimationMac::AnimationProgressed(
const gfx::Animation* animation) {
- NSWindow* window = item_->GetWidget()->GetNativeWindow();
+ NSWindow* window = menu_->GetWidget()->GetNativeWindow();
[window setAlphaValue:animation->CurrentValueBetween(1.0, 0.0)];
}
diff --git a/chromium/ui/views/controls/menu/menu_config.cc b/chromium/ui/views/controls/menu/menu_config.cc
index 7ea5c0104bc..3dc6eef0d4f 100644
--- a/chromium/ui/views/controls/menu/menu_config.cc
+++ b/chromium/ui/views/controls/menu/menu_config.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/menu/menu_config.h"
#include "base/macros.h"
+#include "base/no_destructor.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/controls/menu/menu_image_util.h"
#include "ui/views/controls/menu/menu_item_view.h"
@@ -100,8 +101,8 @@ bool MenuConfig::ShouldShowAcceleratorText(const MenuItemView* item,
// static
const MenuConfig& MenuConfig::instance() {
- CR_DEFINE_STATIC_LOCAL(MenuConfig, instance, ());
- return instance;
+ static base::NoDestructor<MenuConfig> instance;
+ return *instance;
}
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_config_win.cc b/chromium/ui/views/controls/menu/menu_config_win.cc
index 6048ee062fd..72665510ca0 100644
--- a/chromium/ui/views/controls/menu/menu_config_win.cc
+++ b/chromium/ui/views/controls/menu/menu_config_win.cc
@@ -10,9 +10,8 @@
#include "base/logging.h"
#include "base/win/scoped_gdi_object.h"
-#include "base/win/win_client_metrics.h"
-#include "ui/base/l10n/l10n_util_win.h"
#include "ui/gfx/color_utils.h"
+#include "ui/gfx/platform_font_win.h"
#include "ui/native_theme/native_theme_win.h"
using ui::NativeTheme;
@@ -21,15 +20,9 @@ namespace views {
void MenuConfig::Init() {
arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
+ font_list = gfx::FontList(gfx::PlatformFontWin::GetSystemFont(
+ gfx::PlatformFontWin::SystemFont::kMenu));
- NONCLIENTMETRICS_XP metrics;
- base::win::GetNonClientMetrics(&metrics);
- l10n_util::AdjustUIFont(&(metrics.lfMenuFont));
- {
- base::win::ScopedHFONT new_font(CreateFontIndirect(&metrics.lfMenuFont));
- DLOG_ASSERT(new_font.is_valid());
- font_list = gfx::FontList(gfx::Font(new_font.get()));
- }
NativeTheme::ExtraParams extra;
gfx::Size arrow_size = NativeTheme::GetInstanceForNativeUi()->GetPartSize(
NativeTheme::kMenuPopupArrow, NativeTheme::kNormal, extra);
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index d6806061652..9e56ca54813 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -499,6 +499,10 @@ void MenuController::Run(Widget* parent,
}
void MenuController::Cancel(ExitType type) {
+#if defined(OS_MACOSX)
+ menu_closure_animation_.reset();
+#endif
+
// If the menu has already been destroyed, no further cancellation is
// needed. We especially don't want to set the |exit_type_| to a lesser
// value.
@@ -1529,7 +1533,7 @@ void MenuController::UpdateInitialLocation(const gfx::Rect& bounds,
void MenuController::Accept(MenuItemView* item, int event_flags) {
#if defined(OS_MACOSX)
menu_closure_animation_ = std::make_unique<MenuClosureAnimationMac>(
- item,
+ item, item->GetParentMenuItem()->GetSubmenu(),
base::BindOnce(&MenuController::ReallyAccept, base::Unretained(this),
base::Unretained(item), event_flags));
menu_closure_animation_->Start();
@@ -1845,8 +1849,7 @@ void MenuController::CommitPendingSelection() {
// Open all the submenus preceeding the last menu item (last menu item is
// handled next).
if (new_path.size() > 1) {
- for (std::vector<MenuItemView*>::iterator i = new_path.begin();
- i != new_path.end() - 1; ++i) {
+ for (auto i = new_path.begin(); i != new_path.end() - 1; ++i) {
OpenMenu(*i);
}
}
@@ -2070,10 +2073,9 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
const int right_of_parent =
item_loc.x() + item->width() - submenu_horizontal_inset;
- 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);
+ MenuScrollViewContainer* container =
+ item->GetParentMenuItem()->GetSubmenu()->GetScrollViewContainer();
+ menu_bounds.set_y(item_loc.y() - container->border()->GetInsets().top());
// Assume the menu can be placed in the preferred location.
menu_bounds.set_x(create_on_right ? right_of_parent : left_of_parent);
@@ -2609,7 +2611,18 @@ void MenuController::RepostEventAndCancel(SubmenuView* source,
if (last_part.type != MenuPart::NONE)
exit_type = EXIT_OUTERMOST;
}
+#if defined(OS_MACOSX)
+ SubmenuView* target = exit_type == EXIT_ALL
+ ? source
+ : state_.item->GetRootMenuItem()->GetSubmenu();
+ menu_closure_animation_ = std::make_unique<MenuClosureAnimationMac>(
+ nullptr, target,
+ base::BindOnce(&MenuController::Cancel, base::Unretained(this),
+ exit_type));
+ menu_closure_animation_->Start();
+#else
Cancel(exit_type);
+#endif
}
void MenuController::SetDropMenuItem(MenuItemView* new_target,
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index 57c22228ae9..ad8f6732a80 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -1232,6 +1232,7 @@ TEST_F(MenuControllerTest, PreserveGestureForOwner) {
// Tests that touch outside menu does not closes the menu when forwarding
// gesture events to owner.
TEST_F(MenuControllerTest, NoTouchCloseWhenSendingGesturesToOwner) {
+ views::test::DisableMenuClosureAnimations();
MenuController* controller = menu_controller();
// Owner wants the gesture events.
@@ -1259,6 +1260,7 @@ TEST_F(MenuControllerTest, NoTouchCloseWhenSendingGesturesToOwner) {
// Touch outside again and menu should be closed.
controller->OnTouchEvent(sub_menu, &touch_event);
+ views::test::WaitForMenuClosureAnimation();
EXPECT_FALSE(IsShowing());
EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}
@@ -1267,6 +1269,7 @@ TEST_F(MenuControllerTest, NoTouchCloseWhenSendingGesturesToOwner) {
// occur outside of the bounds of the menu. Instead a proper shutdown should
// occur.
TEST_F(MenuControllerTest, AsynchronousRepostEvent) {
+ views::test::DisableMenuClosureAnimations();
MenuController* controller = menu_controller();
TestMenuControllerDelegate* delegate = menu_controller_delegate();
std::unique_ptr<TestMenuControllerDelegate> nested_delegate(
@@ -1291,6 +1294,7 @@ TEST_F(MenuControllerTest, AsynchronousRepostEvent) {
// When attempting to select outside of all menus this should lead to a
// shutdown. This should not crash while attempting to repost the event.
SetSelectionOnPointerDown(sub_menu, &event);
+ views::test::WaitForMenuClosureAnimation();
EXPECT_EQ(delegate, GetCurrentDelegate());
EXPECT_EQ(1, delegate->on_menu_closed_called());
@@ -1305,6 +1309,7 @@ TEST_F(MenuControllerTest, AsynchronousRepostEvent) {
// Tests that an asynchronous menu reposts touch events that occur outside of
// the bounds of the menu, and that the menu closes.
TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) {
+ views::test::DisableMenuClosureAnimations();
MenuController* controller = menu_controller();
TestMenuControllerDelegate* delegate = menu_controller_delegate();
@@ -1319,6 +1324,7 @@ TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) {
ui::ET_TOUCH_PRESSED, location, ui::EventTimeForNow(),
ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
controller->OnTouchEvent(sub_menu, &event);
+ views::test::WaitForMenuClosureAnimation();
EXPECT_FALSE(IsShowing());
EXPECT_EQ(1, delegate->on_menu_closed_called());
@@ -1332,6 +1338,7 @@ TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) {
// Tests that having the MenuController deleted during RepostEvent does not
// cause a crash. ASAN bots should not detect use-after-free in MenuController.
TEST_F(MenuControllerTest, AsynchronousRepostEventDeletesController) {
+ views::test::DisableMenuClosureAnimations();
MenuController* controller = menu_controller();
std::unique_ptr<TestMenuControllerDelegate> nested_delegate(
new TestMenuControllerDelegate());
@@ -1358,6 +1365,7 @@ TEST_F(MenuControllerTest, AsynchronousRepostEventDeletesController) {
// When attempting to select outside of all menus this should lead to a
// shutdown. This should not crash while attempting to repost the event.
SetSelectionOnPointerDown(sub_menu, &event);
+ views::test::WaitForMenuClosureAnimation();
// Close to remove observers before test TearDown
sub_menu->Close();
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 104ae4c6da5..780a0f9c27b 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -86,7 +86,7 @@ void TransferGesture(Widget* source, Widget* target) {
#else // !defined(OS_MACOSX)
source->GetGestureRecognizer()->TransferEventsTo(
source->GetNativeView(), target->GetNativeView(),
- ui::GestureRecognizer::ShouldCancelTouches::DontCancel);
+ ui::TransferTouchesBehavior::kDontCancel);
#endif // defined(OS_MACOSX)
}
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 6c007a1030c..7b17d2662ec 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -155,7 +155,18 @@ bool MenuItemView::GetTooltipText(const gfx::Point& p,
}
void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- node_data->role = ax::mojom::Role::kMenuItem;
+ // Set the role based on the type of menu item.
+ switch (GetType()) {
+ case CHECKBOX:
+ node_data->role = ax::mojom::Role::kMenuItemCheckBox;
+ break;
+ case RADIO:
+ node_data->role = ax::mojom::Role::kMenuItemRadio;
+ break;
+ default:
+ node_data->role = ax::mojom::Role::kMenuItem;
+ break;
+ }
base::string16 item_text;
if (IsContainer()) {
@@ -867,7 +878,7 @@ void MenuItemView::GetLabelStyle(MenuDelegate::LabelStyle* style) const {
void MenuItemView::AddEmptyMenus() {
DCHECK(HasSubmenu());
- if (!submenu_->HasVisibleChildren()) {
+ if (!submenu_->HasVisibleChildren() && !submenu_->HasEmptyMenuItemView()) {
submenu_->AddChildViewAt(new EmptyMenuMenuItem(this), 0);
} else {
for (int i = 0, item_count = submenu_->GetMenuItemCount(); i < item_count;
diff --git a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
index 07273f5de1a..e4f42f008b4 100644
--- a/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view_unittest.cc
@@ -136,13 +136,18 @@ TEST(MenuItemViewUnitTest, TestEmptySubmenuWhenAllChildItemsAreHidden) {
EXPECT_EQ(2, submenu->child_count());
// Adds any empty menu items to the menu, if needed.
+ EXPECT_FALSE(submenu->HasEmptyMenuItemView());
root_menu.AddEmptyMenus();
-
+ EXPECT_TRUE(submenu->HasEmptyMenuItemView());
// Because all of the submenu's children are hidden, an empty menu item should
// have been added.
ASSERT_EQ(3, submenu->child_count());
MenuItemView* empty_item = static_cast<MenuItemView*>(submenu->child_at(0));
ASSERT_TRUE(empty_item);
+ // Not allowed to add an duplicated empty menu item
+ // if it already has an empty menu item.
+ root_menu.AddEmptyMenus();
+ ASSERT_EQ(3, submenu->child_count());
ASSERT_EQ(MenuItemView::kEmptyMenuItemViewID, empty_item->id());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_APP_MENU_EMPTY_SUBMENU),
empty_item->title());
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc
index 45b071661bb..b38b0d49d53 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc
@@ -6,6 +6,7 @@
#include "ui/aura/env.h"
#include "ui/aura/window.h"
+#include "ui/base/ui_base_features.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/public/activation_client.h"
@@ -23,16 +24,27 @@ aura::Window* GetOwnerRootWindow(views::Widget* owner) {
MenuPreTargetHandlerAura::MenuPreTargetHandlerAura(MenuController* controller,
Widget* owner)
: controller_(controller), root_(GetOwnerRootWindow(owner)) {
- aura::Env::GetInstance()->AddPreTargetHandler(
- this, ui::EventTarget::Priority::kSystem);
if (root_) {
+ root_->env()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
wm::GetActivationClient(root_)->AddObserver(this);
root_->AddObserver(this);
+ } else {
+ // TODO(mukai): check if this code path can run in ChromeOS and find the
+ // solution for SingleProcessMash.
+ if (features::IsUsingWindowService()) {
+ LOG(WARNING) << "MenuPreTargetHandlerAura is created without owner "
+ << "widget. This may not work well in SingleProcessMash.";
+ }
+ aura::Env::GetInstance()->AddPreTargetHandler(
+ this, ui::EventTarget::Priority::kSystem);
}
}
MenuPreTargetHandlerAura::~MenuPreTargetHandlerAura() {
- aura::Env::GetInstance()->RemovePreTargetHandler(this);
+ if (root_)
+ root_->env()->RemovePreTargetHandler(this);
+ else
+ aura::Env::GetInstance()->RemovePreTargetHandler(this);
Cleanup();
}
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 2cc6a8c1a7c..7acfc99f907 100644
--- a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -106,6 +106,8 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
gfx::Rect(kWindowOffset, kWindowOffset, kWindowWidth, kWindowHeight));
parent_->Show();
+ native_view_subview_count_ = [[parent_->GetNativeView() subviews] count];
+
base::Closure on_close = base::Bind(&MenuRunnerCocoaTest::MenuCloseCallback,
base::Unretained(this));
if (GetParam() == MenuType::NATIVE)
@@ -116,6 +118,9 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
}
void TearDown() override {
+ EXPECT_EQ(native_view_subview_count_,
+ [[parent_->GetNativeView() subviews] count]);
+
if (runner_) {
runner_->Release();
runner_ = NULL;
@@ -151,10 +156,6 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
void RunMenuAt(const gfx::Rect& anchor) {
last_anchor_frame_ = NSZeroRect;
- // Should be one child (the compositor layer) before showing, and it should
- // go up by one (the anchor view) while the menu is shown.
- EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]);
-
base::OnceClosure callback =
base::BindOnce(&MenuRunnerCocoaTest::ComboboxRunMenuAtCallback,
base::Unretained(this));
@@ -168,9 +169,6 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
runner_->RunMenuAt(parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT,
MenuRunner::COMBOBOX);
MaybeRunAsync();
-
- // Ensure the anchor view is removed.
- EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]);
}
void MenuCancelCallback() {
@@ -244,6 +242,7 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
internal::MenuRunnerImplInterface* runner_ = nullptr;
views::Widget* parent_ = nullptr;
NSRect last_anchor_frame_ = NSZeroRect;
+ NSUInteger native_view_subview_count_ = 0;
int menu_close_count_ = 0;
private:
@@ -256,10 +255,11 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
NSArray* subviews = [parent_->GetNativeView() subviews];
// An anchor view should only be added for Native menus.
if (GetParam() == MenuType::NATIVE) {
- ASSERT_EQ(2u, [subviews count]);
- last_anchor_frame_ = [[subviews objectAtIndex:1] frame];
+ ASSERT_EQ(native_view_subview_count_ + 1, [subviews count]);
+ last_anchor_frame_ =
+ [[subviews objectAtIndex:native_view_subview_count_] frame];
} else {
- EXPECT_EQ(1u, [subviews count]);
+ EXPECT_EQ(native_view_subview_count_, [subviews count]);
}
runner_->Cancel();
}
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl.cc b/chromium/ui/views/controls/menu/menu_runner_impl.cc
index 1c7b5c4c72a..3f1fb8af38b 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_impl.cc
@@ -192,8 +192,7 @@ void MenuRunnerImpl::SiblingMenuCreated(MenuItemView* menu) {
MenuRunnerImpl::~MenuRunnerImpl() {
delete menu_;
- for (std::set<MenuItemView*>::iterator i = sibling_menus_.begin();
- i != sibling_menus_.end(); ++i)
+ for (auto i = sibling_menus_.begin(); i != sibling_menus_.end(); ++i)
delete *i;
}
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index c9ad4e4f5b9..36865a59316 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -61,6 +61,14 @@ SubmenuView::~SubmenuView() {
delete scroll_view_container_;
}
+bool SubmenuView::HasEmptyMenuItemView() {
+ for (int i = 0; i < child_count(); i++) {
+ if (child_at(i)->id() == MenuItemView::kEmptyMenuItemViewID)
+ return true;
+ }
+ return false;
+}
+
bool SubmenuView::HasVisibleChildren() {
for (int i = 0, item_count = GetMenuItemCount(); i < item_count; i++) {
if (GetMenuItemAt(i)->visible())
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 9ba69331264..4374790035e 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -51,6 +51,9 @@ class VIEWS_EXPORT SubmenuView : public View,
explicit SubmenuView(MenuItemView* parent);
~SubmenuView() override;
+ // Returns true if the submenu has at least one empty menu item.
+ bool HasEmptyMenuItemView();
+
// Returns true if the submenu has at least one visible child item.
bool HasVisibleChildren();
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index 32019ba3fdb..5240d2bf72d 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -67,6 +67,10 @@ void NativeViewHost::SetNativeViewSize(const gfx::Size& size) {
InvalidateLayout();
}
+gfx::NativeView NativeViewHost::GetNativeViewContainer() const {
+ return native_view_ ? native_wrapper_->GetNativeViewContainer() : nullptr;
+}
+
void NativeViewHost::NativeViewDestroyed() {
// Detach so we can clear our state and notify the native_wrapper_ to release
// ref on the native view.
@@ -225,7 +229,7 @@ void NativeViewHost::ClearFocus() {
Widget::Widgets widgets;
Widget::GetAllChildWidgets(native_view(), &widgets);
- for (Widget::Widgets::iterator i = widgets.begin(); i != widgets.end(); ++i) {
+ for (auto i = widgets.begin(); i != widgets.end(); ++i) {
focus_manager->ViewRemoved((*i)->GetRootView());
if (!focus_manager->GetFocusedView())
return;
diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h
index 5bd897cf3ed..ec0b8e9f18a 100644
--- a/chromium/ui/views/controls/native/native_view_host.h
+++ b/chromium/ui/views/controls/native/native_view_host.h
@@ -63,6 +63,10 @@ class VIEWS_EXPORT NativeViewHost : public View {
// NatieView's size always equals this View's size.
void SetNativeViewSize(const gfx::Size& size);
+ // Returns the container that contains this host's native view. Returns null
+ // if there's no attached native view or it has no container.
+ gfx::NativeView GetNativeViewContainer() const;
+
// Fast resizing will move the native view and clip its visible region, this
// will result in white areas and will not resize the content (so scrollbars
// will be all wrong and content will flow offscreen). Only use this
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 4bd67c7a87d..3be7f536eb1 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -5,6 +5,7 @@
#include "ui/views/controls/native/native_view_host_aura.h"
#include "base/logging.h"
+#include "base/optional.h"
#include "build/build_config.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/focus_client.h"
@@ -98,10 +99,12 @@ void NativeViewHostAura::AttachNativeView() {
}
void NativeViewHostAura::NativeViewDetaching(bool destroyed) {
- // This method causes a succession of window tree changes.
- // ScopedPauseOcclusionTracking ensures that occlusion is recomputed at the
- // end of the method instead of after each change.
- aura::WindowOcclusionTracker::ScopedPauseOcclusionTracking pause_occlusion;
+ // This method causes a succession of window tree changes. ScopedPause ensures
+ // that occlusion is recomputed at the end of the method instead of after each
+ // change.
+ base::Optional<aura::WindowOcclusionTracker::ScopedPause> pause_occlusion;
+ if (clipping_window_)
+ pause_occlusion.emplace(clipping_window_->env());
clipping_window_delegate_->set_native_view(NULL);
RemoveClippingWindow();
@@ -212,6 +215,10 @@ void NativeViewHostAura::SetFocus() {
client->FocusWindow(window);
}
+gfx::NativeView NativeViewHostAura::GetNativeViewContainer() const {
+ return clipping_window_.get();
+}
+
gfx::NativeViewAccessible NativeViewHostAura::GetNativeViewAccessible() {
return NULL;
}
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 a6072997977..0adf8fb3aec 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.h
+++ b/chromium/ui/views/controls/native/native_view_host_aura.h
@@ -41,6 +41,7 @@ class NativeViewHostAura : public NativeViewHostWrapper,
override;
void HideWidget() override;
void SetFocus() override;
+ gfx::NativeView GetNativeViewContainer() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(int x, int y) override;
diff --git a/chromium/ui/views/controls/native/native_view_host_mac.h b/chromium/ui/views/controls/native/native_view_host_mac.h
index 69659c9aafd..f46e575e442 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.h
+++ b/chromium/ui/views/controls/native/native_view_host_mac.h
@@ -7,24 +7,35 @@
#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
+#include "ui/base/cocoa/views_hostable.h"
#include "ui/views/controls/native/native_view_host_wrapper.h"
#include "ui/views/views_export.h"
namespace ui {
class LayerOwner;
-}
+class ViewsHostableView;
+} // namespace ui
namespace views {
+class BridgedNativeWidgetHostImpl;
class NativeViewHost;
// Mac implementation of NativeViewHostWrapper.
-class NativeViewHostMac : public NativeViewHostWrapper {
+class NativeViewHostMac : public NativeViewHostWrapper,
+ public ui::ViewsHostableView::Host {
public:
explicit NativeViewHostMac(NativeViewHost* host);
~NativeViewHostMac() override;
- // Overridden from NativeViewHostWrapper:
+ // ViewsHostableView::Host:
+ ui::Layer* GetUiLayer() const override;
+ uint64_t GetViewsFactoryHostId() const override;
+ uint64_t GetNSViewId() const override;
+ id GetAccessibilityElement() const override;
+ void OnHostableViewDestroying() override;
+
+ // NativeViewHostWrapper:
void AttachNativeView() override;
void NativeViewDetaching(bool destroyed) override;
void AddedToWidget() override;
@@ -37,16 +48,25 @@ class NativeViewHostMac : public NativeViewHostWrapper {
override;
void HideWidget() override;
void SetFocus() override;
+ gfx::NativeView GetNativeViewContainer() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(int x, int y) override;
private:
+ // Return the BridgedNativeWidgetHostImpl for this hosted view.
+ BridgedNativeWidgetHostImpl* GetBridgedNativeWidgetHost() const;
+
// Our associated NativeViewHost. Owns this.
NativeViewHost* host_;
// Retain the native view as it may be destroyed at an unpredictable time.
base::scoped_nsobject<NSView> native_view_;
+ // If |native_view| supports the ViewsHostable protocol, then this is the
+ // the corresponding ViewsHostableView interface (which is implemeted only
+ // by WebContents and tests).
+ ui::ViewsHostableView* native_view_hostable_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(NativeViewHostMac);
};
diff --git a/chromium/ui/views/controls/native/native_view_host_mac.mm b/chromium/ui/views/controls/native/native_view_host_mac.mm
index debbe51f102..d98e6e1456c 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.mm
+++ b/chromium/ui/views/controls/native/native_view_host_mac.mm
@@ -8,19 +8,11 @@
#include "base/mac/foundation_util.h"
#import "ui/accessibility/platform/ax_platform_node_mac.h"
-#import "ui/base/cocoa/accessibility_hostable.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/widget/native_widget_mac.h"
#include "ui/views/widget/widget.h"
-// NSViews that can be drawn as a ui::Layer directly will implement this
-// interface. Calling cr_setParentLayer will embed the ui::Layer of the NSView
-// under |parentUiLayer|.
-@interface NSView (UICompositor)
-- (void)cr_setParentUiLayer:(ui::Layer*)parentUiLayer;
-@end
-
namespace views {
namespace {
@@ -59,6 +51,60 @@ NativeViewHostMac::NativeViewHostMac(NativeViewHost* host) : host_(host) {
NativeViewHostMac::~NativeViewHostMac() {
}
+BridgedNativeWidgetHostImpl* NativeViewHostMac::GetBridgedNativeWidgetHost()
+ const {
+ return BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ host_->GetWidget()->GetNativeWindow());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeViewHostMac, ViewsHostableView::Host implementation:
+
+ui::Layer* NativeViewHostMac::GetUiLayer() const {
+ return host_->layer();
+}
+
+uint64_t NativeViewHostMac::GetViewsFactoryHostId() const {
+ auto* bridge_host = GetBridgedNativeWidgetHost();
+ if (bridge_host && bridge_host->bridge_factory_host())
+ return bridge_host->bridge_factory_host()->GetHostId();
+ return 0;
+}
+
+uint64_t NativeViewHostMac::GetNSViewId() const {
+ auto* bridge_host = GetBridgedNativeWidgetHost();
+ if (bridge_host)
+ return bridge_host->GetRootViewNSViewId();
+ return 0;
+}
+
+id NativeViewHostMac::GetAccessibilityElement() const {
+ // Find the closest ancestor view that participates in the views toolkit
+ // accessibility hierarchy and set its element as the native view's parent.
+ // This is necessary because a closer ancestor might already be attaching
+ // to the NSView/content hierarchy.
+ // For example, web content is currently embedded into the views hierarchy
+ // roughly like this:
+ // BrowserView (views)
+ // |_ WebView (views)
+ // |_ NativeViewHost (views)
+ // |_ WebContentView (Cocoa, is |native_view_| in this scenario,
+ // | accessibility ignored).
+ // |_ RenderWidgetHostView (Cocoa)
+ // WebView specifies either the RenderWidgetHostView or the native view as
+ // its accessibility element. That means that if we were to set it as
+ // |native_view_|'s parent, the RenderWidgetHostView would be its own
+ // accessibility parent! Instead, we want to find the browser view and
+ // attach to its node.
+ return ClosestPlatformAncestorNode(host_->parent());
+}
+
+void NativeViewHostMac::OnHostableViewDestroying() {
+ DCHECK(native_view_hostable_);
+ host_->NativeViewDestroyed();
+ DCHECK(!native_view_hostable_);
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostMac, NativeViewHostWrapper implementation:
@@ -66,46 +112,25 @@ void NativeViewHostMac::AttachNativeView() {
DCHECK(host_->native_view());
DCHECK(!native_view_);
native_view_.reset([host_->native_view() retain]);
+ EnsureNativeViewHasNoChildWidgets(native_view_);
- if ([native_view_ respondsToSelector:@selector(cr_setParentUiLayer:)])
- [native_view_ cr_setParentUiLayer:host_->layer()];
- if ([native_view_ conformsToProtocol:@protocol(AccessibilityHostable)]) {
- // Find the closest ancestor view that participates in the views toolkit
- // accessibility hierarchy and set its element as the native view's parent.
- // This is necessary because a closer ancestor might already be attaching
- // to the NSView/content hierarchy.
- // For example, web content is currently embedded into the views hierarchy
- // roughly like this:
- // BrowserView (views)
- // |_ WebView (views)
- // |_ NativeViewHost (views)
- // |_ WebContentView (Cocoa, is |native_view_| in this scenario,
- // | accessibility ignored).
- // |_ RenderWidgetHostView (Cocoa)
- // WebView specifies either the RenderWidgetHostView or the native view as
- // its accessibility element. That means that if we were to set it as
- // |native_view_|'s parent, the RenderWidgetHostView would be its own
- // accessibility parent! Instead, we want to find the browser view and
- // attach to its node.
+ auto* bridge_host = GetBridgedNativeWidgetHost();
+ DCHECK(bridge_host);
+ [bridge_host->native_widget_mac()->GetNativeView() addSubview:native_view_];
+ bridge_host->SetAssociationForView(host_, native_view_);
+
+ if ([native_view_ conformsToProtocol:@protocol(ViewsHostable)]) {
id hostable = native_view_;
- [hostable setAccessibilityParentElement:ClosestPlatformAncestorNode(
- host_->parent())];
+ native_view_hostable_ = [hostable viewsHostableView];
+ if (native_view_hostable_)
+ native_view_hostable_->OnViewsHostableAttached(this);
}
-
- EnsureNativeViewHasNoChildWidgets(native_view_);
- BridgedNativeWidget* bridge = NativeWidgetMac::GetBridgeForNativeWindow(
- host_->GetWidget()->GetNativeWindow());
- DCHECK(bridge);
- [bridge->ns_view() addSubview:native_view_];
- bridge->SetAssociationForView(host_, native_view_);
}
void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
- // |destroyed| is only true if this class calls host_->NativeViewDestroyed().
- // Aura does this after observing an aura OnWindowDestroying, but NSViews
- // are reference counted so there isn't a reliable signal. Instead, a
- // reference is retained until the NativeViewHost is detached.
- DCHECK(!destroyed);
+ // |destroyed| is only true if this class calls host_->NativeViewDestroyed(),
+ // which is called if a hosted WebContentsView about to be destroyed (note
+ // that its corresponding NSView may still exist).
// |native_view_| can be nil here if RemovedFromWidget() is called before
// NativeViewHost::Detach().
@@ -118,19 +143,16 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
[host_->native_view() setHidden:YES];
[host_->native_view() removeFromSuperview];
- if ([native_view_ respondsToSelector:@selector(cr_setParentUiLayer:)])
- [native_view_ cr_setParentUiLayer:nullptr];
- if ([native_view_ conformsToProtocol:@protocol(AccessibilityHostable)]) {
- id hostable = native_view_;
- [hostable setAccessibilityParentElement:nil];
+ if (native_view_hostable_) {
+ native_view_hostable_->OnViewsHostableDetached();
+ native_view_hostable_ = nullptr;
}
EnsureNativeViewHasNoChildWidgets(host_->native_view());
- BridgedNativeWidget* bridge = NativeWidgetMac::GetBridgeForNativeWindow(
- host_->GetWidget()->GetNativeWindow());
- // BridgedNativeWidget can be null when Widget is closing.
- if (bridge)
- bridge->ClearAssociationForView(host_);
+ auto* bridge_host = GetBridgedNativeWidgetHost();
+ // BridgedNativeWidgetImpl can be null when Widget is closing.
+ if (bridge_host)
+ bridge_host->ClearAssociationForView(host_);
native_view_.reset();
}
@@ -191,15 +213,29 @@ void NativeViewHostMac::ShowWidget(int x,
[[host_->native_view() superview] convertRect:window_rect fromView:nil];
[host_->native_view() setFrame:container_rect];
[host_->native_view() setHidden:NO];
+
+ if (native_view_hostable_)
+ native_view_hostable_->OnViewsHostableShow(gfx::Rect(x, y, w, h));
}
void NativeViewHostMac::HideWidget() {
[host_->native_view() setHidden:YES];
+
+ if (native_view_hostable_)
+ native_view_hostable_->OnViewsHostableHide();
}
void NativeViewHostMac::SetFocus() {
if ([host_->native_view() acceptsFirstResponder])
[[host_->native_view() window] makeFirstResponder:host_->native_view()];
+
+ if (native_view_hostable_)
+ native_view_hostable_->OnViewsHostableMakeFirstResponder();
+}
+
+gfx::NativeView NativeViewHostMac::GetNativeViewContainer() const {
+ NOTIMPLEMENTED();
+ return nullptr;
}
gfx::NativeViewAccessible NativeViewHostMac::GetNativeViewAccessible() {
diff --git a/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm b/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm
index 4a4fdcad1b1..85373e5b977 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm
+++ b/chromium/ui/views/controls/native/native_view_host_mac_unittest.mm
@@ -12,17 +12,38 @@
#import "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#import "testing/gtest_mac.h"
-#import "ui/base/cocoa/accessibility_hostable.h"
+#import "ui/base/cocoa/views_hostable.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/native/native_view_host_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
-@interface TestAccessibilityHostableView : NSView<AccessibilityHostable>
-@property(nonatomic, assign) id accessibilityParentElement;
+class TestViewsHostable : public ui::ViewsHostableView {
+ public:
+ id parent_accessibility_element() const {
+ return parent_accessibility_element_;
+ }
+
+ private:
+ // ui::ViewsHostableView:
+ void OnViewsHostableAttached(ui::ViewsHostableView::Host* host) override {
+ parent_accessibility_element_ = host->GetAccessibilityElement();
+ }
+ void OnViewsHostableDetached() override {
+ parent_accessibility_element_ = nil;
+ }
+ void OnViewsHostableShow(const gfx::Rect& bounds_in_window) override {}
+ void OnViewsHostableHide() override {}
+ void OnViewsHostableMakeFirstResponder() override {}
+
+ id parent_accessibility_element_ = nil;
+};
+
+@interface TestViewsHostableView : NSView<ViewsHostable>
+@property(nonatomic, assign) ui::ViewsHostableView* viewsHostableView;
@end
-@implementation TestAccessibilityHostableView
-@synthesize accessibilityParentElement = accessibilityParentElement_;
+@implementation TestViewsHostableView
+@synthesize viewsHostableView = viewsHostableView_;
@end
namespace views {
@@ -115,15 +136,18 @@ TEST_F(NativeViewHostMacTest, AccessibilityParent) {
CreateHost();
host()->Detach();
- base::scoped_nsobject<TestAccessibilityHostableView> view(
- [[TestAccessibilityHostableView alloc] init]);
+ base::scoped_nsobject<TestViewsHostableView> view(
+ [[TestViewsHostableView alloc] init]);
+ TestViewsHostable views_hostable;
+ [view setViewsHostableView:&views_hostable];
+
host()->Attach(view);
- EXPECT_NSEQ([view accessibilityParentElement],
+ EXPECT_NSEQ(views_hostable.parent_accessibility_element(),
toplevel()->GetRootView()->GetNativeViewAccessible());
host()->Detach();
DestroyHost();
- EXPECT_FALSE([view accessibilityParentElement]);
+ EXPECT_FALSE(views_hostable.parent_accessibility_element());
}
// Test that the content windows' bounds are set to the correct values while the
diff --git a/chromium/ui/views/controls/native/native_view_host_wrapper.h b/chromium/ui/views/controls/native/native_view_host_wrapper.h
index 513c35f1a71..07cf9f1fea0 100644
--- a/chromium/ui/views/controls/native/native_view_host_wrapper.h
+++ b/chromium/ui/views/controls/native/native_view_host_wrapper.h
@@ -78,6 +78,10 @@ class NativeViewHostWrapper {
// Sets focus to the gfx::NativeView.
virtual void SetFocus() = 0;
+ // Returns the container that contains the NativeViewHost's native view if
+ // any.
+ virtual gfx::NativeView GetNativeViewContainer() const = 0;
+
// Return the native view accessible corresponding to the wrapped native
// view.
virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
diff --git a/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.h b/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.h
index a0c88726dab..c69087a9382 100644
--- a/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/cocoa_scroll_bar.h
@@ -5,13 +5,13 @@
#ifndef UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
#define UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
-#include "base/macros.h"
#import "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/animation/slide_animation.h"
-#import "ui/views/cocoa/views_scrollbar_bridge.h"
#include "ui/views/controls/scrollbar/base_scroll_bar.h"
#include "ui/views/views_export.h"
+#import "ui/views_bridge_mac/views_scrollbar_bridge.h"
namespace views {
diff --git a/chromium/ui/views/controls/styled_label.cc b/chromium/ui/views/controls/styled_label.cc
index 2c12e6e77ef..9e4477f7636 100644
--- a/chromium/ui/views/controls/styled_label.cc
+++ b/chromium/ui/views/controls/styled_label.cc
@@ -28,13 +28,6 @@ namespace views {
namespace {
-gfx::Insets FocusBorderInsets(const Label& label) {
- // StyledLabel never adds a border, so the only Insets added are for the
- // possible focus ring.
- DCHECK(label.View::GetInsets().IsEmpty());
- return label.GetInsets();
-}
-
std::unique_ptr<Label> CreateLabelRange(
const base::string16& text,
int text_context,
@@ -216,24 +209,6 @@ const char* StyledLabel::GetClassName() const {
return kViewClassName;
}
-gfx::Insets StyledLabel::GetInsets() const {
- gfx::Insets insets = View::GetInsets();
- if (Link::GetDefaultFocusStyle() != Link::FocusStyle::RING)
- return insets;
-
- // We need a focus border iff we contain a link that will have a focus border.
- // That in turn will be true only if the link is non-empty.
- for (StyleRanges::const_iterator i(style_ranges_.begin());
- i != style_ranges_.end(); ++i) {
- if (i->style_info.IsLink() && !i->range.is_empty()) {
- insets += gfx::Insets(Link::kFocusBorderPadding);
- break;
- }
- }
-
- return insets;
-}
-
void StyledLabel::GetAccessibleNodeData(ui::AXNodeData* node_data) {
if (text_context_ == style::CONTEXT_DIALOG_TITLE)
node_data->role = ax::mojom::Role::kTitleBar;
@@ -488,26 +463,18 @@ gfx::Size StyledLabel::CalculateAndDoLayout(int width, bool dry_run) {
gfx::Size view_size = child_view->GetPreferredSize();
// |offset.y()| already contains |insets.top()|.
gfx::Point view_origin(insets.left() + offset.x(), offset.y());
- gfx::Insets focus_border_insets;
- if (Link::GetDefaultFocusStyle() == Link::FocusStyle::RING && label) {
- // Calculate the size of the optional focus border, and overlap by that
- // amount. Otherwise, "<a>link</a>," will render as "link ,".
- focus_border_insets = FocusBorderInsets(*label);
- }
- view_origin.Offset(-focus_border_insets.left(), -focus_border_insets.top());
// The custom view could be wider than the available width; clamp as needed.
- if (custom_view) {
- view_size.set_width(std::min(
- view_size.width(), width - offset.x() + focus_border_insets.width()));
- }
+ if (custom_view)
+ view_size.set_width(std::min(view_size.width(), width - offset.x()));
+
child_view->SetBoundsRect(gfx::Rect(view_origin, view_size));
- offset.set_x(offset.x() + view_size.width() - focus_border_insets.width());
+ offset.set_x(offset.x() + view_size.width());
total_height =
- std::max(total_height, child_view->bounds().bottom() + insets.bottom() -
- focus_border_insets.bottom());
+ std::max(total_height, std::max(child_view->bounds().bottom(),
+ offset.y() + default_line_height) +
+ insets.bottom());
used_width = std::max(used_width, offset.x());
- max_line_height = std::max(
- max_line_height, view_size.height() - focus_border_insets.height());
+ max_line_height = std::max(max_line_height, view_size.height());
if (!dry_run) {
views_in_a_line.push_back(child_view);
diff --git a/chromium/ui/views/controls/styled_label.h b/chromium/ui/views/controls/styled_label.h
index 43544ef691b..110007b1838 100644
--- a/chromium/ui/views/controls/styled_label.h
+++ b/chromium/ui/views/controls/styled_label.h
@@ -140,7 +140,6 @@ class VIEWS_EXPORT StyledLabel : public View, public LinkListener {
// View:
const char* GetClassName() const override;
- gfx::Insets GetInsets() const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int w) const override;
diff --git a/chromium/ui/views/controls/styled_label_unittest.cc b/chromium/ui/views/controls/styled_label_unittest.cc
index e79fadddb32..1d218215e66 100644
--- a/chromium/ui/views/controls/styled_label_unittest.cc
+++ b/chromium/ui/views/controls/styled_label_unittest.cc
@@ -513,13 +513,32 @@ TEST_F(StyledLabelTest, SetTextContextAndDefaultStyle) {
}
TEST_F(StyledLabelTest, LineHeight) {
- const std::string text("one");
+ const std::string text("one\ntwo\nthree");
+ InitStyledLabel(text);
+ styled()->SetLineHeight(18);
+ EXPECT_EQ(18 * 3, styled()->GetHeightForWidth(100));
+}
+
+TEST_F(StyledLabelTest, LineHeightWithBorder) {
+ const std::string text("one\ntwo\nthree");
+ InitStyledLabel(text);
+ styled()->SetLineHeight(18);
+ styled()->SetBorder(views::CreateSolidBorder(1, SK_ColorGRAY));
+ EXPECT_EQ(18 * 3 + 2, styled()->GetHeightForWidth(100));
+}
+
+TEST_F(StyledLabelTest, LineHeightWithLink) {
+ const std::string text("one\ntwo\nthree");
InitStyledLabel(text);
- int default_height = styled()->GetHeightForWidth(100);
- const std::string newline_text("one\ntwo\nthree");
- InitStyledLabel(newline_text);
styled()->SetLineHeight(18);
- EXPECT_EQ(18 * 2 + default_height, styled()->GetHeightForWidth(100));
+
+ styled()->AddStyleRange(gfx::Range(0, 3),
+ StyledLabel::RangeStyleInfo::CreateForLink());
+ styled()->AddStyleRange(gfx::Range(4, 7),
+ StyledLabel::RangeStyleInfo::CreateForLink());
+ styled()->AddStyleRange(gfx::Range(8, 13),
+ StyledLabel::RangeStyleInfo::CreateForLink());
+ EXPECT_EQ(18 * 3, styled()->GetHeightForWidth(100));
}
TEST_F(StyledLabelTest, HandleEmptyLayout) {
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 04e572c25d0..96309bc1709 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -407,7 +407,7 @@ TabStrip::TabStrip(TabbedPane::Orientation orientation,
layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END);
} else {
const int kTabStripEdgePadding = 8;
- const int kTabSpacing = 16;
+ const int kTabSpacing = 8;
layout = std::make_unique<BoxLayout>(
BoxLayout::kVertical, gfx::Insets(kTabStripEdgePadding, 0, 0, 0),
kTabSpacing);
diff --git a/chromium/ui/views/controls/textfield/textfield.cc b/chromium/ui/views/controls/textfield/textfield.cc
index 752c642e2da..2ff60335add 100644
--- a/chromium/ui/views/controls/textfield/textfield.cc
+++ b/chromium/ui/views/controls/textfield/textfield.cc
@@ -19,6 +19,7 @@
#include "ui/base/cursor/cursor.h"
#include "ui/base/default_style.h"
#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/ime/constants.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_edit_commands.h"
#include "ui/base/resource/resource_bundle.h"
@@ -73,6 +74,7 @@
#endif
#if defined(OS_MACOSX)
+#include "ui/base/cocoa/defaults_utils.h"
#include "ui/base/cocoa/secure_password_input.h"
#endif
@@ -149,6 +151,14 @@ ui::TextEditCommand GetCommandForKeyEvent(const ui::KeyEvent& event) {
return shift
? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
: ui::TextEditCommand::MOVE_TO_END_OF_LINE;
+ case ui::VKEY_UP:
+ return shift ? ui::TextEditCommand::
+ MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::INVALID_COMMAND;
+ case ui::VKEY_DOWN:
+ return shift
+ ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
+ : ui::TextEditCommand::INVALID_COMMAND;
case ui::VKEY_BACK:
if (!control)
return ui::TextEditCommand::DELETE_BACKWARD;
@@ -203,11 +213,14 @@ ui::TextEditCommand GetTextEditCommandFromMenuCommand(int command_id,
return ui::TextEditCommand::INVALID_COMMAND;
}
-base::TimeDelta GetPasswordRevealDuration() {
- return ViewsDelegate::GetInstance()
- ? ViewsDelegate::GetInstance()
- ->GetTextfieldPasswordRevealDuration()
- : base::TimeDelta();
+base::TimeDelta GetPasswordRevealDuration(const ui::KeyEvent& event) {
+ // The key event may carries the property that indicates it was from the
+ // virtual keyboard.
+ // In that case, reveals the password characters for 1 second.
+ auto* properties = event.properties();
+ bool from_vk =
+ properties && properties->find(ui::kPropertyFromVK) != properties->end();
+ return from_vk ? base::TimeDelta::FromSeconds(1) : base::TimeDelta();
}
bool IsControlKeyModifier(int flags) {
@@ -229,8 +242,6 @@ const char Textfield::kViewClassName[] = "Textfield";
// static
base::TimeDelta Textfield::GetCaretBlinkInterval() {
- static constexpr base::TimeDelta default_value =
- base::TimeDelta::FromMilliseconds(500);
#if defined(OS_WIN)
static const size_t system_value = ::GetCaretBlinkTime();
if (system_value != 0) {
@@ -238,8 +249,12 @@ base::TimeDelta Textfield::GetCaretBlinkInterval() {
? base::TimeDelta()
: base::TimeDelta::FromMilliseconds(system_value);
}
+#elif defined(OS_MACOSX)
+ base::TimeDelta system_value;
+ if (ui::TextInsertionCaretBlinkPeriod(&system_value))
+ return system_value;
#endif
- return default_value;
+ return base::TimeDelta::FromMilliseconds(500);
}
// static
@@ -1398,17 +1413,9 @@ bool Textfield::GetAcceleratorForCommandId(int command_id,
*accelerator = ui::Accelerator(ui::VKEY_A, ui::EF_PLATFORM_ACCELERATOR);
return true;
- case IDS_CONTENT_CONTEXT_EMOJI:
-#if defined(OS_MACOSX)
- *accelerator = ui::Accelerator(ui::VKEY_SPACE,
- ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN);
- return true;
-#else
- return false;
-#endif
-
default:
- return false;
+ return text_services_context_menu_->GetAcceleratorForCommandId(
+ command_id, accelerator);
}
}
@@ -1495,11 +1502,14 @@ void Textfield::InsertChar(const ui::KeyEvent& event) {
DoInsertChar(ch);
- if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD &&
- !GetPasswordRevealDuration().is_zero()) {
- const size_t change_offset = model_->GetCursorPosition();
- DCHECK_GT(change_offset, 0u);
- RevealPasswordChar(change_offset - 1);
+ if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD) {
+ password_char_reveal_index_ = -1;
+ base::TimeDelta duration = GetPasswordRevealDuration(event);
+ if (!duration.is_zero()) {
+ const size_t change_offset = model_->GetCursorPosition();
+ DCHECK_GT(change_offset, 0u);
+ RevealPasswordChar(change_offset - 1, duration);
+ }
}
}
@@ -2287,15 +2297,16 @@ bool Textfield::ImeEditingAllowed() const {
return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
}
-void Textfield::RevealPasswordChar(int index) {
+void Textfield::RevealPasswordChar(int index, base::TimeDelta duration) {
GetRenderText()->SetObscuredRevealIndex(index);
SchedulePaint();
+ password_char_reveal_index_ = index;
if (index != -1) {
password_reveal_timer_.Start(
- FROM_HERE, GetPasswordRevealDuration(),
+ FROM_HERE, duration,
base::Bind(&Textfield::RevealPasswordChar,
- weak_ptr_factory_.GetWeakPtr(), -1));
+ weak_ptr_factory_.GetWeakPtr(), -1, duration));
}
}
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 314bde9feff..4d20d983432 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -244,6 +244,8 @@ class VIEWS_EXPORT Textfield : public View,
// Set extra spacing placed between glyphs; used for obscured text styling.
void SetGlyphSpacing(int spacing);
+ int GetPasswordCharRevealIndex() const { return password_char_reveal_index_; }
+
// View overrides:
int GetBaseline() const override;
gfx::Size CalculatePreferredSize() const override;
@@ -470,7 +472,8 @@ class VIEWS_EXPORT Textfield : public View,
// Reveals the password character at |index| for a set duration.
// If |index| is -1, the existing revealed character will be reset.
- void RevealPasswordChar(int index);
+ // |duration| is the time to remain the password char to be visible.
+ void RevealPasswordChar(int index, base::TimeDelta duration);
void CreateTouchSelectionControllerAndNotifyIt();
@@ -628,6 +631,9 @@ class VIEWS_EXPORT Textfield : public View,
// The focus ring for this TextField.
std::unique_ptr<FocusRing> focus_ring_;
+ // The password char reveal index, for testing only.
+ int password_char_reveal_index_ = -1;
+
// Used to bind callback functions to this object.
base::WeakPtrFactory<Textfield> weak_ptr_factory_;
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index 4d77de34ffc..1bfea07108c 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard.h"
@@ -268,9 +269,9 @@ gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) {
// NSTextKillRingSize, a text system default. However to keep things simple,
// the default kill ring size of 1 (i.e. a single buffer) is assumed.
base::string16* GetKillBuffer() {
- CR_DEFINE_STATIC_LOCAL(base::string16, kill_buffer, ());
+ static base::NoDestructor<base::string16> kill_buffer;
DCHECK(base::MessageLoopForUI::IsCurrent());
- return &kill_buffer;
+ return kill_buffer.get();
}
// Helper method to set the kill buffer.
@@ -486,7 +487,7 @@ bool TextfieldModel::CanRedo() {
if (edit_history_.empty())
return false;
// There is no redo iff the current edit is the last element in the history.
- EditHistory::iterator iter = current_edit_;
+ auto iter = current_edit_;
return iter == edit_history_.end() || // at the top.
++iter != edit_history_.end();
}
@@ -760,7 +761,7 @@ void TextfieldModel::ClearRedoHistory() {
ClearEditHistory();
return;
}
- EditHistory::iterator delete_start = current_edit_;
+ auto delete_start = current_edit_;
++delete_start;
edit_history_.erase(delete_start, edit_history_.end());
}
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index f8a8292c501..be57d658a24 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/format_macros.h"
#include "base/i18n/rtl.h"
@@ -27,6 +28,7 @@
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/emoji/emoji_panel_helper.h"
+#include "ui/base/ime/constants.h"
#include "ui/base/ime/input_method_base.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/input_method_factory.h"
@@ -157,7 +159,7 @@ ui::EventDispatchDetails MockInputMethod::DispatchKeyEvent(ui::KeyEvent* key) {
// which trigger the appropriate NSResponder action messages for composition.
#if defined(OS_MACOSX)
if (key->is_char())
- return DispatchKeyEventPostIME(key);
+ return DispatchKeyEventPostIME(key, base::NullCallback());
#endif
// Checks whether the key event is from EventGenerator on Windows which will
@@ -177,9 +179,9 @@ ui::EventDispatchDetails MockInputMethod::DispatchKeyEvent(ui::KeyEvent* key) {
ui::KeyEvent mock_key(ui::ET_KEY_PRESSED,
ui::VKEY_PROCESSKEY,
key->flags());
- dispatch_details = DispatchKeyEventPostIME(&mock_key);
+ dispatch_details = DispatchKeyEventPostIME(&mock_key, base::NullCallback());
} else {
- dispatch_details = DispatchKeyEventPostIME(key);
+ dispatch_details = DispatchKeyEventPostIME(key, base::NullCallback());
}
if (key->handled() || dispatch_details.dispatcher_destroyed)
@@ -553,9 +555,13 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
SendKeyEvent(key_code, false, false);
}
- void SendKeyEvent(base::char16 ch) { SendKeyEvent(ch, ui::EF_NONE); }
+ void SendKeyEvent(base::char16 ch) { SendKeyEvent(ch, ui::EF_NONE, false); }
void SendKeyEvent(base::char16 ch, int flags) {
+ SendKeyEvent(ch, flags, false);
+ }
+
+ void SendKeyEvent(base::char16 ch, int flags, bool from_vk) {
if (ch < 0x80) {
ui::KeyboardCode code =
ch == ' ' ? ui::VKEY_SPACE :
@@ -567,6 +573,11 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
// Mac, key events don't pass through InputMethod. Hence they are
// dispatched regularly.
ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::DomCode::NONE, flags);
+ if (from_vk) {
+ ui::Event::Properties properties;
+ properties[ui::kPropertyFromVK] = std::vector<uint8_t>();
+ event.SetProperties(properties);
+ }
#if defined(OS_MACOSX)
event_generator_->Dispatch(&event);
#else
@@ -1056,27 +1067,18 @@ TEST_F(TextfieldTest, MoveUpDownAndModifySelection) {
textfield_->SetSelectionRange(gfx::Range(6));
- // Shift+[Up/Down] on Mac should execute the command
- // MOVE_[UP/DOWN]_AND_MODIFY_SELECTION. On other platforms, textfield won't
- // handle these events.
+ // Shift+[Up/Down] should select the text to the beginning and end of the
+ // line, respectively.
SendKeyEvent(ui::VKEY_UP, true /* shift */, false /* command */);
EXPECT_TRUE(textfield_->key_received());
-#if defined(OS_MACOSX)
EXPECT_TRUE(textfield_->key_handled());
EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange());
-#else
- EXPECT_FALSE(textfield_->key_handled());
-#endif
textfield_->clear();
SendKeyEvent(ui::VKEY_DOWN, true /* shift */, false /* command */);
EXPECT_TRUE(textfield_->key_received());
-#if defined(OS_MACOSX)
EXPECT_TRUE(textfield_->key_handled());
EXPECT_EQ(gfx::Range(6, 11), textfield_->GetSelectedRange());
-#else
- EXPECT_FALSE(textfield_->key_handled());
-#endif
textfield_->clear();
}
@@ -1292,8 +1294,15 @@ TEST_F(TextfieldTest, TextInputType_InsertionTest) {
EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType());
SendKeyEvent(ui::VKEY_A);
- SendKeyEvent(kHebrewLetterSamekh);
+ EXPECT_EQ(-1, textfield_->GetPasswordCharRevealIndex());
+ SendKeyEvent(kHebrewLetterSamekh, ui::EF_NONE, true /* from_vk */);
+#if !defined(OS_MACOSX)
+ // Don't verifies the password character reveal on MacOS, because on MacOS,
+ // the text insertion is not done through TextInputClient::InsertChar().
+ EXPECT_EQ(1, textfield_->GetPasswordCharRevealIndex());
+#endif
SendKeyEvent(ui::VKEY_B);
+ EXPECT_EQ(-1, textfield_->GetPasswordCharRevealIndex());
EXPECT_EQ(WideToUTF16(L"a\x05E1"
L"b"),
diff --git a/chromium/ui/views/controls/views_text_services_context_menu.h b/chromium/ui/views/controls/views_text_services_context_menu.h
index bf411354261..726f6e37146 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu.h
+++ b/chromium/ui/views/controls/views_text_services_context_menu.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/i18n/rtl.h"
+#include "ui/base/accelerators/accelerator.h"
#include "ui/views/views_export.h"
namespace ui {
@@ -20,10 +21,8 @@ class Textfield;
// This class is used to add and handle text service items in the text context
// menu.
-class ViewsTextServicesContextMenu {
+class ViewsTextServicesContextMenu : public ui::AcceleratorProvider {
public:
- virtual ~ViewsTextServicesContextMenu() {}
-
// Creates a platform-specific ViewsTextServicesContextMenu object.
static std::unique_ptr<ViewsTextServicesContextMenu> Create(
ui::SimpleMenuModel* menu,
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_base.cc b/chromium/ui/views/controls/views_text_services_context_menu_base.cc
index eae69906422..89858fbb099 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu_base.cc
+++ b/chromium/ui/views/controls/views_text_services_context_menu_base.cc
@@ -5,17 +5,28 @@
#include "ui/views/controls/views_text_services_context_menu_base.h"
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
+#include "ui/base/accelerators/accelerator.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/base/models/simple_menu_model.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/textfield/textfield.h"
namespace views {
+namespace {
+
const char kViewsTextServicesContextMenuHistogram[] =
"ViewsTextServicesContextMenu.Used";
+// Do not change the values in this enum as they are used by UMA.
+enum class Command { kEmoji = 0, kMaxValue = kEmoji };
+
+} // namespace
+
ViewsTextServicesContextMenuBase::ViewsTextServicesContextMenuBase(
ui::SimpleMenuModel* menu,
Textfield* client)
@@ -25,7 +36,7 @@ ViewsTextServicesContextMenuBase::ViewsTextServicesContextMenuBase(
// Not inserted on read-only fields or if the OS/version doesn't support it.
if (!client_->read_only() && ui::IsEmojiPanelSupported()) {
menu->InsertSeparatorAt(0, ui::NORMAL_SEPARATOR);
- menu->InsertItemWithStringIdAt(0, static_cast<int>(Command::kEmoji),
+ menu->InsertItemWithStringIdAt(0, IDS_CONTENT_CONTEXT_EMOJI,
IDS_CONTENT_CONTEXT_EMOJI);
}
}
@@ -33,7 +44,27 @@ ViewsTextServicesContextMenuBase::ViewsTextServicesContextMenuBase(
ViewsTextServicesContextMenuBase::~ViewsTextServicesContextMenuBase() {}
bool ViewsTextServicesContextMenuBase::SupportsCommand(int command_id) const {
- return command_id == static_cast<int>(Command::kEmoji);
+ return command_id == IDS_CONTENT_CONTEXT_EMOJI;
+}
+
+bool ViewsTextServicesContextMenuBase::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accelerator) const {
+ if (command_id == IDS_CONTENT_CONTEXT_EMOJI) {
+#if defined(OS_WIN)
+ *accelerator = ui::Accelerator(ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN);
+ return true;
+#elif defined(OS_MACOSX)
+ *accelerator = ui::Accelerator(ui::VKEY_SPACE,
+ ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN);
+ return true;
+#else
+ // TODO(crbug.com/887660): Add accelerator key for Chrome OS.
+ return false;
+#endif
+ }
+
+ return false;
}
bool ViewsTextServicesContextMenuBase::IsCommandIdChecked(
@@ -43,14 +74,14 @@ bool ViewsTextServicesContextMenuBase::IsCommandIdChecked(
bool ViewsTextServicesContextMenuBase::IsCommandIdEnabled(
int command_id) const {
- if (command_id == static_cast<int>(Command::kEmoji))
+ if (command_id == IDS_CONTENT_CONTEXT_EMOJI)
return true;
return false;
}
void ViewsTextServicesContextMenuBase::ExecuteCommand(int command_id) {
- if (command_id == static_cast<int>(Command::kEmoji)) {
+ if (command_id == IDS_CONTENT_CONTEXT_EMOJI) {
ui::ShowEmojiPanel();
UMA_HISTOGRAM_ENUMERATION(kViewsTextServicesContextMenuHistogram,
Command::kEmoji);
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_base.h b/chromium/ui/views/controls/views_text_services_context_menu_base.h
index 08e5a7ad0c0..bbc3e19d206 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu_base.h
+++ b/chromium/ui/views/controls/views_text_services_context_menu_base.h
@@ -21,6 +21,10 @@ class ViewsTextServicesContextMenuBase : public ViewsTextServicesContextMenu {
// Returns true if the given |command_id| is handled by the menu.
bool SupportsCommand(int command_id) const override;
+ // ui::AcceleratorProvider:
+ bool GetAcceleratorForCommandId(int command_id,
+ ui::Accelerator* accelerator) const override;
+
// Methods associated with SimpleMenuModel::Delegate.
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
@@ -30,9 +34,6 @@ class ViewsTextServicesContextMenuBase : public ViewsTextServicesContextMenu {
Textfield* client() const { return client_; }
private:
- // Do not change the values in this enum as they are used by UMA.
- enum class Command { kEmoji = 0, kMaxValue = kEmoji };
-
// The view associated with the menu. Weak. Owns |this|.
Textfield* client_ = nullptr;
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm
index ece41dd5f53..e87f913ff61 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm
@@ -5,7 +5,7 @@
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#import "base/mac/foundation_util.h"
-#import "ui/views/cocoa/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
namespace views {
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.cc b/chromium/ui/views/controls/webview/web_dialog_view.cc
index 90a9612cf61..56fc98b2840 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -116,7 +116,7 @@ bool WebDialogView::CanClose() {
if (!is_attempting_close_dialog_) {
// Fire beforeunload event when user attempts to close the dialog.
is_attempting_close_dialog_ = true;
- web_view_->web_contents()->DispatchBeforeUnload();
+ web_view_->web_contents()->DispatchBeforeUnload(false /* auto_cancel */);
}
return false;
}
@@ -140,6 +140,12 @@ base::string16 WebDialogView::GetWindowTitle() const {
return base::string16();
}
+base::string16 WebDialogView::GetAccessibleWindowTitle() const {
+ if (delegate_)
+ return delegate_->GetAccessibleDialogTitle();
+ return GetWindowTitle();
+}
+
std::string WebDialogView::GetWindowName() const {
if (delegate_)
return delegate_->GetDialogName();
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h
index 0fd7bc03288..29d18cb2e1f 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -66,6 +66,7 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
bool CanResize() const override;
ui::ModalType GetModalType() const override;
base::string16 GetWindowTitle() const override;
+ base::string16 GetAccessibleWindowTitle() const override;
std::string GetWindowName() const override;
void WindowClosing() override;
views::View* GetContentsView() override;
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index 74ddbc9b3a4..2a4cc7e8938 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -149,18 +149,6 @@ const char* WebView::GetClassName() const {
return kViewClassName;
}
-std::unique_ptr<content::WebContents> WebView::SwapWebContents(
- std::unique_ptr<content::WebContents> new_web_contents) {
- if (wc_owner_)
- wc_owner_->SetDelegate(NULL);
- std::unique_ptr<content::WebContents> old_web_contents(std::move(wc_owner_));
- wc_owner_ = std::move(new_web_contents);
- if (wc_owner_)
- wc_owner_->SetDelegate(this);
- SetWebContents(wc_owner_.get());
- return old_web_contents;
-}
-
void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
if (crashed_overlay_view_)
crashed_overlay_view_->SetBoundsRect(gfx::Rect(size()));
@@ -258,6 +246,10 @@ void WebView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
// provided via other means. Providing it here would be redundant.
// Mark the name as explicitly empty so that accessibility_checks pass.
node_data->SetNameExplicitlyEmpty();
+ if (child_ax_tree_id_ != ui::AXTreeIDUnknown()) {
+ node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+ child_ax_tree_id_);
+ }
}
gfx::NativeViewAccessible WebView::GetNativeViewAccessible() {
@@ -415,8 +407,13 @@ void WebView::UpdateCrashedOverlayView() {
}
void WebView::NotifyAccessibilityWebContentsChanged() {
- if (web_contents())
- NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
+ content::RenderFrameHost* rfh =
+ web_contents() ? web_contents()->GetMainFrame() : nullptr;
+ if (rfh)
+ child_ax_tree_id_ = rfh->GetAXTreeID();
+ else
+ child_ax_tree_id_ = ui::AXTreeIDUnknown();
+ NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
}
std::unique_ptr<content::WebContents> WebView::CreateWebContents(
diff --git a/chromium/ui/views/controls/webview/webview.h b/chromium/ui/views/controls/webview/webview.h
index 994520b83b1..2a4b4937c16 100644
--- a/chromium/ui/views/controls/webview/webview.h
+++ b/chromium/ui/views/controls/webview/webview.h
@@ -120,11 +120,6 @@ class WEBVIEW_EXPORT WebView : public View,
};
protected:
- // Swaps the owned WebContents |wc_owner_| with |new_web_contents|. Returns
- // the previously owned WebContents.
- std::unique_ptr<content::WebContents> SwapWebContents(
- std::unique_ptr<content::WebContents> new_web_contents);
-
// Called when the web contents is successfully attached.
virtual void OnWebContentsAttached() {}
// Called when letterboxing (scaling the native view to preserve aspect
@@ -211,6 +206,10 @@ class WEBVIEW_EXPORT WebView : public View,
gfx::Size min_size_;
gfx::Size max_size_;
+ // Tracks the child accessibility tree id which is associated with the
+ // WebContents's main RenderFrameHost.
+ ui::AXTreeID child_ax_tree_id_;
+
DISALLOW_COPY_AND_ASSIGN(WebView);
};
diff --git a/chromium/ui/views/corewm/tooltip_controller.cc b/chromium/ui/views/corewm/tooltip_controller.cc
index 02cd71ac0ad..77d84caccc6 100644
--- a/chromium/ui/views/corewm/tooltip_controller.cc
+++ b/chromium/ui/views/corewm/tooltip_controller.cc
@@ -95,16 +95,14 @@ aura::Window* GetTooltipTarget(const ui::MouseEvent& event,
// If |target| has capture all events go to it, even if the mouse is
// really over another window. Find the real window the mouse is over.
- gfx::Point screen_loc(event.location());
- aura::client::GetScreenPositionClient(event_target->GetRootWindow())->
- ConvertPointToScreen(event_target, &screen_loc);
+ const gfx::Point screen_loc = event.target()->GetScreenLocation(event);
display::Screen* screen = display::Screen::GetScreen();
aura::Window* target = screen->GetWindowAtScreenPoint(screen_loc);
if (!target)
return NULL;
gfx::Point target_loc(screen_loc);
- aura::client::GetScreenPositionClient(target->GetRootWindow())->
- ConvertPointFromScreen(target, &target_loc);
+ aura::client::GetScreenPositionClient(target->GetRootWindow())
+ ->ConvertPointFromScreen(target, &target_loc);
aura::Window* screen_target = target->GetEventHandlerForPoint(target_loc);
if (!IsValidTarget(event_target, screen_target))
return NULL;
diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
index 1212a6f38b1..83519930cee 100644
--- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
@@ -463,10 +463,8 @@ namespace {
// Returns the index of |window| in its parent's children.
int IndexInParent(const aura::Window* window) {
- aura::Window::Windows::const_iterator i =
- std::find(window->parent()->children().begin(),
- window->parent()->children().end(),
- window);
+ auto i = std::find(window->parent()->children().begin(),
+ window->parent()->children().end(), window);
return i == window->parent()->children().end() ? -1 :
static_cast<int>(i - window->parent()->children().begin());
}
diff --git a/chromium/ui/views/corewm/tooltip_win.cc b/chromium/ui/views/corewm/tooltip_win.cc
index 462365750fb..153d4c47484 100644
--- a/chromium/ui/views/corewm/tooltip_win.cc
+++ b/chromium/ui/views/corewm/tooltip_win.cc
@@ -4,8 +4,6 @@
#include "ui/views/corewm/tooltip_win.h"
-#include <winuser.h>
-
#include "base/debug/stack_trace.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
@@ -14,11 +12,28 @@
#include "ui/display/screen.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/platform_font_win.h"
#include "ui/views/corewm/cursor_height_provider_win.h"
namespace views {
namespace corewm {
+namespace {
+
+// Substitute GetWindowFont() from windowsx.h.
+// Do not include windowsx.h as its macros break the views jumbo build.
+HFONT GetWindowFont(HWND hwnd) {
+ return reinterpret_cast<HFONT>(::SendMessage(hwnd, WM_GETFONT, 0, 0));
+}
+
+// Substitute SetWindowFont() from windowsx.h.
+// Do not include windowsx.h as its macros break the views jumbo build.
+void SetWindowFont(HWND hwnd, HFONT hfont, BOOL fRedraw) {
+ ::SendMessage(hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(hfont), fRedraw);
+}
+
+} // namespace
+
TooltipWin::TooltipWin(HWND parent)
: parent_hwnd_(parent),
tooltip_hwnd_(NULL),
@@ -70,7 +85,7 @@ bool TooltipWin::EnsureTooltipWindow() {
return false;
}
- l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+ MaybeOverrideFont();
SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0,
reinterpret_cast<LPARAM>(&toolinfo_));
@@ -96,6 +111,33 @@ void TooltipWin::PositionTooltip() {
display.work_area()));
SetWindowPos(tooltip_hwnd_, NULL, tooltip_bounds.x(), tooltip_bounds.y(), 0,
0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
+ MaybeOverrideFont();
+}
+
+void TooltipWin::MaybeOverrideFont() {
+ gfx::PlatformFontWin::FontAdjustment font_adjustment;
+ const HFONT old_font = GetWindowFont(tooltip_hwnd_);
+
+ // Determine if we need to override the font.
+ if ((!override_font_ || override_font_->GetNativeFont() != old_font) &&
+ l10n_util::NeedOverrideDefaultUIFont(
+ &font_adjustment.font_family_override, &font_adjustment.font_scale)) {
+ // Determine if we need to regenerate the font.
+ // There are a number of situations under which Windows can replace the
+ // font in a tooltip, but we don't actually need to regenerate our override
+ // font unless the underlying text/DPI scale of the window has changed.
+ const float current_scale =
+ display::win::ScreenWin::GetScaleFactorForHWND(tooltip_hwnd_);
+ if (!override_font_ || current_scale != override_scale_) {
+ override_font_ =
+ gfx::PlatformFontWin::AdjustExistingFont(old_font, font_adjustment);
+ override_scale_ = current_scale;
+ }
+
+ // Override the font in the tooltip.
+ SetWindowFont(tooltip_hwnd_, override_font_->GetNativeFont(), FALSE);
+ }
}
int TooltipWin::GetMaxWidth(const gfx::Point& location) const {
@@ -116,12 +158,6 @@ void TooltipWin::SetText(aura::Window* window,
// See comment in header for details on why |location_| is needed.
location_ = location;
- // Without this we get a flicker of the tooltip appearing at 0x0. Not sure
- // why.
- SetWindowPos(tooltip_hwnd_, NULL, 0, 0, 0, 0,
- SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
- SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
-
base::string16 adjusted_text(tooltip_text);
base::i18n::AdjustStringForLocaleDirection(&adjusted_text);
toolinfo_.lpszText = const_cast<WCHAR*>(adjusted_text.c_str());
@@ -138,8 +174,6 @@ void TooltipWin::Show() {
SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE,
TRUE, reinterpret_cast<LPARAM>(&toolinfo_));
- SetWindowPos(tooltip_hwnd_, HWND_TOPMOST, 0, 0, 0, 0,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE);
}
void TooltipWin::Hide() {
diff --git a/chromium/ui/views/corewm/tooltip_win.h b/chromium/ui/views/corewm/tooltip_win.h
index eb9e5209de3..e656c87d3ce 100644
--- a/chromium/ui/views/corewm/tooltip_win.h
+++ b/chromium/ui/views/corewm/tooltip_win.h
@@ -5,15 +5,17 @@
#ifndef UI_VIEWS_COREWM_TOOLTIP_WIN_H_
#define UI_VIEWS_COREWM_TOOLTIP_WIN_H_
+#include <windows.h>
+#include <commctrl.h>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
+#include "ui/gfx/font.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/corewm/tooltip.h"
-#include <windows.h>
-#include <commctrl.h>
-
namespace views {
namespace corewm {
@@ -36,6 +38,9 @@ class VIEWS_EXPORT TooltipWin : public Tooltip {
// Sets the position of the tooltip.
void PositionTooltip();
+ // Might override the font size for localization (e.g. Hindi).
+ void MaybeOverrideFont();
+
// Tooltip:
int GetMaxWidth(const gfx::Point& location) const override;
void SetText(aura::Window* window,
@@ -45,6 +50,11 @@ class VIEWS_EXPORT TooltipWin : public Tooltip {
void Hide() override;
bool IsVisible() override;
+ // Font we're currently overriding our UI font with.
+ // (Lets us keep a handle around so we don't leak.)
+ // Should outlast |tooltip_hwnd_|.
+ base::Optional<gfx::Font> override_font_;
+
// The window |tooltip_hwnd_| is parented to.
HWND parent_hwnd_;
@@ -62,6 +72,10 @@ class VIEWS_EXPORT TooltipWin : public Tooltip {
// cache it.
gfx::Point location_;
+ // What the scale was the last time we overrode the font, to see if we can
+ // re-use our previous override.
+ float override_scale_ = 0.0f;
+
DISALLOW_COPY_AND_ASSIGN(TooltipWin);
};
diff --git a/chromium/ui/views/event_utils.cc b/chromium/ui/views/event_utils.cc
new file mode 100644
index 00000000000..ecec6e0220c
--- /dev/null
+++ b/chromium/ui/views/event_utils.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 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/event_utils.h"
+
+#include "base/time/time.h"
+#include "ui/events/event.h"
+#include "ui/views/metrics.h"
+
+namespace views {
+
+bool IsPossiblyUnintendedInteraction(const base::TimeTicks& initial_timestamp,
+ const ui::Event& event) {
+ return (event.IsMouseEvent() || event.IsPointerEvent() ||
+ event.IsTouchEvent()) &&
+ event.time_stamp() <
+ initial_timestamp +
+ base::TimeDelta::FromMilliseconds(GetDoubleClickInterval());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/event_utils.h b/chromium/ui/views/event_utils.h
new file mode 100644
index 00000000000..cfc553ff659
--- /dev/null
+++ b/chromium/ui/views/event_utils.h
@@ -0,0 +1,28 @@
+// Copyright (c) 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_EVENT_UTILS_H_
+#define UI_VIEWS_EVENT_UTILS_H_
+
+#include "ui/views/views_export.h"
+
+namespace base {
+class TimeTicks;
+}
+
+namespace ui {
+class Event;
+}
+
+namespace views {
+
+// Returns true if the event is a mouse, touch, or pointer event that took place
+// within the double-click time interval after the |initial_timestamp|.
+VIEWS_EXPORT bool IsPossiblyUnintendedInteraction(
+ const base::TimeTicks& initial_timestamp,
+ const ui::Event& event);
+
+} // namespace views
+
+#endif // UI_VIEWS_EVENT_UTILS_H_
diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn
index c757e20b7ff..0069d8c9c8d 100644
--- a/chromium/ui/views/examples/BUILD.gn
+++ b/chromium/ui/views/examples/BUILD.gn
@@ -9,6 +9,8 @@ jumbo_component("views_examples_lib") {
testonly = true
sources = [
+ "animated_image_view_example.cc",
+ "animated_image_view_example.h",
"box_layout_example.cc",
"box_layout_example.h",
"bubble_example.cc",
diff --git a/chromium/ui/views/examples/animated_image_view_example.cc b/chromium/ui/views/examples/animated_image_view_example.cc
new file mode 100644
index 00000000000..4e52a95aeab
--- /dev/null
+++ b/chromium/ui/views/examples/animated_image_view_example.cc
@@ -0,0 +1,143 @@
+// 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/examples/animated_image_view_example.h"
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/skottie_wrapper.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/animated_image_view.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view.h"
+
+namespace views {
+namespace examples {
+
+namespace {
+
+// This class can load a skottie(and lottie) animation file from disk and play
+// it in a view as AnimatedImageView.
+// See https://skia.org/user/modules/skottie for more info on skottie.
+class AnimationGallery : public View,
+ public TextfieldController,
+ public ButtonListener {
+ public:
+ AnimationGallery()
+ : animated_image_view_(new AnimatedImageView()),
+ image_view_container_(new views::View()),
+ size_input_(new Textfield()),
+ file_chooser_(new Textfield()),
+ file_go_button_(
+ MdTextButton::Create(this, base::ASCIIToUTF16("Render"))) {
+ AddChildView(size_input_);
+
+ image_view_container_->AddChildView(animated_image_view_);
+ image_view_container_->SetLayoutManager(std::make_unique<FillLayout>());
+ animated_image_view_->SetBorder(
+ CreateSolidSidedBorder(1, 1, 1, 1, SK_ColorBLACK));
+ AddChildView(image_view_container_);
+
+ BoxLayout* box = SetLayoutManager(
+ std::make_unique<BoxLayout>(BoxLayout::kVertical, gfx::Insets(10), 10));
+ box->SetFlexForView(image_view_container_, 1);
+
+ file_chooser_->set_placeholder_text(
+ base::ASCIIToUTF16("Enter path to lottie JSON file"));
+ View* file_container = new View();
+ BoxLayout* file_box =
+ file_container->SetLayoutManager(std::make_unique<BoxLayout>(
+ BoxLayout::kHorizontal, gfx::Insets(10), 10));
+ file_container->AddChildView(file_chooser_);
+ file_container->AddChildView(file_go_button_);
+ file_box->SetFlexForView(file_chooser_, 1);
+ AddChildView(file_container);
+
+ size_input_->set_placeholder_text(
+ base::ASCIIToUTF16("Size in dip (Empty for default)"));
+ size_input_->set_controller(this);
+ }
+
+ ~AnimationGallery() override = default;
+
+ // TextfieldController:
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override {
+ if (sender == size_input_) {
+ if (!base::StringToInt(new_contents, &size_) && (size_ > 0)) {
+ size_ = 0;
+ size_input_->SetText(base::string16());
+ }
+ Update();
+ }
+ }
+
+ // ButtonListener:
+ void ButtonPressed(Button* sender, const ui::Event& event) override {
+ DCHECK_EQ(file_go_button_, sender);
+ std::string json;
+ base::ScopedAllowBlockingForTesting allow_blocking;
+#if defined(OS_POSIX)
+ base::FilePath path(base::UTF16ToUTF8(file_chooser_->text()));
+#else
+ base::FilePath path(file_chooser_->text());
+#endif // defined(OS_POSIX)
+ base::ReadFileToString(path, &json);
+
+ auto skottie = base::MakeRefCounted<gfx::SkottieWrapper>(
+ base::RefCountedString::TakeString(&json));
+ animated_image_view_->SetAnimatedImage(
+ std::make_unique<gfx::SkiaVectorAnimation>(skottie));
+ animated_image_view_->Play();
+ Update();
+ }
+
+ private:
+ void Update() {
+ if (size_ > 24)
+ animated_image_view_->SetImageSize(gfx::Size(size_, size_));
+ else
+ animated_image_view_->ResetImageSize();
+ Layout();
+ }
+
+ AnimatedImageView* animated_image_view_;
+ View* image_view_container_;
+ Textfield* size_input_;
+ Textfield* file_chooser_;
+ Button* file_go_button_;
+
+ int size_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(AnimationGallery);
+};
+
+} // namespace
+
+AnimatedImageViewExample::AnimatedImageViewExample()
+ : ExampleBase("Animated Image View") {}
+
+AnimatedImageViewExample::~AnimatedImageViewExample() {}
+
+void AnimatedImageViewExample::CreateExampleView(View* container) {
+ container->SetLayoutManager(std::make_unique<FillLayout>());
+ container->AddChildView(new AnimationGallery());
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/animated_image_view_example.h b/chromium/ui/views/examples/animated_image_view_example.h
new file mode 100644
index 00000000000..8bf30b56a87
--- /dev/null
+++ b/chromium/ui/views/examples/animated_image_view_example.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_EXAMPLES_ANIMATED_IMAGE_VIEW_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_ANIMATED_IMAGE_VIEW_EXAMPLE_H_
+
+#include "base/macros.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views {
+namespace examples {
+
+class VIEWS_EXAMPLES_EXPORT AnimatedImageViewExample : public ExampleBase {
+ public:
+ AnimatedImageViewExample();
+ ~AnimatedImageViewExample() override;
+
+ // ExampleBase:
+ void CreateExampleView(View* container) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AnimatedImageViewExample);
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_ANIMATED_IMAGE_VIEW_EXAMPLE_H_
diff --git a/chromium/ui/views/examples/examples_main.cc b/chromium/ui/views/examples/examples_main.cc
index 4dd22a71197..f2f3a2a205b 100644
--- a/chromium/ui/views/examples/examples_main.cc
+++ b/chromium/ui/views/examples/examples_main.cc
@@ -118,9 +118,10 @@ int main(int argc, char** argv) {
display::Screen::SetScreenInstance(desktop_screen.get());
#endif
- views::examples::ShowExamplesWindow(views::examples::QUIT_ON_CLOSE);
+ base::RunLoop run_loop;
+ views::examples::ShowExamplesWindow(run_loop.QuitClosure());
- base::RunLoop().Run();
+ run_loop.Run();
ui::ResourceBundle::CleanupSharedInstance();
}
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index b903e478740..683d5d59711 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -18,6 +18,7 @@
#include "ui/views/background.h"
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/label.h"
+#include "ui/views/examples/animated_image_view_example.h"
#include "ui/views/examples/box_layout_example.h"
#include "ui/views/examples/bubble_example.h"
#include "ui/views/examples/button_example.h"
@@ -58,6 +59,7 @@ namespace {
// Creates the default set of examples.
ExampleVector CreateExamples() {
ExampleVector examples;
+ examples.push_back(std::make_unique<AnimatedImageViewExample>());
examples.push_back(std::make_unique<BoxLayoutExample>());
examples.push_back(std::make_unique<BubbleExample>());
examples.push_back(std::make_unique<ButtonExample>());
@@ -131,11 +133,11 @@ class ComboboxModelExampleList : public ui::ComboboxModel {
class ExamplesWindowContents : public WidgetDelegateView,
public ComboboxListener {
public:
- ExamplesWindowContents(Operation operation, ExampleVector examples)
+ ExamplesWindowContents(base::OnceClosure on_close, ExampleVector examples)
: combobox_(new Combobox(&combobox_model_)),
example_shown_(new View),
status_label_(new Label),
- operation_(operation) {
+ on_close_(std::move(on_close)) {
instance_ = this;
combobox_->set_listener(this);
combobox_model_.SetExamples(std::move(examples));
@@ -188,8 +190,8 @@ class ExamplesWindowContents : public WidgetDelegateView,
}
void WindowClosing() override {
instance_ = NULL;
- if (operation_ == QUIT_ON_CLOSE)
- base::RunLoop::QuitCurrentWhenIdleDeprecated();
+ if (on_close_)
+ std::move(on_close_).Run();
}
gfx::Size CalculatePreferredSize() const override {
return gfx::Size(800, 300);
@@ -212,7 +214,7 @@ class ExamplesWindowContents : public WidgetDelegateView,
Combobox* combobox_;
View* example_shown_;
Label* status_label_;
- const Operation operation_;
+ base::OnceClosure on_close_;
DISALLOW_COPY_AND_ASSIGN(ExamplesWindowContents);
};
@@ -220,7 +222,7 @@ class ExamplesWindowContents : public WidgetDelegateView,
// static
ExamplesWindowContents* ExamplesWindowContents::instance_ = NULL;
-void ShowExamplesWindow(Operation operation,
+void ShowExamplesWindow(base::OnceClosure on_close,
gfx::NativeWindow window_context,
ExampleVector extra_examples) {
if (ExamplesWindowContents::instance()) {
@@ -230,7 +232,7 @@ void ShowExamplesWindow(Operation operation,
Widget* widget = new Widget;
Widget::InitParams params;
params.delegate =
- new ExamplesWindowContents(operation, std::move(examples));
+ new ExamplesWindowContents(std::move(on_close), std::move(examples));
params.context = window_context;
widget->Init(params);
widget->Show();
diff --git a/chromium/ui/views/examples/examples_window.h b/chromium/ui/views/examples/examples_window.h
index 804252fcc9b..d543c01c3f6 100644
--- a/chromium/ui/views/examples/examples_window.h
+++ b/chromium/ui/views/examples/examples_window.h
@@ -15,16 +15,11 @@
namespace views {
namespace examples {
-enum Operation {
- DO_NOTHING_ON_CLOSE = 0,
- QUIT_ON_CLOSE,
-};
-
// Shows a window with the views examples in it. |extra_examples| contains any
// additional examples to add. |window_context| is used to determine where the
// window should be created (see |Widget::InitParams::context| for details).
VIEWS_EXAMPLES_EXPORT void ShowExamplesWindow(
- Operation operation,
+ base::OnceClosure on_close,
gfx::NativeWindow window_context = nullptr,
std::vector<std::unique_ptr<ExampleBase>> extra_examples =
std::vector<std::unique_ptr<ExampleBase>>());
diff --git a/chromium/ui/views/examples/examples_window_with_content.cc b/chromium/ui/views/examples/examples_window_with_content.cc
index 1133e88fa9a..c9391fa8bd8 100644
--- a/chromium/ui/views/examples/examples_window_with_content.cc
+++ b/chromium/ui/views/examples/examples_window_with_content.cc
@@ -14,12 +14,13 @@
namespace views {
namespace examples {
-void ShowExamplesWindowWithContent(Operation operation,
+void ShowExamplesWindowWithContent(base::OnceClosure on_close,
content::BrowserContext* browser_context,
gfx::NativeWindow window_context) {
std::vector<std::unique_ptr<ExampleBase>> extra_examples;
extra_examples.push_back(std::make_unique<WebViewExample>(browser_context));
- ShowExamplesWindow(operation, window_context, std::move(extra_examples));
+ ShowExamplesWindow(std::move(on_close), window_context,
+ std::move(extra_examples));
}
} // namespace examples
diff --git a/chromium/ui/views/examples/examples_window_with_content.h b/chromium/ui/views/examples/examples_window_with_content.h
index 945201bdf7c..dbcb1fbd806 100644
--- a/chromium/ui/views/examples/examples_window_with_content.h
+++ b/chromium/ui/views/examples/examples_window_with_content.h
@@ -18,7 +18,7 @@ namespace examples {
// Shows a window with the views examples in it.
VIEWS_EXAMPLES_WITH_CONTENT_EXPORT void ShowExamplesWindowWithContent(
- Operation operation,
+ base::OnceClosure on_close,
content::BrowserContext* browser_context,
gfx::NativeWindow window_context);
diff --git a/chromium/ui/views/examples/examples_with_content_main_exe.cc b/chromium/ui/views/examples/examples_with_content_main_exe.cc
index ffbad7ff3e7..3506d740035 100644
--- a/chromium/ui/views/examples/examples_with_content_main_exe.cc
+++ b/chromium/ui/views/examples/examples_with_content_main_exe.cc
@@ -15,11 +15,12 @@
namespace {
-void ShowContentExampleWindow(content::BrowserContext* browser_context,
+void ShowContentExampleWindow(ui::ViewsContentClient* views_content_client,
+ content::BrowserContext* browser_context,
gfx::NativeWindow window_context) {
- views::examples::ShowExamplesWindowWithContent(views::examples::QUIT_ON_CLOSE,
- browser_context,
- window_context);
+ views::examples::ShowExamplesWindowWithContent(
+ std::move(views_content_client->quit_closure()), browser_context,
+ window_context);
// These lines serve no purpose other than to introduce an explicit content
// dependency. If the main executable doesn't have this dependency, the linker
@@ -45,6 +46,7 @@ int main(int argc, const char** argv) {
ui::ViewsContentClient views_content_client(argc, argv);
#endif
- views_content_client.set_task(base::Bind(&ShowContentExampleWindow));
+ views_content_client.set_task(base::Bind(
+ &ShowContentExampleWindow, base::Unretained(&views_content_client)));
return views_content_client.RunMain();
}
diff --git a/chromium/ui/views/examples/menu_example.cc b/chromium/ui/views/examples/menu_example.cc
index 2e9081c9893..3c2713a432c 100644
--- a/chromium/ui/views/examples/menu_example.cc
+++ b/chromium/ui/views/examples/menu_example.cc
@@ -155,7 +155,7 @@ void ExampleMenuModel::ExecuteCommand(int command_id, int event_flags) {
checked_fruit = "Kiwi";
// Update the check status.
- std::set<int>::iterator iter = checked_fruits_.find(command_id);
+ auto iter = checked_fruits_.find(command_id);
if (iter == checked_fruits_.end()) {
DVLOG(1) << "Checked " << checked_fruit;
checked_fruits_.insert(command_id);
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index ed29e91704b..10da1cd7fb3 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -130,12 +130,6 @@ TEST_F(FocusManagerTest, FocusChangeListener) {
}
TEST_F(FocusManagerTest, WidgetFocusChangeListener) {
- // TODO: this test ends up calling focus on the aura::Window associated with
- // the Widget and expecting that to change activation. This should work for
- // aura-mus-client as well. http://crbug.com/664261.
- if (IsMus())
- return;
-
// First, ensure the simulator is aware of the Widget created in SetUp() being
// currently active.
test::WidgetTest::SimulateNativeActivate(GetWidget());
diff --git a/chromium/ui/views/focus/widget_focus_manager.cc b/chromium/ui/views/focus/widget_focus_manager.cc
index 099b286e94c..79517fbd4bd 100644
--- a/chromium/ui/views/focus/widget_focus_manager.cc
+++ b/chromium/ui/views/focus/widget_focus_manager.cc
@@ -4,17 +4,63 @@
#include "ui/views/focus/widget_focus_manager.h"
-#include "base/memory/singleton.h"
+#include "base/supports_user_data.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#endif
namespace views {
+#if defined(USE_AURA)
+namespace {
+
+const char kWidgetFocusManagerKey[] = "WidgetFocusManager";
+
+} // namespace
+
+class WidgetFocusManager::Owner : public base::SupportsUserData::Data {
+ public:
+ explicit Owner(std::unique_ptr<WidgetFocusManager> focus_manager)
+ : focus_manager_(std::move(focus_manager)) {}
+ ~Owner() override = default;
+
+ WidgetFocusManager* focus_manager() { return focus_manager_.get(); }
+
+ private:
+ std::unique_ptr<WidgetFocusManager> focus_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(Owner);
+};
+
+#endif
+
// WidgetFocusManager ----------------------------------------------------------
// static
-WidgetFocusManager* WidgetFocusManager::GetInstance() {
- return base::Singleton<WidgetFocusManager>::get();
+WidgetFocusManager* WidgetFocusManager::GetInstance(gfx::NativeWindow context) {
+#if defined(USE_AURA)
+ // With aura there may be multiple Envs, in such a situation the
+ // WidgetFocusManager needs to be per Env.
+ aura::Env* env = context ? context->env() : aura::Env::GetInstance();
+ DCHECK(env);
+ Owner* owner = static_cast<Owner*>(env->GetUserData(kWidgetFocusManagerKey));
+ if (!owner) {
+ std::unique_ptr<Owner> owner_ptr =
+ std::make_unique<Owner>(base::WrapUnique(new WidgetFocusManager()));
+ owner = owner_ptr.get();
+ env->SetUserData(kWidgetFocusManagerKey, std::move(owner_ptr));
+ }
+ return owner->focus_manager();
+#else
+ static base::NoDestructor<WidgetFocusManager> instance;
+ return instance.get();
+#endif
}
+WidgetFocusManager::~WidgetFocusManager() = default;
+
void WidgetFocusManager::AddFocusChangeListener(
WidgetFocusChangeListener* listener) {
focus_change_listeners_.AddObserver(listener);
@@ -34,8 +80,6 @@ void WidgetFocusManager::OnNativeFocusChanged(gfx::NativeView focused_now) {
WidgetFocusManager::WidgetFocusManager() : enabled_(true) {}
-WidgetFocusManager::~WidgetFocusManager() {}
-
// AutoNativeNotificationDisabler ----------------------------------------------
AutoNativeNotificationDisabler::AutoNativeNotificationDisabler() {
diff --git a/chromium/ui/views/focus/widget_focus_manager.h b/chromium/ui/views/focus/widget_focus_manager.h
index 068a4825b46..eb29250c7e6 100644
--- a/chromium/ui/views/focus/widget_focus_manager.h
+++ b/chromium/ui/views/focus/widget_focus_manager.h
@@ -6,14 +6,11 @@
#define UI_VIEWS_FOCUS_WIDGET_FOCUS_MANAGER_H_
#include "base/macros.h"
+#include "base/no_destructor.h"
#include "base/observer_list.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
-namespace base {
-template <typename T> struct DefaultSingletonTraits;
-}
-
namespace views {
// This interface should be implemented by classes that want to be notified when
@@ -32,7 +29,9 @@ class WidgetFocusChangeListener {
class VIEWS_EXPORT WidgetFocusManager {
public:
// Returns the singleton instance.
- static WidgetFocusManager* GetInstance();
+ static WidgetFocusManager* GetInstance(gfx::NativeWindow context = nullptr);
+
+ ~WidgetFocusManager();
// Adds/removes a WidgetFocusChangeListener |listener| to the set of
// active listeners.
@@ -50,10 +49,10 @@ class VIEWS_EXPORT WidgetFocusManager {
void DisableNotifications() { enabled_ = false; }
private:
- friend struct base::DefaultSingletonTraits<WidgetFocusManager>;
+ class Owner;
+ friend class base::NoDestructor<WidgetFocusManager>;
WidgetFocusManager();
- ~WidgetFocusManager();
base::ObserverList<WidgetFocusChangeListener>::Unchecked
focus_change_listeners_;
diff --git a/chromium/ui/views/layout/box_layout.cc b/chromium/ui/views/layout/box_layout.cc
index f9c1b6dc485..cdc9750f08b 100644
--- a/chromium/ui/views/layout/box_layout.cc
+++ b/chromium/ui/views/layout/box_layout.cc
@@ -363,7 +363,7 @@ void BoxLayout::ViewRemoved(View* host, View* view) {
}
int BoxLayout::GetFlexForView(const View* view) const {
- FlexMap::const_iterator it = flex_map_.find(view);
+ auto it = flex_map_.find(view);
if (it == flex_map_.end())
return default_flex_;
@@ -371,7 +371,7 @@ int BoxLayout::GetFlexForView(const View* view) const {
}
int BoxLayout::GetMinimumSizeForView(const View* view) const {
- FlexMap::const_iterator it = flex_map_.find(view);
+ auto it = flex_map_.find(view);
if (it == flex_map_.end() || !it->second.use_min_size)
return 0;
diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h
index 86a3c0a78cb..759d4ab03f0 100644
--- a/chromium/ui/views/linux_ui/linux_ui.h
+++ b/chromium/ui/views/linux_ui/linux_ui.h
@@ -101,12 +101,10 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
virtual bool GetColor(int id,
SkColor* color,
PrefService* pref_service) const = 0;
+ virtual bool GetDisplayProperty(int id, int* result) const = 0;
// Returns the preferences that we pass to WebKit.
virtual SkColor GetFocusRingColor() const = 0;
- virtual SkColor GetThumbActiveColor() const = 0;
- virtual SkColor GetThumbInactiveColor() const = 0;
- virtual SkColor GetTrackColor() const = 0;
virtual SkColor GetActiveSelectionBgColor() const = 0;
virtual SkColor GetActiveSelectionFgColor() const = 0;
virtual SkColor GetInactiveSelectionBgColor() const = 0;
diff --git a/chromium/ui/views/mus/ax_remote_host.cc b/chromium/ui/views/mus/ax_remote_host.cc
index 0affab635ac..01511da2296 100644
--- a/chromium/ui/views/mus/ax_remote_host.cc
+++ b/chromium/ui/views/mus/ax_remote_host.cc
@@ -6,10 +6,12 @@
#include <stddef.h>
+#include "base/no_destructor.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_event.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/window.h"
@@ -27,9 +29,6 @@ using display::Screen;
namespace views {
-// For external linkage.
-constexpr int AXRemoteHost::kRemoteAXTreeID;
-
AXRemoteHost::AXRemoteHost() {
AXAuraObjCache::GetInstance()->SetDelegate(this);
}
@@ -42,12 +41,12 @@ AXRemoteHost::~AXRemoteHost() {
void AXRemoteHost::Init(service_manager::Connector* connector) {
connector->BindInterface(ax::mojom::kAXHostServiceName, &ax_host_ptr_);
- BindAndSetRemote();
+ BindAndRegisterRemote();
}
void AXRemoteHost::InitForTesting(ax::mojom::AXHostPtr host_ptr) {
ax_host_ptr_ = std::move(host_ptr);
- BindAndSetRemote();
+ BindAndRegisterRemote();
}
void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
@@ -62,6 +61,10 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
widget_ = widget;
widget_->AddObserver(this);
+ DCHECK_NE(tree_id_, ui::AXTreeIDUnknown());
+ widget_->GetNativeWindow()->SetProperty(ui::kChildAXTreeID,
+ new std::string(tree_id_.ToString()));
+
// The cache needs to track the root window to follow focus changes.
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
cache->OnRootWindowObjCreated(widget_->GetNativeWindow());
@@ -71,7 +74,7 @@ void AXRemoteHost::StartMonitoringWidget(Widget* widget) {
View* contents_view = widget_->widget_delegate()->GetContentsView();
AXAuraObjWrapper* contents_wrapper = cache->GetOrCreate(contents_view);
- tree_source_ = std::make_unique<AXTreeSourceMus>(contents_wrapper);
+ tree_source_ = std::make_unique<AXTreeSourceMus>(contents_wrapper, tree_id_);
tree_serializer_ = std::make_unique<AuraAXTreeSerializer>(tree_source_.get());
// Inform the serializer of the display device scale factor.
@@ -99,9 +102,15 @@ void AXRemoteHost::HandleEvent(View* view, ax::mojom::Event event_type) {
if (!enabled_)
return;
- AXAuraObjWrapper* aura_obj =
- view ? AXAuraObjCache::GetInstance()->GetOrCreate(view)
- : tree_source_->GetRoot();
+ if (!view) {
+ SendEvent(tree_source_->GetRoot(), event_type);
+ return;
+ }
+
+ // Can return null for views without a widget.
+ AXAuraObjWrapper* aura_obj = AXAuraObjCache::GetInstance()->GetOrCreate(view);
+ if (!aura_obj)
+ return;
SendEvent(aura_obj, event_type);
}
@@ -168,15 +177,26 @@ void AXRemoteHost::FlushForTesting() {
ax_host_ptr_.FlushForTesting();
}
-void AXRemoteHost::BindAndSetRemote() {
+void AXRemoteHost::BindAndRegisterRemote() {
ax::mojom::AXRemoteHostPtr remote;
binding_.Bind(mojo::MakeRequest(&remote));
- ax_host_ptr_->SetRemoteHost(std::move(remote));
+ ax_host_ptr_->RegisterRemoteHost(
+ std::move(remote),
+ base::BindOnce(&AXRemoteHost::RegisterRemoteHostCallback,
+ base::Unretained(this)));
+}
+
+void AXRemoteHost::RegisterRemoteHostCallback(const ui::AXTreeID& tree_id,
+ bool enabled) {
+ tree_id_ = tree_id;
+
+ // Set the initial enabled state and send the AX tree if necessary.
+ OnAutomationEnabled(enabled);
}
void AXRemoteHost::Enable() {
// 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.
+ // "enabled" state even if ChromeVox is off 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
@@ -234,7 +254,7 @@ void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
event.event_type = event_type;
// Other fields are not used.
- ax_host_ptr_->HandleAccessibilityEvent(kRemoteAXTreeID, updates, event);
+ ax_host_ptr_->HandleAccessibilityEvent(tree_id_, updates, event);
}
void AXRemoteHost::PerformHitTest(const ui::AXActionData& action) {
diff --git a/chromium/ui/views/mus/ax_remote_host.h b/chromium/ui/views/mus/ax_remote_host.h
index 7e506159487..bb432ba5073 100644
--- a/chromium/ui/views/mus/ax_remote_host.h
+++ b/chromium/ui/views/mus/ax_remote_host.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/mojom/ax_host.mojom.h"
#include "ui/display/display_observer.h"
@@ -41,10 +42,6 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
public display::DisplayObserver,
public AXAuraObjCache::Delegate {
public:
- // Well-known tree ID for the remote client.
- // TODO(jamescook): Support different IDs for different clients.
- static constexpr int kRemoteAXTreeID = -2;
-
AXRemoteHost();
~AXRemoteHost() override;
@@ -84,7 +81,10 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
private:
// Registers this object as a remote host for the parent AXHost.
- void BindAndSetRemote();
+ void BindAndRegisterRemote();
+
+ // Callback for initial state from AXHost.
+ void RegisterRemoteHostCallback(const ui::AXTreeID& tree_id, bool enabled);
void Enable();
void Disable();
@@ -102,6 +102,9 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
mojo::Binding<ax::mojom::AXRemoteHost> binding_{this};
+ // ID to use for the AX tree.
+ ui::AXTreeID tree_id_;
+
// Whether accessibility automation support is enabled.
bool enabled_ = false;
diff --git a/chromium/ui/views/mus/ax_remote_host_unittest.cc b/chromium/ui/views/mus/ax_remote_host_unittest.cc
index fd187350140..d6620cf9b2a 100644
--- a/chromium/ui/views/mus/ax_remote_host_unittest.cc
+++ b/chromium/ui/views/mus/ax_remote_host_unittest.cc
@@ -5,9 +5,11 @@
#include "ui/views/mus/ax_remote_host.h"
#include "base/macros.h"
+#include "base/no_destructor.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/mojom/ax_host.mojom.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/transform.h"
@@ -21,6 +23,13 @@
namespace views {
namespace {
+// Returns a well-known tree ID for the test widget.
+const ui::AXTreeID& TestAXTreeID() {
+ static const base::NoDestructor<ui::AXTreeID> test_ax_tree_id(
+ ui::AXTreeID::FromString("123"));
+ return *test_ax_tree_id;
+}
+
// Simulates the AXHostService in the browser.
class TestAXHostService : public ax::mojom::AXHost {
public:
@@ -35,33 +44,34 @@ class TestAXHostService : public ax::mojom::AXHost {
}
void ResetCounts() {
- add_client_count_ = 0;
+ remote_host_count_ = 0;
event_count_ = 0;
- last_tree_id_ = 0;
+ last_tree_id_ = ui::AXTreeIDUnknown();
last_updates_.clear();
last_event_ = ui::AXEvent();
}
// ax::mojom::AXHost:
- void SetRemoteHost(ax::mojom::AXRemoteHostPtr client) override {
- ++add_client_count_;
- client->OnAutomationEnabled(automation_enabled_);
+ void RegisterRemoteHost(ax::mojom::AXRemoteHostPtr client,
+ RegisterRemoteHostCallback cb) override {
+ ++remote_host_count_;
+ std::move(cb).Run(TestAXTreeID(), automation_enabled_);
client.FlushForTesting();
}
- void HandleAccessibilityEvent(int32_t tree_id,
+ void HandleAccessibilityEvent(const ui::AXTreeID& tree_id,
const std::vector<ui::AXTreeUpdate>& updates,
const ui::AXEvent& event) override {
++event_count_;
- last_tree_id_ = tree_id;
+ last_tree_id_ = ui::AXTreeID::FromString(tree_id);
last_updates_ = updates;
last_event_ = event;
}
mojo::Binding<ax::mojom::AXHost> binding_{this};
bool automation_enabled_ = false;
- int add_client_count_ = 0;
+ int remote_host_count_ = 0;
int event_count_ = 0;
- int last_tree_id_ = 0;
+ ui::AXTreeID last_tree_id_ = ui::AXTreeIDUnknown();
std::vector<ui::AXTreeUpdate> last_updates_;
ui::AXEvent last_event_;
@@ -127,7 +137,7 @@ TEST_F(AXRemoteHostTest, CreateRemote) {
CreateRemote(&service);
// Client registered itself with service.
- EXPECT_EQ(1, service.add_client_count_);
+ EXPECT_EQ(1, service.remote_host_count_);
}
TEST_F(AXRemoteHostTest, AutomationEnabled) {
@@ -136,7 +146,15 @@ TEST_F(AXRemoteHostTest, AutomationEnabled) {
std::unique_ptr<Widget> widget = CreateTestWidget();
remote->FlushForTesting();
+ // Tree ID is assigned.
+ std::string* tree_id_ptr =
+ widget->GetNativeWindow()->GetProperty(ui::kChildAXTreeID);
+ ASSERT_TRUE(tree_id_ptr);
+ ui::AXTreeID tree_id = ui::AXTreeID::FromString(*tree_id_ptr);
+ EXPECT_EQ(TestAXTreeID(), tree_id);
+
// Event was sent with initial hierarchy.
+ EXPECT_EQ(TestAXTreeID(), service.last_tree_id_);
EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type);
EXPECT_EQ(AXAuraObjCache::GetInstance()->GetID(
widget->widget_delegate()->GetContentsView()),
@@ -165,13 +183,15 @@ TEST_F(AXRemoteHostTest, AutomationEnabledTwice) {
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.
-// https://crbug.com/862759
-TEST_F(AXRemoteHostTest, SendEventBeforeWidgetCreated) {
+// Verifies that a remote app doesn't crash if a View triggers an accessibility
+// event before it is attached to a Widget. https://crbug.com/889121
+TEST_F(AXRemoteHostTest, SendEventOnViewWithNoWidget) {
TestAXHostService service(true /*automation_enabled*/);
AXRemoteHost* remote = CreateRemote(&service);
+ std::unique_ptr<Widget> widget = CreateTestWidget();
+ remote->FlushForTesting();
+
+ // Create a view that is not yet associated with the widget.
views::View view;
remote->HandleEvent(&view, ax::mojom::Event::kLocationChanged);
// No crash.
@@ -230,6 +250,9 @@ TEST_F(AXRemoteHostTest, PerformAction) {
// 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);
AXAuraObjCache::GetInstance()->GetOrCreate(&view);
// Request an action on the view.
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.cc b/chromium/ui/views/mus/ax_tree_source_mus.cc
index 7f767c443f6..6199fb3cabf 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus.cc
@@ -11,14 +11,17 @@
namespace views {
-AXTreeSourceMus::AXTreeSourceMus(AXAuraObjWrapper* root) : root_(root) {
+AXTreeSourceMus::AXTreeSourceMus(AXAuraObjWrapper* root,
+ const ui::AXTreeID& tree_id)
+ : root_(root), tree_id_(tree_id) {
DCHECK(root_);
+ DCHECK_NE(tree_id_, ui::AXTreeIDUnknown());
}
AXTreeSourceMus::~AXTreeSourceMus() = default;
bool AXTreeSourceMus::GetTreeData(ui::AXTreeData* tree_data) const {
- tree_data->tree_id = AXRemoteHost::kRemoteAXTreeID;
+ tree_data->tree_id = tree_id_;
return AXTreeSourceViews::GetTreeData(tree_data);
}
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.h b/chromium/ui/views/mus/ax_tree_source_mus.h
index 6e3681e0773..6c9170747ed 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.h
+++ b/chromium/ui/views/mus/ax_tree_source_mus.h
@@ -6,6 +6,7 @@
#define UI_VIEWS_MUS_AX_TREE_SOURCE_MUS_H_
#include "base/macros.h"
+#include "ui/accessibility/ax_tree_id.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
#include "ui/views/mus/mus_export.h"
@@ -20,7 +21,7 @@ class AXAuraObjWrapper;
class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
public:
// |root| must outlive this object.
- explicit AXTreeSourceMus(AXAuraObjWrapper* root);
+ AXTreeSourceMus(AXAuraObjWrapper* root, const ui::AXTreeID& tree_id);
~AXTreeSourceMus() override;
void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
@@ -35,6 +36,9 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
// The top-level object to use for the AX tree.
AXAuraObjWrapper* root_;
+ // ID to use for the AX tree.
+ const ui::AXTreeID tree_id_;
+
// The display device scale factor to use while serializing this update.
float device_scale_factor_ = 1.f;
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 2f7bc9a6299..b4fbdd54ac4 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
@@ -51,6 +51,7 @@ class AXTreeSourceMusTest : public ViewsTestBase {
std::unique_ptr<Widget> widget_;
Label* label_ = nullptr; // Owned by views hierarchy.
+ const ui::AXTreeID ax_tree_id_ = ui::AXTreeID::FromString("123");
private:
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceMusTest);
@@ -59,17 +60,17 @@ class AXTreeSourceMusTest : public ViewsTestBase {
TEST_F(AXTreeSourceMusTest, GetTreeData) {
AXAuraObjWrapper* root =
AXAuraObjCache::GetInstance()->GetOrCreate(widget_->GetContentsView());
- AXTreeSourceMus tree(root);
+ AXTreeSourceMus tree(root, ax_tree_id_);
ui::AXTreeData tree_data;
tree.GetTreeData(&tree_data);
- EXPECT_EQ(AXRemoteHost::kRemoteAXTreeID, tree_data.tree_id);
+ EXPECT_EQ(ax_tree_id_, tree_data.tree_id);
}
TEST_F(AXTreeSourceMusTest, Serialize) {
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
- AXTreeSourceMus tree(root);
+ AXTreeSourceMus tree(root, ax_tree_id_);
EXPECT_EQ(root, tree.GetRoot());
// Serialize the root.
@@ -93,7 +94,7 @@ TEST_F(AXTreeSourceMusTest, ScaleFactor) {
AXAuraObjWrapper* root = cache->GetOrCreate(widget_->GetContentsView());
// Simulate serializing a widget on a high-dpi display.
- AXTreeSourceMus tree(root);
+ AXTreeSourceMus tree(root, ax_tree_id_);
tree.set_device_scale_factor(2.f);
// Serialize the root.
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 93d30122d2a..61fd282fbb4 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -43,7 +43,7 @@ namespace views {
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.
+// very little but honor kTopViewInset.
class ClientSideNonClientFrameView : public NonClientFrameView,
public aura::WindowObserver {
public:
@@ -53,16 +53,22 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
// provided by the window manager.
GetViewAccessibility().set_is_ignored(true);
- observed_.Add(widget_->GetNativeWindow()->GetRootWindow());
+ // Initialize kTopViewInset to a default value. Further updates will come
+ // from Ash. This is necessary so that during app window creation,
+ // GetWindowBoundsForClientBounds() can calculate correctly.
+ const auto& values = views::WindowManagerFrameValues::instance();
+ widget->GetNativeWindow()->SetProperty(aura::client::kTopViewInset,
+ widget->IsMaximized()
+ ? values.maximized_insets.top()
+ : values.normal_insets.top());
+ observed_.Add(window());
}
~ClientSideNonClientFrameView() override {}
private:
- // Returns the default values of client area insets from the window manager.
- static gfx::Insets GetDefaultWindowManagerInsets(bool is_maximized) {
- const WindowManagerFrameValues& values =
- WindowManagerFrameValues::instance();
- return is_maximized ? values.maximized_insets : values.normal_insets;
+ gfx::Insets GetClientInsets() const {
+ const int top_inset = window()->GetProperty(aura::client::kTopViewInset);
+ return gfx::Insets(top_inset, 0, 0, 0);
}
// View:
@@ -75,7 +81,7 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
gfx::Rect result(GetLocalBounds());
if (widget_->IsFullscreen())
return result;
- result.Inset(GetDefaultWindowManagerInsets(widget_->IsMaximized()));
+ result.Inset(GetClientInsets());
return result;
}
gfx::Rect GetWindowBoundsForClientBounds(
@@ -83,12 +89,9 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
if (widget_->IsFullscreen())
return client_bounds;
- const gfx::Insets insets(
- GetDefaultWindowManagerInsets(widget_->IsMaximized()));
- return gfx::Rect(client_bounds.x() - insets.left(),
- client_bounds.y() - insets.top(),
- client_bounds.width() + insets.width(),
- client_bounds.height() + insets.height());
+ gfx::Rect outset_bounds = client_bounds;
+ outset_bounds.Inset(-GetClientInsets());
+ return outset_bounds;
}
int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {
@@ -136,20 +139,16 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
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();
- }
+ if (key == aura::client::kTopViewInset) {
+ InvalidateLayout();
+ widget_->GetRootView()->Layout();
}
}
+ aura::Window* window() const {
+ return widget_->GetNativeWindow()->GetRootWindow();
+ }
+
views::Widget* widget_;
ScopedObserver<aura::Window, aura::WindowObserver> observed_{this};
@@ -286,20 +285,6 @@ void DesktopWindowTreeHostMus::SendClientAreaToServer() {
std::vector<gfx::Rect>());
}
-void DesktopWindowTreeHostMus::SendHitTestMaskToServer() {
- if (!native_widget_delegate_->HasHitTestMask()) {
- aura::WindowPortMus::Get(window())->SetHitTestMask(base::nullopt);
- return;
- }
-
- gfx::Path mask_path;
- native_widget_delegate_->GetHitTestMask(&mask_path);
- // TODO(jamescook): Use the full path for the mask.
- gfx::Rect mask_rect =
- gfx::ToEnclosingRect(gfx::SkRectToRectF(mask_path.getBounds()));
- aura::WindowPortMus::Get(window())->SetHitTestMask(mask_rect);
-}
-
bool DesktopWindowTreeHostMus::IsFocusClientInstalledOnFocusSynchronizer()
const {
return MusClient::Get()
@@ -340,8 +325,11 @@ void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
window()->SetProperty(aura::client::kShowStateKey, params.show_state);
- if (!params.bounds.IsEmpty())
+ if (!params.bounds.IsEmpty()) {
+ // Init the scale now (before InitHost below), it is used by SetBoundsInDIP.
+ IntializeDeviceScaleFactor(GetDisplay().device_scale_factor());
SetBoundsInDIP(params.bounds);
+ }
cursor_manager_ = std::make_unique<wm::CursorManager>(
std::make_unique<NativeCursorManagerMus>(window()));
@@ -428,7 +416,6 @@ void DesktopWindowTreeHostMus::OnWidgetInitDone() {
// the NonClientView was created, which means we may not have sent the
// client-area and hit-test-mask.
SendClientAreaToServer();
- SendHitTestMaskToServer();
MusClient::Get()->OnCaptureClientSet(
aura::client::GetCaptureClient(window()));
@@ -871,7 +858,6 @@ void DesktopWindowTreeHostMus::OnWindowManagerFrameValuesChanged() {
}
SendClientAreaToServer();
- SendHitTestMaskToServer();
}
void DesktopWindowTreeHostMus::OnActiveFocusClientChanged(
@@ -946,7 +932,6 @@ void DesktopWindowTreeHostMus::OnViewBoundsChanged(views::View* observed_view) {
native_widget_delegate_->AsWidget()->non_client_view()->frame_view());
SendClientAreaToServer();
- SendHitTestMaskToServer();
}
void DesktopWindowTreeHostMus::OnViewIsDeleting(View* observed_view) {
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 a93e0c297ed..17c0655e987 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.h
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
@@ -49,7 +49,6 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
private:
void SendClientAreaToServer();
- void SendHitTestMaskToServer();
// Returns true if the FocusClient associated with our window is installed on
// the FocusSynchronizer.
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 85bfbad2488..159770b5a1c 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
@@ -24,7 +24,6 @@
#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"
@@ -240,42 +239,24 @@ 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);
-
+// Tests that changes to kTopViewInset will cause the client area to be updated.
+TEST_F(DesktopWindowTreeHostMusTest, ServerTopInsetChangeUpdatesClientArea) {
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());
+ auto set_top_inset = [&widget](int value) {
+ widget->GetNativeWindow()->GetRootWindow()->SetProperty(
+ aura::client::kTopViewInset, value);
+ };
+
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());
+ set_top_inset(3);
+ gfx::Rect root_bounds = widget->GetRootView()->bounds();
+ root_bounds.Inset(gfx::Insets(3, 0, 0, 0));
+
+ set_top_inset(0);
+ EXPECT_EQ(widget->GetRootView()->bounds(), widget->client_view()->bounds());
}
TEST_F(DesktopWindowTreeHostMusTest, CursorClientDuringTearDown) {
diff --git a/chromium/ui/views/mus/drag_interactive_uitest.cc b/chromium/ui/views/mus/drag_interactive_uitest.cc
index 999ec9e269a..92dc07d7a7d 100644
--- a/chromium/ui/views/mus/drag_interactive_uitest.cc
+++ b/chromium/ui/views/mus/drag_interactive_uitest.cc
@@ -86,24 +86,24 @@ class TargetView : public views::View {
DISALLOW_COPY_AND_ASSIGN(TargetView);
};
-std::unique_ptr<ui::PointerEvent> CreateMouseMoveEvent(int x, int y) {
- return std::make_unique<ui::PointerEvent>(ui::MouseEvent(
+std::unique_ptr<ui::MouseEvent> CreateMouseMoveEvent(int x, int y) {
+ return std::make_unique<ui::MouseEvent>(
ui::ET_MOUSE_MOVED, gfx::Point(x, y), gfx::Point(x, y),
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_NONE));
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_NONE);
}
-std::unique_ptr<ui::PointerEvent> CreateMouseDownEvent(int x, int y) {
- return std::make_unique<ui::PointerEvent>(
- ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(x, y), gfx::Point(x, y),
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON));
+std::unique_ptr<ui::MouseEvent> CreateMouseDownEvent(int x, int y) {
+ return std::make_unique<ui::MouseEvent>(
+ ui::ET_MOUSE_PRESSED, gfx::Point(x, y), gfx::Point(x, y),
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
}
-std::unique_ptr<ui::PointerEvent> CreateMouseUpEvent(int x, int y) {
- return std::make_unique<ui::PointerEvent>(
- ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(x, y), gfx::Point(x, y),
- ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
- ui::EF_LEFT_MOUSE_BUTTON));
+std::unique_ptr<ui::MouseEvent> CreateMouseUpEvent(int x, int y) {
+ return std::make_unique<ui::MouseEvent>(
+ ui::ET_MOUSE_RELEASED, gfx::Point(x, y), gfx::Point(x, y),
+ ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
}
} // namespace
diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc
index 4678479162a..4bed24086c3 100644
--- a/chromium/ui/views/mus/mus_client.cc
+++ b/chromium/ui/views/mus/mus_client.cc
@@ -270,7 +270,7 @@ MusClient::ConfigurePropertiesFromParams(
// TODO(crbug.com/667566): Support additional scales or gfx::Image[Skia].
gfx::ImageSkia app_icon = init_params.delegate->GetWindowAppIcon();
- SkBitmap app_bitmap = app_icon.GetRepresentation(1.f).sk_bitmap();
+ SkBitmap app_bitmap = app_icon.GetRepresentation(1.f).GetBitmap();
if (!app_bitmap.isNull()) {
properties[WindowManager::kAppIcon_Property] =
mojo::ConvertTo<TransportType>(app_bitmap);
@@ -278,7 +278,7 @@ MusClient::ConfigurePropertiesFromParams(
// TODO(crbug.com/667566): Support additional scales or gfx::Image[Skia].
gfx::ImageSkia window_icon = init_params.delegate->GetWindowIcon();
- SkBitmap window_bitmap = window_icon.GetRepresentation(1.f).sk_bitmap();
+ SkBitmap window_bitmap = window_icon.GetRepresentation(1.f).GetBitmap();
if (!window_bitmap.isNull()) {
properties[WindowManager::kWindowIcon_Property] =
mojo::ConvertTo<TransportType>(window_bitmap);
diff --git a/chromium/ui/views/mus/mus_views_delegate.cc b/chromium/ui/views/mus/mus_views_delegate.cc
index e383ac00d69..6456b0d31d7 100644
--- a/chromium/ui/views/mus/mus_views_delegate.cc
+++ b/chromium/ui/views/mus/mus_views_delegate.cc
@@ -6,6 +6,7 @@
#include "ui/views/mus/ax_remote_host.h"
#include "ui/views/mus/mus_client.h"
+#include "ui/views/mus/pointer_watcher_event_router.h"
namespace views {
@@ -19,4 +20,19 @@ void MusViewsDelegate::NotifyAccessibilityEvent(View* view,
MusClient::Get()->ax_remote_host()->HandleEvent(view, event_type);
}
+void MusViewsDelegate::AddPointerWatcher(PointerWatcher* pointer_watcher,
+ bool wants_moves) {
+ MusClient::Get()->pointer_watcher_event_router()->AddPointerWatcher(
+ pointer_watcher, wants_moves);
+}
+
+void MusViewsDelegate::RemovePointerWatcher(PointerWatcher* pointer_watcher) {
+ MusClient::Get()->pointer_watcher_event_router()->RemovePointerWatcher(
+ pointer_watcher);
+}
+
+bool MusViewsDelegate::IsPointerWatcherSupported() const {
+ return true;
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/mus_views_delegate.h b/chromium/ui/views/mus/mus_views_delegate.h
index b7d55503ac1..6346df2979b 100644
--- a/chromium/ui/views/mus/mus_views_delegate.h
+++ b/chromium/ui/views/mus/mus_views_delegate.h
@@ -20,6 +20,10 @@ class VIEWS_MUS_EXPORT MusViewsDelegate : public ViewsDelegate {
// ViewsDelegate:
void NotifyAccessibilityEvent(View* view,
ax::mojom::Event event_type) override;
+ void AddPointerWatcher(PointerWatcher* pointer_watcher,
+ bool wants_moves) override;
+ void RemovePointerWatcher(PointerWatcher* pointer_watcher) override;
+ bool IsPointerWatcherSupported() const override;
private:
LayoutProvider layout_provider_;
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 a203d2b14fd..a0fc60681e3 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_host.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.cc
@@ -15,7 +15,14 @@
namespace views {
-RemoteViewHost::RemoteViewHost() = default;
+RemoteViewHost::RemoteViewHost()
+ : embedding_root_(std::make_unique<aura::Window>(nullptr)) {
+ embedding_root_->set_owned_by_parent(false);
+ embedding_root_->SetName("RemoteViewHostWindow");
+ embedding_root_->SetType(aura::client::WINDOW_TYPE_CONTROL);
+ embedding_root_->Init(ui::LAYER_NOT_DRAWN);
+}
+
RemoteViewHost::~RemoteViewHost() = default;
void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
@@ -29,29 +36,11 @@ void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
embed_callback_ = std::move(callback);
if (GetWidget())
- CreateEmbeddingRoot();
+ EmbedImpl();
}
-void RemoteViewHost::CreateEmbeddingRoot() {
- // Should not be attached to anything.
- DCHECK(!native_view());
-
- // There is a pending embed request.
- DCHECK(!embed_token_.is_empty());
-
- embedding_root_ = std::make_unique<aura::Window>(nullptr);
- embedding_root_->set_owned_by_parent(false);
-
- embedding_root_->SetName("RemoteViewHostWindow");
- embedding_root_->SetProperty(aura::client::kEmbedType,
- aura::client::WindowEmbedType::EMBED_IN_OWNER);
- embedding_root_->SetType(aura::client::WINDOW_TYPE_CONTROL);
- embedding_root_->Init(ui::LAYER_NOT_DRAWN);
-
- // Must happen before EmbedUsingToken call for window server to figure out
- // the relevant display.
- Attach(embedding_root_.get());
-
+void RemoteViewHost::EmbedImpl() {
+ DCHECK(IsEmbedPending());
aura::WindowPortMus::Get(embedding_root_.get())
->EmbedUsingToken(embed_token_, embed_flags_,
base::BindOnce(&RemoteViewHost::OnEmbedResult,
@@ -60,17 +49,17 @@ void RemoteViewHost::CreateEmbeddingRoot() {
void RemoteViewHost::OnEmbedResult(bool success) {
LOG_IF(ERROR, !success) << "Failed to embed, token=" << embed_token_;
-
- if (!success && embedding_root_)
- embedding_root_.reset();
-
+ embed_token_ = {};
if (embed_callback_)
std::move(embed_callback_).Run(success);
}
void RemoteViewHost::AddedToWidget() {
- if (!native_view() && !embed_token_.is_empty())
- CreateEmbeddingRoot();
+ if (native_view())
+ return;
+ Attach(embedding_root_.get());
+ if (IsEmbedPending())
+ EmbedImpl();
}
} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host.h b/chromium/ui/views/mus/remote_view/remote_view_host.h
index 44b1552f325..2a3e4530124 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_host.h
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.h
@@ -36,8 +36,10 @@ class RemoteViewHost : public views::NativeViewHost {
EmbedCallback callback);
private:
+ bool IsEmbedPending() const { return !embed_token_.is_empty(); }
+
// Creates the embedding aura::Window and attach to it.
- void CreateEmbeddingRoot();
+ void EmbedImpl();
// Invoked after the embed operation.
void OnEmbedResult(bool success);
@@ -49,7 +51,7 @@ class RemoteViewHost : public views::NativeViewHost {
int embed_flags_ = 0;
EmbedCallback embed_callback_;
- std::unique_ptr<aura::Window> embedding_root_;
+ const std::unique_ptr<aura::Window> embedding_root_;
base::WeakPtrFactory<RemoteViewHost> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(RemoteViewHost);
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
index 611c00151cd..30db5c39f9a 100644
--- a/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
+++ b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
@@ -80,21 +80,20 @@ class RemoteViewHostTest : public aura::test::AuraTestBase {
DISALLOW_COPY_AND_ASSIGN(RemoteViewHostTest);
};
-// Tests that the embed operation fails with an unknown token and RemoteViewHost
-// will not be attached.
+// Tests that the embed operation fails with an unknown token.
TEST_F(RemoteViewHostTest, BadEmbed) {
const base::UnguessableToken unknown_token = base::UnguessableToken::Create();
// Ownership will be passed to |widget| later.
RemoteViewHost* host = new RemoteViewHost();
std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
- EXPECT_FALSE(host->native_view());
+ EXPECT_TRUE(host->native_view());
// Embed fails with unknown token.
EXPECT_FALSE(Embed(host, unknown_token));
- // |host| is not attached after adding to a widget.
- EXPECT_FALSE(host->native_view());
+ // |host| is still attached despite the Embed failure.
+ EXPECT_TRUE(host->native_view());
}
// Tests when RemoveViewHost is added to a widget before embedding.
@@ -105,15 +104,15 @@ TEST_F(RemoteViewHostTest, AddToWidgetBeforeEmbed) {
// Ownership will be passed to |widget| later.
RemoteViewHost* host = new RemoteViewHost();
- // |host| is not attached because embed operation is not performed.
+ // |host| is not attached until the widget is created.
EXPECT_FALSE(host->native_view());
std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
- EXPECT_FALSE(host->native_view());
+ EXPECT_TRUE(host->native_view());
// Embed succeeds.
EXPECT_TRUE(Embed(host, token));
- // |host| is now attached to the embedding window.
+ // |host| is still attached to the embedding window.
EXPECT_TRUE(host->native_view());
}
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
index 40dafe4c9db..1beddbf9de8 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ b/chromium/ui/views/mus/views_mus_test_suite.cc
@@ -14,7 +14,6 @@
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/simple_thread.h"
-#include "base/threading/thread.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "services/catalog/catalog.h"
@@ -68,24 +67,18 @@ class DefaultService : public service_manager::Service {
class ServiceManagerConnection {
public:
ServiceManagerConnection()
- : thread_("Persistent service_manager connections"),
- ipc_thread_("IPC thread") {
+ : thread_("Persistent service_manager connections") {
catalog::Catalog::LoadDefaultCatalogManifest(
base::FilePath(kCatalogFilename));
- mojo::core::Init();
- ipc_thread_.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
- ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
- ipc_thread_.task_runner(),
- mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
base::Thread::Options options;
thread_.StartWithOptions(options);
thread_.task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&ServiceManagerConnection::SetUpConnections,
- base::Unretained(this), &wait));
+ FROM_HERE,
+ base::BindOnce(
+ &ServiceManagerConnection::SetUpConnectionsOnBackgroundThread,
+ base::Unretained(this), &wait));
wait.Wait();
}
@@ -94,8 +87,9 @@ class ServiceManagerConnection {
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread_.task_runner()->PostTask(
FROM_HERE,
- base::BindOnce(&ServiceManagerConnection::TearDownConnections,
- base::Unretained(this), &wait));
+ base::BindOnce(
+ &ServiceManagerConnection::TearDownConnectionsOnBackgroundThread,
+ base::Unretained(this), &wait));
wait.Wait();
}
@@ -124,7 +118,7 @@ class ServiceManagerConnection {
wait->Signal();
}
- void SetUpConnections(base::WaitableEvent* wait) {
+ void SetUpConnectionsOnBackgroundThread(base::WaitableEvent* wait) {
background_service_manager_ =
std::make_unique<service_manager::BackgroundServiceManager>(nullptr,
nullptr);
@@ -140,8 +134,9 @@ class ServiceManagerConnection {
wait->Signal();
}
- void TearDownConnections(base::WaitableEvent* wait) {
+ void TearDownConnectionsOnBackgroundThread(base::WaitableEvent* wait) {
context_.reset();
+ background_service_manager_.reset();
wait->Signal();
}
@@ -155,8 +150,6 @@ class ServiceManagerConnection {
}
base::Thread thread_;
- base::Thread ipc_thread_;
- std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support_;
std::unique_ptr<service_manager::BackgroundServiceManager>
background_service_manager_;
std::unique_ptr<service_manager::ServiceContext> context_;
@@ -226,7 +219,7 @@ std::unique_ptr<PlatformTestHelper> CreatePlatformTestHelper() {
} // namespace
ViewsMusTestSuite::ViewsMusTestSuite(int argc, char** argv)
- : ViewsTestSuite(argc, argv) {}
+ : ViewsTestSuite(argc, argv), ipc_thread_("IPC thread") {}
ViewsMusTestSuite::~ViewsMusTestSuite() {}
@@ -248,6 +241,13 @@ void ViewsMusTestSuite::Initialize() {
switches::kEnableFeatures, features::kMash.name);
PlatformTestHelper::set_factory(base::Bind(&CreatePlatformTestHelper));
+
+ mojo::core::Init();
+ ipc_thread_.StartWithOptions(
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
+ ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
+ ipc_thread_.task_runner(),
+ mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
}
void ViewsMusTestSuite::InitializeEnv() {
diff --git a/chromium/ui/views/mus/views_mus_test_suite.h b/chromium/ui/views/mus/views_mus_test_suite.h
index 4dc9d09dc07..8490ab91912 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.h
+++ b/chromium/ui/views/mus/views_mus_test_suite.h
@@ -9,8 +9,15 @@
#include "base/macros.h"
#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread.h"
#include "ui/views/views_test_suite.h"
+namespace mojo {
+namespace core {
+class ScopedIPCSupport;
+}
+} // namespace mojo
+
namespace views {
class ViewsMusTestSuite : public ViewsTestSuite {
@@ -24,6 +31,9 @@ class ViewsMusTestSuite : public ViewsTestSuite {
void InitializeEnv() override;
void DestroyEnv() override;
+ base::Thread ipc_thread_;
+ std::unique_ptr<mojo::core::ScopedIPCSupport> ipc_support_;
+
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<aura::Env> env_;
diff --git a/chromium/ui/views/painter.cc b/chromium/ui/views/painter.cc
index 24bb9e2a566..da297c1a02b 100644
--- a/chromium/ui/views/painter.cc
+++ b/chromium/ui/views/painter.cc
@@ -31,7 +31,9 @@ class SolidRoundRectPainter : public Painter {
SolidRoundRectPainter(SkColor bg_color,
SkColor stroke_color,
float radius,
- const gfx::Insets& insets);
+ const gfx::Insets& insets,
+ SkBlendMode blend_mode,
+ bool antialias);
~SolidRoundRectPainter() override;
// Painter:
@@ -43,6 +45,8 @@ class SolidRoundRectPainter : public Painter {
const SkColor stroke_color_;
const float radius_;
const gfx::Insets insets_;
+ const SkBlendMode blend_mode_;
+ const bool antialias_;
DISALLOW_COPY_AND_ASSIGN(SolidRoundRectPainter);
};
@@ -50,11 +54,15 @@ class SolidRoundRectPainter : public Painter {
SolidRoundRectPainter::SolidRoundRectPainter(SkColor bg_color,
SkColor stroke_color,
float radius,
- const gfx::Insets& insets)
+ const gfx::Insets& insets,
+ SkBlendMode blend_mode,
+ bool antialias)
: bg_color_(bg_color),
stroke_color_(stroke_color),
radius_(radius),
- insets_(insets) {}
+ insets_(insets),
+ blend_mode_(blend_mode),
+ antialias_(antialias) {}
SolidRoundRectPainter::~SolidRoundRectPainter() {}
@@ -68,20 +76,27 @@ void SolidRoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
gfx::Rect inset_rect(size);
inset_rect.Inset(insets_);
- gfx::RectF border_rect_f(gfx::ScaleToEnclosingRect(inset_rect, scale));
- const SkScalar scaled_corner_radius = SkFloatToScalar(radius_ * scale);
+ gfx::RectF fill_rect(gfx::ScaleToEnclosingRect(inset_rect, scale));
+ gfx::RectF stroke_rect = fill_rect;
+ float scaled_radius = radius_ * scale;
cc::PaintFlags flags;
- flags.setAntiAlias(true);
+ flags.setBlendMode(blend_mode_);
+ if (antialias_)
+ flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setColor(bg_color_);
- canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, flags);
-
- border_rect_f.Inset(gfx::InsetsF(0.5f));
- flags.setStyle(cc::PaintFlags::kStroke_Style);
- flags.setStrokeWidth(1);
- flags.setColor(stroke_color_);
- canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, flags);
+ canvas->DrawRoundRect(fill_rect, scaled_radius, flags);
+
+ if (stroke_color_ != SK_ColorTRANSPARENT) {
+ constexpr float kStrokeWidth = 1.0f;
+ stroke_rect.Inset(gfx::InsetsF(kStrokeWidth / 2));
+ scaled_radius -= kStrokeWidth / 2;
+ flags.setStyle(cc::PaintFlags::kStroke_Style);
+ flags.setStrokeWidth(kStrokeWidth);
+ flags.setColor(stroke_color_);
+ canvas->DrawRoundRect(stroke_rect, scaled_radius, flags);
+ }
}
// DashedFocusPainter ----------------------------------------------------------
@@ -266,18 +281,22 @@ void Painter::PaintFocusPainter(View* view,
std::unique_ptr<Painter> Painter::CreateSolidRoundRectPainter(
SkColor color,
float radius,
- const gfx::Insets& insets) {
- return std::make_unique<SolidRoundRectPainter>(color, SK_ColorTRANSPARENT,
- radius, insets);
+ const gfx::Insets& insets,
+ SkBlendMode blend_mode,
+ bool antialias) {
+ return std::make_unique<SolidRoundRectPainter>(
+ color, SK_ColorTRANSPARENT, radius, insets, blend_mode, antialias);
}
// static
std::unique_ptr<Painter> Painter::CreateRoundRectWith1PxBorderPainter(
SkColor bg_color,
SkColor stroke_color,
- float radius) {
- return std::make_unique<SolidRoundRectPainter>(bg_color, stroke_color, radius,
- gfx::Insets());
+ float radius,
+ SkBlendMode blend_mode,
+ bool antialias) {
+ return std::make_unique<SolidRoundRectPainter>(
+ bg_color, stroke_color, radius, gfx::Insets(), blend_mode, antialias);
}
// static
diff --git a/chromium/ui/views/painter.h b/chromium/ui/views/painter.h
index cb3f495dc8d..984348ee13a 100644
--- a/chromium/ui/views/painter.h
+++ b/chromium/ui/views/painter.h
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/nine_image_painter_factory.h"
#include "ui/gfx/geometry/insets.h"
@@ -57,14 +58,18 @@ class VIEWS_EXPORT Painter {
static std::unique_ptr<Painter> CreateSolidRoundRectPainter(
SkColor color,
float radius,
- const gfx::Insets& insets = gfx::Insets());
+ const gfx::Insets& insets = gfx::Insets(),
+ SkBlendMode blend_mode = SkBlendMode::kSrcOver,
+ bool antialias = true);
// Creates a painter that draws a RoundRect with a solid color and a given
// corner radius, and also adds a 1px border (inset) in the given color.
static std::unique_ptr<Painter> CreateRoundRectWith1PxBorderPainter(
SkColor bg_color,
SkColor stroke_color,
- float radius);
+ float radius,
+ SkBlendMode blend_mode = SkBlendMode::kSrcOver,
+ bool antialias = true);
// Creates a painter that divides |image| into nine regions. The four corners
// are rendered at the size specified in insets (eg. the upper-left corner is
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index ae97f1994e4..5264dfe5712 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -1,10 +1,9 @@
-// Copyright (c) 2013 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.
#include "ui/views/touchui/touch_selection_controller_impl.h"
-#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "ui/aura/client/cursor_client.h"
@@ -19,6 +18,7 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/path.h"
#include "ui/resources/grit/ui_resources.h"
+#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/coordinate_conversion.h"
@@ -74,14 +74,14 @@ const int kSelectionHandleBarBottomAllowance = 3;
// Creates a widget to host SelectionHandleView.
views::Widget* CreateTouchSelectionPopupWidget(
- gfx::NativeView context,
+ gfx::NativeView parent,
views::WidgetDelegate* widget_delegate) {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.parent = context;
+ params.parent = parent;
params.delegate = widget_delegate;
widget->Init(params);
return widget;
@@ -202,34 +202,6 @@ gfx::Rect BoundToRect(const gfx::SelectionBound& bound) {
bound.edge_bottom_rounded());
}
-// 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:
- 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 {
@@ -238,20 +210,24 @@ using EditingHandleView = TouchSelectionControllerImpl::EditingHandleView;
// A View that displays the text selection handle.
class TouchSelectionControllerImpl::EditingHandleView
- : public views::WidgetDelegateView {
+ : public WidgetDelegateView {
public:
EditingHandleView(TouchSelectionControllerImpl* controller,
- gfx::NativeView context,
+ gfx::NativeView parent,
bool is_cursor_handle)
: controller_(controller),
image_(GetCenterHandleImage()),
is_cursor_handle_(is_cursor_handle),
draw_invisible_(false),
weak_ptr_factory_(this) {
- widget_.reset(CreateTouchSelectionPopupWidget(context, this));
+ widget_.reset(CreateTouchSelectionPopupWidget(parent, this));
+ targeter_ = new aura::WindowTargeter();
aura::Window* window = widget_->GetNativeWindow();
- targeter_ = new TouchHandleWindowTargeter(window);
+ // For Mus clients, adjust targeting of the handle's client root window,
+ // constructed by the window server for the handle's "content" window.
+ if (window->env()->mode() == aura::Env::Mode::MUS)
+ window = window->GetRootWindow();
window->SetEventTargeter(std::unique_ptr<aura::WindowTargeter>(targeter_));
// We are owned by the TouchSelectionControllerImpl.
@@ -264,12 +240,12 @@ class TouchSelectionControllerImpl::EditingHandleView
return selection_bound_.type();
}
- // Overridden from views::WidgetDelegateView:
+ // WidgetDelegateView:
void DeleteDelegate() override {
// We are owned and deleted by TouchSelectionControllerImpl.
}
- // Overridden from views::View:
+ // View:
void OnPaint(gfx::Canvas* canvas) override {
if (draw_invisible_)
return;
@@ -379,8 +355,10 @@ class TouchSelectionControllerImpl::EditingHandleView
selection_bound_.SetEdge(gfx::PointF(edge_top), gfx::PointF(edge_bottom));
}
- targeter_->SetTopInset(selection_bound_.GetHeight() +
- kSelectionHandleVerticalVisualOffset);
+ const gfx::Insets insets(
+ selection_bound_.GetHeight() + kSelectionHandleVerticalVisualOffset, 0,
+ 0, 0);
+ targeter_->SetInsets(insets, insets);
}
void SetDrawInvisible(bool draw_invisible) {
@@ -394,11 +372,11 @@ class TouchSelectionControllerImpl::EditingHandleView
std::unique_ptr<Widget> widget_;
TouchSelectionControllerImpl* controller_;
- // A custom targeter that shifts the hit-test target below the apparent bounds
+ // A WindowTargeter that shifts the hit-test target below the apparent bounds
// to make dragging easier. The |widget_|'s NativeWindow takes ownership over
// the |targeter_| but since the |widget_|'s lifetime is known to this class,
// it can safely access the |targeter_|.
- TouchHandleWindowTargeter* targeter_;
+ aura::WindowTargeter* targeter_;
// In local coordinates
gfx::SelectionBound selection_bound_;
@@ -427,23 +405,20 @@ class TouchSelectionControllerImpl::EditingHandleView
TouchSelectionControllerImpl::TouchSelectionControllerImpl(
ui::TouchEditable* client_view)
: client_view_(client_view),
- client_widget_(nullptr),
- selection_handle_1_(new EditingHandleView(this,
- client_view->GetNativeView(),
- false)),
- selection_handle_2_(new EditingHandleView(this,
- client_view->GetNativeView(),
- false)),
- cursor_handle_(new EditingHandleView(this,
- client_view->GetNativeView(),
- true)),
- command_executed_(false),
- dragging_handle_(nullptr) {
+ selection_handle_1_(
+ new EditingHandleView(this, client_view->GetNativeView(), false)),
+ selection_handle_2_(
+ new EditingHandleView(this, client_view->GetNativeView(), false)),
+ cursor_handle_(
+ new EditingHandleView(this, client_view->GetNativeView(), true)) {
selection_start_time_ = base::TimeTicks::Now();
aura::Window* client_window = client_view_->GetNativeView();
client_widget_ = Widget::GetTopLevelWidgetForNativeView(client_window);
+ // Observe client widget moves and resizes to update the selection handles.
if (client_widget_)
client_widget_->AddObserver(this);
+ if (ViewsDelegate::GetInstance()->IsPointerWatcherSupported())
+ ViewsDelegate::GetInstance()->AddPointerWatcher(this, true);
aura::Env::GetInstance()->AddPreTargetHandler(this);
}
@@ -452,6 +427,8 @@ TouchSelectionControllerImpl::~TouchSelectionControllerImpl() {
command_executed_);
HideQuickMenu();
aura::Env::GetInstance()->RemovePreTargetHandler(this);
+ if (ViewsDelegate::GetInstance()->IsPointerWatcherSupported())
+ ViewsDelegate::GetInstance()->RemovePointerWatcher(this);
if (client_widget_)
client_widget_->RemoveObserver(this);
}
@@ -649,6 +626,18 @@ void TouchSelectionControllerImpl::OnWidgetBoundsChanged(
SelectionChanged();
}
+void TouchSelectionControllerImpl::OnPointerEventObserved(
+ const ui::PointerEvent& event,
+ const gfx::Point& location_in_screen,
+ gfx::NativeView target) {
+ // Disregard CursorClient::IsMouseEventsEnabled, it is disabled for touch
+ // events in this client, but not re-enabled for mouse events sent elsewhere.
+ if (event.pointer_details().pointer_type ==
+ ui::EventPointerType::POINTER_TYPE_MOUSE) {
+ client_view_->DestroyTouchSelection();
+ }
+}
+
void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
client_view_->DestroyTouchSelection();
}
@@ -773,11 +762,11 @@ gfx::Rect TouchSelectionControllerImpl::GetExpectedHandleBounds(
return GetSelectionWidgetBounds(bound);
}
-views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() {
+WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() {
return selection_handle_1_.get();
}
-views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() {
+WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() {
return selection_handle_2_.get();
}
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.h b/chromium/ui/views/touchui/touch_selection_controller_impl.h
index cf222421548..7e231e126e1 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.h
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2013 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_UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
-#define UI_UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
+#ifndef UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
+#define UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
#include "base/macros.h"
#include "base/timer/timer.h"
@@ -11,6 +11,7 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/selection_bound.h"
#include "ui/touch_selection/touch_selection_menu_runner.h"
+#include "ui/views/pointer_watcher.h"
#include "ui/views/view.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/widget_observer.h"
@@ -29,17 +30,16 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
: public ui::TouchEditingControllerDeprecated,
public ui::TouchSelectionMenuClient,
public WidgetObserver,
+ public PointerWatcher,
public ui::EventHandler {
public:
class EditingHandleView;
- // Use TextSelectionController::create().
- explicit TouchSelectionControllerImpl(
- ui::TouchEditable* client_view);
-
+ // Use ui::TouchEditingControllerFactory::Create() instead.
+ explicit TouchSelectionControllerImpl(ui::TouchEditable* client_view);
~TouchSelectionControllerImpl() override;
- // TextSelectionController.
+ // ui::TouchEditingControllerDeprecated:
void SelectionChanged() override;
bool IsHandleDragInProgress() override;
void HideHandles(bool quick) override;
@@ -70,19 +70,22 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
// |bound| should be the clipped version of the selection bound.
bool ShouldShowHandleFor(const gfx::SelectionBound& bound) const;
- // Overridden from ui::TouchSelectionMenuClient.
+ // ui::TouchSelectionMenuClient:
bool IsCommandIdEnabled(int command_id) const override;
void ExecuteCommand(int command_id, int event_flags) override;
void RunContextMenu() override;
- // Overridden from WidgetObserver. We will observe the widget backing the
- // |client_view_| so that when its moved/resized, we can update the selection
- // handles appropriately.
+ // WidgetObserver:
void OnWidgetClosing(Widget* widget) override;
void OnWidgetBoundsChanged(Widget* widget,
const gfx::Rect& new_bounds) override;
- // Overriden from ui::EventHandler.
+ // PointerWatcher:
+ void OnPointerEventObserved(const ui::PointerEvent& event,
+ const gfx::Point& location_in_screen,
+ gfx::NativeView target) override;
+
+ // ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnScrollEvent(ui::ScrollEvent* event) override;
@@ -112,15 +115,15 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
bool IsSelectionHandle2Visible();
bool IsCursorHandleVisible();
gfx::Rect GetExpectedHandleBounds(const gfx::SelectionBound& bound);
- views::WidgetDelegateView* GetHandle1View();
- views::WidgetDelegateView* GetHandle2View();
+ WidgetDelegateView* GetHandle1View();
+ WidgetDelegateView* GetHandle2View();
ui::TouchEditable* client_view_;
- Widget* client_widget_;
+ Widget* client_widget_ = nullptr;
std::unique_ptr<EditingHandleView> selection_handle_1_;
std::unique_ptr<EditingHandleView> selection_handle_2_;
std::unique_ptr<EditingHandleView> cursor_handle_;
- bool command_executed_;
+ bool command_executed_ = false;
base::TimeTicks selection_start_time_;
// Timer to trigger quick menu (Quick menu is not shown if the selection
@@ -129,7 +132,7 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
base::OneShotTimer quick_menu_timer_;
// Pointer to the SelectionHandleView being dragged during a drag session.
- EditingHandleView* dragging_handle_;
+ EditingHandleView* dragging_handle_ = nullptr;
// In cursor mode, the two selection bounds are the same and correspond to
// |cursor_handle_|; otherwise, they correspond to |selection_handle_1_| and
@@ -148,4 +151,4 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
} // namespace views
-#endif // UI_UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
+#endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index d238fad21fd..d0aba92898f 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -311,7 +311,7 @@ bool View::Contains(const View* view) const {
}
int View::GetIndexOf(const View* view) const {
- Views::const_iterator i(std::find(children_.begin(), children_.end(), view));
+ auto i(std::find(children_.begin(), children_.end(), view));
return i != children_.end() ? static_cast<int>(i - children_.begin()) : -1;
}
@@ -1191,6 +1191,13 @@ void View::ConvertEventToTarget(ui::EventTarget* target,
event->ConvertLocationToTarget(this, static_cast<View*>(target));
}
+gfx::PointF View::GetScreenLocationF(const ui::LocatedEvent& event) const {
+ DCHECK_EQ(this, event.target());
+ gfx::Point screen_location(event.location());
+ ConvertPointToScreen(this, &screen_location);
+ return gfx::PointF(screen_location);
+}
+
// Accelerators ----------------------------------------------------------------
void View::AddAccelerator(const ui::Accelerator& accelerator) {
@@ -1209,8 +1216,7 @@ void View::RemoveAccelerator(const ui::Accelerator& accelerator) {
return;
}
- std::vector<ui::Accelerator>::iterator i(
- std::find(accelerators_->begin(), accelerators_->end(), accelerator));
+ auto i(std::find(accelerators_->begin(), accelerators_->end(), accelerator));
if (i == accelerators_->end()) {
NOTREACHED() << "Removing non-existing accelerator";
return;
@@ -2204,7 +2210,7 @@ void View::BoundsChanged(const gfx::Rect& previous_bounds) {
// Notify interested Views that visible bounds within the root view may have
// changed.
if (descendants_to_notify_.get()) {
- for (Views::iterator i(descendants_to_notify_->begin());
+ for (auto i(descendants_to_notify_->begin());
i != descendants_to_notify_->end(); ++i) {
(*i)->OnVisibleBoundsChanged();
}
@@ -2254,8 +2260,8 @@ void View::AddDescendantToNotify(View* view) {
void View::RemoveDescendantToNotify(View* view) {
DCHECK(view && descendants_to_notify_.get());
- Views::iterator i(std::find(
- descendants_to_notify_->begin(), descendants_to_notify_->end(), view));
+ auto i(std::find(descendants_to_notify_->begin(),
+ descendants_to_notify_->end(), view));
DCHECK(i != descendants_to_notify_->end());
descendants_to_notify_->erase(i);
if (descendants_to_notify_->empty())
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index 4248609dd3c..161e015c044 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -888,6 +888,7 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
ui::EventTargeter* GetEventTargeter() override;
void ConvertEventToTarget(ui::EventTarget* target,
ui::LocatedEvent* event) override;
+ gfx::PointF GetScreenLocationF(const ui::LocatedEvent& event) const override;
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
diff --git a/chromium/ui/views/view_properties.cc b/chromium/ui/views/view_properties.cc
index e55acc0ca94..2f4f54e35ff 100644
--- a/chromium/ui/views/view_properties.cc
+++ b/chromium/ui/views/view_properties.cc
@@ -20,6 +20,8 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, gfx::Insets*);
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT,
views::BubbleDialogDelegateView*);
+DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, gfx::Path*);
+
namespace views {
DEFINE_UI_CLASS_PROPERTY_KEY(int, kHitTestComponentKey, HTNOWHERE);
@@ -27,5 +29,6 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Insets, kMarginsKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(views::BubbleDialogDelegateView*,
kAnchoredDialogKey,
nullptr);
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Path, kHighlightPathKey, nullptr);
} // namespace views
diff --git a/chromium/ui/views/view_properties.h b/chromium/ui/views/view_properties.h
index 2896ee94512..5f63c1b902d 100644
--- a/chromium/ui/views/view_properties.h
+++ b/chromium/ui/views/view_properties.h
@@ -10,6 +10,7 @@
namespace gfx {
class Insets;
+class Path;
} // namespace gfx
namespace views {
@@ -30,6 +31,12 @@ VIEWS_EXPORT extern const ui::ClassProperty<gfx::Insets*>* const kMarginsKey;
VIEWS_EXPORT extern const ui::ClassProperty<BubbleDialogDelegateView*>* const
kAnchoredDialogKey;
+// A property to store a highlight path related to the view. This is nominally
+// used by the default inkdrop and focus ring that are both used to highlight
+// the view in different ways.
+VIEWS_EXPORT extern const ui::ClassProperty<gfx::Path*>* const
+ kHighlightPathKey;
+
} // namespace views
// Declaring the template specialization here to make sure that the
@@ -40,5 +47,5 @@ VIEWS_EXPORT extern const ui::ClassProperty<BubbleDialogDelegateView*>* const
DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, gfx::Insets*);
DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT,
views::BubbleDialogDelegateView*);
-
+DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, gfx::Path*);
#endif // UI_VIEWS_VIEW_PROPERTIES_H_
diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc
index 846e579237c..d580fde1f8b 100644
--- a/chromium/ui/views/views_delegate.cc
+++ b/chromium/ui/views/views_delegate.cc
@@ -48,8 +48,7 @@ ViewsDelegate* ViewsDelegate::GetInstance() {
void ViewsDelegate::SaveWindowPlacement(const Widget* widget,
const std::string& window_name,
const gfx::Rect& bounds,
- ui::WindowShowState show_state) {
-}
+ ui::WindowShowState show_state) {}
bool ViewsDelegate::GetSavedWindowPlacement(
const Widget* widget,
@@ -66,8 +65,7 @@ void ViewsDelegate::NotifyMenuItemFocused(const base::string16& menu_name,
const base::string16& menu_item_name,
int item_index,
int item_count,
- bool has_submenu) {
-}
+ bool has_submenu) {}
ViewsDelegate::ProcessMenuAcceleratorResult
ViewsDelegate::ProcessAcceleratorWhileMenuShowing(
@@ -98,20 +96,14 @@ NonClientFrameView* ViewsDelegate::CreateDefaultNonClientFrameView(
return nullptr;
}
-void ViewsDelegate::AddRef() {
-}
+void ViewsDelegate::AddRef() {}
-void ViewsDelegate::ReleaseRef() {
-}
+void ViewsDelegate::ReleaseRef() {}
void ViewsDelegate::OnBeforeWidgetInit(
Widget::InitParams* params,
internal::NativeWidgetDelegate* delegate) {}
-base::TimeDelta ViewsDelegate::GetTextfieldPasswordRevealDuration() {
- return base::TimeDelta();
-}
-
bool ViewsDelegate::WindowManagerProvidesTitleBar(bool maximized) {
return false;
}
@@ -140,4 +132,16 @@ bool ViewsDelegate::ShouldMirrorArrowsInRTL() const {
return true;
}
+void ViewsDelegate::AddPointerWatcher(PointerWatcher*, bool) {
+ NOTREACHED();
+}
+
+void ViewsDelegate::RemovePointerWatcher(PointerWatcher*) {
+ NOTREACHED();
+}
+
+bool ViewsDelegate::IsPointerWatcherSupported() const {
+ return false;
+}
+
} // namespace views
diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h
index 3f16d177c21..b5237c3f20f 100644
--- a/chromium/ui/views/views_delegate.h
+++ b/chromium/ui/views/views_delegate.h
@@ -23,10 +23,6 @@
#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
-namespace base {
-class TimeDelta;
-}
-
namespace gfx {
class ImageSkia;
class Rect;
@@ -34,13 +30,14 @@ class Rect;
namespace ui {
class ContextFactory;
+class TouchEditingControllerFactory;
}
namespace views {
class NativeWidget;
class NonClientFrameView;
-class ViewsTouchEditingControllerFactory;
+class PointerWatcher;
class View;
class Widget;
@@ -173,9 +170,6 @@ class VIEWS_EXPORT ViewsDelegate {
virtual void OnBeforeWidgetInit(Widget::InitParams* params,
internal::NativeWidgetDelegate* delegate);
- // Returns the password reveal duration for Textfield.
- virtual base::TimeDelta GetTextfieldPasswordRevealDuration();
-
// Returns true if the operating system's window manager will always provide a
// title bar with caption buttons (ignoring the setting to
// |remove_standard_frame| in InitParams). If |maximized|, this applies to
@@ -206,11 +200,18 @@ class VIEWS_EXPORT ViewsDelegate {
// opens in the opposite direction.
virtual bool ShouldMirrorArrowsInRTL() const;
+ // Allows lower-level views components to use Mus-only PointerWatcher wiring.
+ // TODO(crbug.com/887725): Support PointerWatcher without mus, refactor.
+ virtual void AddPointerWatcher(PointerWatcher* pointer_watcher,
+ bool wants_moves);
+ virtual void RemovePointerWatcher(PointerWatcher* pointer_watcher);
+ virtual bool IsPointerWatcherSupported() const;
+
protected:
ViewsDelegate();
private:
- std::unique_ptr<ViewsTouchEditingControllerFactory>
+ std::unique_ptr<ui::TouchEditingControllerFactory>
editing_controller_factory_;
#if defined(USE_AURA)
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 86578b995a2..38447dc9ae0 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_capture_client.cc
@@ -79,8 +79,7 @@ void DesktopCaptureClient::SetCapture(aura::Window* new_capture_window) {
// Notify the other roots that we got capture. This is important so that
// they reset state.
CaptureClients capture_clients(*capture_clients_);
- for (CaptureClients::iterator i = capture_clients.begin();
- i != capture_clients.end(); ++i) {
+ for (auto i = capture_clients.begin(); i != capture_clients.end(); ++i) {
if (*i != this) {
aura::client::CaptureDelegate* delegate =
(*i)->root_->GetHost()->dispatcher();
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 00073d3d3bf..f0da4f88142 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
@@ -450,8 +450,7 @@ void DesktopDragDropClientAuraX11::X11DragContext::ReadActions() {
int DesktopDragDropClientAuraX11::X11DragContext::GetDragOperation() const {
int drag_operation = ui::DragDropTypes::DRAG_NONE;
- for (std::vector<::Atom>::const_iterator it = actions_.begin();
- it != actions_.end(); ++it) {
+ for (auto it = actions_.begin(); it != actions_.end(); ++it) {
MaskOperation(*it, &drag_operation);
}
@@ -711,7 +710,7 @@ void DesktopDragDropClientAuraX11::OnXdndDrop(
}
if (!IsDragDropInProgress()) {
- UMA_HISTOGRAM_COUNTS("Event.DragDrop.ExternalOriginDrop", 1);
+ UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1);
}
drag_operation = delegate->OnPerformDrop(event);
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
index a6fe148e3d2..f60cc49e7ab 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11_unittest.cc
@@ -354,8 +354,7 @@ void TestDragDropClient::SetTopmostXWindowAndMoveMouse(::Window xid) {
}
void TestDragDropClient::SendXClientEvent(::Window xid, XEvent* event) {
- std::map< ::Window, ClientMessageEventCollector*>::iterator it =
- collectors_.find(xid);
+ auto it = collectors_.find(xid);
if (it != collectors_.end())
it->second->RecordEvent(event->xclient);
}
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 99c525f3219..094a0b00bce 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
@@ -99,7 +99,7 @@ DWORD DesktopDropTargetWin::OnDrop(IDataObject* data_object,
DragDropClient* client = aura::client::GetDragDropClient(root_window_);
if (client && !client->IsDragDropInProgress() &&
drag_operation != ui::DragDropTypes::DRAG_NONE) {
- UMA_HISTOGRAM_COUNTS("Event.DragDrop.ExternalOriginDrop", 1);
+ UMA_HISTOGRAM_COUNTS_1M("Event.DragDrop.ExternalOriginDrop", 1);
}
}
if (target_window_) {
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index 5d4ae7a9805..d0731338684 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -51,7 +51,7 @@ void DesktopNativeCursorManager::SetCursor(
delegate->CommitCursor(new_cursor);
if (delegate->IsCursorVisible()) {
- for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ for (auto i = hosts_.begin(); i != hosts_.end(); ++i)
(*i)->SetCursor(new_cursor);
}
}
@@ -66,11 +66,11 @@ void DesktopNativeCursorManager::SetVisibility(
} else {
gfx::NativeCursor invisible_cursor(ui::CursorType::kNone);
cursor_loader_->SetPlatformCursor(&invisible_cursor);
- for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ for (auto i = hosts_.begin(); i != hosts_.end(); ++i)
(*i)->SetCursor(invisible_cursor);
}
- for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ for (auto i = hosts_.begin(); i != hosts_.end(); ++i)
(*i)->OnCursorVisibilityChanged(visible);
}
@@ -90,7 +90,7 @@ void DesktopNativeCursorManager::SetMouseEventsEnabled(
SetVisibility(delegate->IsCursorVisible(), delegate);
- for (Hosts::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
+ for (auto i = hosts_.begin(); i != hosts_.end(); ++i)
(*i)->dispatcher()->OnMouseEventsEnableStateChanged(enabled);
}
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 01a429a67e3..264858b3a46 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
@@ -595,11 +595,15 @@ const ui::Layer* DesktopNativeWidgetAura::GetLayer() const {
}
void DesktopNativeWidgetAura::ReorderNativeViews() {
+ if (!content_window_)
+ return;
+
// Reordering native views causes multiple changes to the window tree.
- // Instantiate a ScopedPauseOcclusionTracking to recompute occlusion once at
- // the end of this scope rather than after each individual change.
+ // Instantiate a ScopedPause to recompute occlusion once at the end of this
+ // scope rather than after each individual change.
// https://crbug.com/829918
- aura::WindowOcclusionTracker::ScopedPauseOcclusionTracking pause_occlusion;
+ aura::WindowOcclusionTracker::ScopedPause pause_occlusion(
+ content_window_->env());
window_reorderer_->ReorderChildWindows();
}
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 9d4d564ee7a..2514071e8bd 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
@@ -17,7 +17,6 @@
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/window_occlusion_tracker_test_api.h"
#include "ui/aura/window.h"
-#include "ui/aura/window_occlusion_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/display/screen.h"
#include "ui/events/event_processor.h"
@@ -312,7 +311,7 @@ TEST_F(DesktopNativeWidgetAuraTest, ReorderDoesntRecomputeOcclusion) {
parent.Show();
aura::Window* parent_window = parent.GetNativeWindow();
- aura::WindowOcclusionTracker::Track(parent_window);
+ parent_window->TrackOcclusionState();
View* contents_view = parent.GetContentsView();
@@ -335,7 +334,8 @@ TEST_F(DesktopNativeWidgetAuraTest, ReorderDoesntRecomputeOcclusion) {
contents_view->AddChildView(host_view3);
// Reorder child views. Expect occlusion to only be recomputed once.
- aura::test::WindowOcclusionTrackerTestApi window_occlusion_tracker_test_api;
+ aura::test::WindowOcclusionTrackerTestApi window_occlusion_tracker_test_api(
+ parent_window->env());
const int num_times_occlusion_recomputed =
window_occlusion_tracker_test_api.GetNumTimesOcclusionRecomputed();
contents_view->ReorderChildView(host_view3, 0);
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
index a5e871e8dae..6dd57cd7454 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
@@ -4,6 +4,7 @@
#include "ui/views/widget/desktop_aura/desktop_screen_ozone.h"
+#include "ui/aura/screen_ozone.h"
#include "ui/display/display.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_snapshot.h"
@@ -55,7 +56,16 @@ void DesktopScreenOzone::OnDisplaySnapshotsInvalidated() {}
//////////////////////////////////////////////////////////////////////////////
display::Screen* CreateDesktopScreen() {
- return new DesktopScreenOzone;
+ auto platform_screen = ui::OzonePlatform::GetInstance()->CreateScreen();
+ if (!platform_screen) {
+ // TODO: At the moment, only the Ozone/Headless uses this patch. Fix it:
+ // https://crbug.com/891613
+ LOG(ERROR) << "PlatformScreen is not implemented for this ozone platform. "
+ "Falling back to old DesktopScreenOzone implementation. See "
+ "https://crbug.com/872339 for details";
+ return new DesktopScreenOzone;
+ }
+ return new aura::ScreenOzone(std::move(platform_screen));
}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index e90710c2c39..0951d2fb5b9 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -232,8 +232,7 @@ display::Display DesktopScreenX11::GetDisplayNearestPoint(
const gfx::Point& point) const {
if (displays_.size() <= 1)
return GetPrimaryDisplay();
- for (std::vector<display::Display>::const_iterator it = displays_.begin();
- it != displays_.end(); ++it) {
+ for (auto it = displays_.begin(); it != displays_.end(); ++it) {
if (it->bounds().Contains(point))
return *it;
}
@@ -244,8 +243,7 @@ display::Display DesktopScreenX11::GetDisplayMatching(
const gfx::Rect& match_rect) const {
int max_area = 0;
const display::Display* matching = NULL;
- for (std::vector<display::Display>::const_iterator it = displays_.begin();
- it != displays_.end(); ++it) {
+ for (auto it = displays_.begin(); it != displays_.end(); ++it) {
gfx::Rect intersect = gfx::IntersectRects(it->bounds(), match_rect);
int area = intersect.width() * intersect.height();
if (area > max_area) {
@@ -450,7 +448,7 @@ std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
monitor_order_primary_display_index = displays.size();
- if (!display::Display::HasForceColorProfile()) {
+ if (!display::Display::HasForceDisplayColorProfile()) {
gfx::ICCProfile icc_profile = GetICCProfileForMonitor(
monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
icc_profile.HistogramDisplay(display.id());
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 dcf1d7d40c2..fbfa8df1f7d 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
@@ -6,13 +6,16 @@
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/transient_window_client.h"
+#include "ui/base/hit_test.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/window_event_filter.h"
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/window/native_frame_view.h"
#include "ui/wm/core/window_util.h"
@@ -91,6 +94,19 @@ void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
const Widget::InitParams& params) {
native_widget_delegate_->OnNativeWidgetCreated(true);
+
+ // Setup a non_client_window_event_filter, which handles resize/move, double
+ // click and other events.
+ DCHECK(!non_client_window_event_filter_);
+ std::unique_ptr<WindowEventFilter> window_event_filter =
+ std::make_unique<WindowEventFilter>(this);
+ auto* wm_move_resize_handler = GetWmMoveResizeHandler(*platform_window());
+ if (wm_move_resize_handler)
+ window_event_filter->SetWmMoveResizeHandler(
+ GetWmMoveResizeHandler(*(platform_window())));
+
+ non_client_window_event_filter_ = std::move(window_event_filter);
+ window()->AddPreTargetHandler(non_client_window_event_filter_.get());
}
void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {}
@@ -135,6 +151,8 @@ void DesktopWindowTreeHostPlatform::CloseNow() {
if (!weak_ref || got_on_closed_)
return;
+ RemoveNonClientEventFilter();
+
native_widget_delegate_->OnNativeWidgetDestroying();
got_on_closed_ = true;
@@ -449,7 +467,34 @@ bool DesktopWindowTreeHostPlatform::ShouldCreateVisibilityController() const {
return true;
}
+void DesktopWindowTreeHostPlatform::DispatchEvent(ui::Event* event) {
+#if defined(USE_OZONE)
+ // Make sure the |event| is marked as a non-client if it's a non-client
+ // mouse down event. This is needed to make sure the WindowEventDispatcher
+ // does not set a |mouse_pressed_handler_| for such events, because they are
+ // not always followed with non-client mouse up events in case of
+ // Ozone/Wayland or Ozone/X11.
+ //
+ // Also see the comment in WindowEventDispatcher::PreDispatchMouseEvent..
+ aura::Window* content_window = desktop_native_widget_aura_->content_window();
+ if (content_window && content_window->delegate()) {
+ if (event->IsMouseEvent()) {
+ ui::MouseEvent* mouse_event = event->AsMouseEvent();
+ int flags = mouse_event->flags();
+ int hit_test_code = content_window->delegate()->GetNonClientComponent(
+ mouse_event->location());
+ if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
+ flags |= ui::EF_IS_NON_CLIENT;
+ mouse_event->set_flags(flags);
+ }
+ }
+#endif
+
+ WindowTreeHostPlatform::DispatchEvent(event);
+}
+
void DesktopWindowTreeHostPlatform::OnClosed() {
+ RemoveNonClientEventFilter();
got_on_closed_ = true;
desktop_native_widget_aura_->OnHostClosed();
}
@@ -492,6 +537,14 @@ void DesktopWindowTreeHostPlatform::Relayout() {
widget->GetRootView()->Layout();
}
+void DesktopWindowTreeHostPlatform::RemoveNonClientEventFilter() {
+ if (!non_client_window_event_filter_)
+ return;
+
+ window()->RemovePreTargetHandler(non_client_window_event_filter_.get());
+ non_client_window_event_filter_.reset();
+}
+
Widget* DesktopWindowTreeHostPlatform::GetWidget() {
return native_widget_delegate_->AsWidget();
}
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 b6219dd00a7..e0b98abdaf0 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
@@ -12,6 +12,8 @@
namespace views {
+class WindowEventFilter;
+
class VIEWS_EXPORT DesktopWindowTreeHostPlatform
: public aura::WindowTreeHostPlatform,
public DesktopWindowTreeHost {
@@ -90,14 +92,19 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
bool ShouldCreateVisibilityController() const override;
// WindowTreeHostPlatform:
+ void DispatchEvent(ui::Event* event) override;
void OnClosed() override;
void OnWindowStateChanged(ui::PlatformWindowState new_state) override;
void OnCloseRequest() override;
void OnActivationChanged(bool active) override;
private:
+ FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostPlatformTest, HitTest);
+
void Relayout();
+ void RemoveNonClientEventFilter();
+
Widget* GetWidget();
gfx::Rect ToDIPRect(const gfx::Rect& rect_in_pixels) const;
@@ -113,6 +120,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
bool is_active_ = false;
+ // A handler for events intended for non client area.
+ std::unique_ptr<WindowEventFilter> non_client_window_event_filter_;
+
base::WeakPtrFactory<DesktopWindowTreeHostPlatform> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostPlatform);
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_interactive_uitest.cc
new file mode 100644
index 00000000000..f959917fcfe
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_interactive_uitest.cc
@@ -0,0 +1,272 @@
+// 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 "ui/aura/window_tree_host_platform.h"
+#include "ui/base/hit_test.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
+#include "ui/views/test/views_interactive_ui_test_base.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/window_event_filter.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/native_frame_view.h"
+
+namespace views {
+
+namespace {
+
+bool IsNonClientComponent(int hittest) {
+ switch (hittest) {
+ case HTBOTTOM:
+ case HTBOTTOMLEFT:
+ case HTBOTTOMRIGHT:
+ case HTCAPTION:
+ case HTLEFT:
+ case HTRIGHT:
+ case HTTOP:
+ case HTTOPLEFT:
+ case HTTOPRIGHT:
+ return true;
+ default:
+ return false;
+ }
+ return true;
+}
+
+// A fake handler, which just stores the hittest and pointer location values.
+class FakeWmMoveResizeHandler : public ui::WmMoveResizeHandler {
+ public:
+ using SetBoundsCallback = base::RepeatingCallback<void(gfx::Rect)>;
+ explicit FakeWmMoveResizeHandler(ui::PlatformWindow* window)
+ : platform_window_(window), hittest_(-1) {}
+ ~FakeWmMoveResizeHandler() override = default;
+
+ void Reset() {
+ hittest_ = -1;
+ pointer_location_ = gfx::Point();
+ }
+
+ int hittest() const { return hittest_; }
+ gfx::Point pointer_location() const { return pointer_location_; }
+
+ void set_bounds(const gfx::Rect& bounds) { bounds_ = bounds; }
+
+ // ui::WmMoveResizeHandler
+ void DispatchHostWindowDragMovement(
+ int hittest,
+ const gfx::Point& pointer_location) override {
+ hittest_ = hittest;
+ pointer_location_ = pointer_location;
+
+ platform_window_->SetBounds(bounds_);
+ }
+
+ private:
+ ui::PlatformWindow* platform_window_;
+ gfx::Rect bounds_;
+
+ int hittest_ = -1;
+ gfx::Point pointer_location_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeWmMoveResizeHandler);
+};
+
+void SetExpectationBasedOnHittestValue(int hittest,
+ const FakeWmMoveResizeHandler& handler,
+ const gfx::Point& pointer_location) {
+ if (IsNonClientComponent(hittest)) {
+ // Ensure both the pointer location and the hit test value are passed to the
+ // fake move/resize handler.
+ EXPECT_EQ(handler.pointer_location().ToString(),
+ pointer_location.ToString());
+ EXPECT_EQ(handler.hittest(), hittest);
+ return;
+ }
+
+ // Ensure the handler does not receive the hittest value or the pointer
+ // location.
+ EXPECT_TRUE(handler.pointer_location().IsOrigin());
+ EXPECT_NE(handler.hittest(), hittest);
+}
+
+// This is used to return a customized result to NonClientHitTest.
+class HitTestNonClientFrameView : public NativeFrameView {
+ public:
+ explicit HitTestNonClientFrameView(Widget* widget)
+ : NativeFrameView(widget), hit_test_result_(HTNOWHERE) {}
+ ~HitTestNonClientFrameView() override {}
+
+ void set_hit_test_result(int component) { hit_test_result_ = component; }
+
+ // NonClientFrameView overrides:
+ int NonClientHitTest(const gfx::Point& point) override {
+ return hit_test_result_;
+ }
+
+ private:
+ int hit_test_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestNonClientFrameView);
+};
+
+// This is used to return HitTestNonClientFrameView on create call.
+class HitTestWidgetDelegate : public views::WidgetDelegate {
+ public:
+ HitTestWidgetDelegate(views::Widget* widget,
+ HitTestNonClientFrameView* frame_view)
+ : widget_(widget), frame_view_(frame_view) {}
+ ~HitTestWidgetDelegate() override {}
+
+ void set_can_resize(bool can_resize) {
+ can_resize_ = can_resize;
+ widget_->OnSizeConstraintsChanged();
+ }
+
+ // views::WidgetDelegate:
+ bool CanResize() const override { return can_resize_; }
+ views::Widget* GetWidget() override { return widget_; }
+ views::Widget* GetWidget() const override { return widget_; }
+ views::NonClientFrameView* CreateNonClientFrameView(Widget* widget) override {
+ return frame_view_;
+ }
+
+ private:
+ views::Widget* widget_;
+ HitTestNonClientFrameView* frame_view_;
+ bool can_resize_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(HitTestWidgetDelegate);
+};
+
+} // namespace
+
+class DesktopWindowTreeHostPlatformTest : public ViewsInteractiveUITestBase {
+ public:
+ DesktopWindowTreeHostPlatformTest() = default;
+ ~DesktopWindowTreeHostPlatformTest() override = default;
+
+ protected:
+ Widget* BuildTopLevelDesktopWidget(const gfx::Rect& bounds) {
+ Widget* toplevel = new Widget;
+ frame_view_ = new HitTestNonClientFrameView(toplevel);
+ delegate_ = new HitTestWidgetDelegate(toplevel, frame_view_);
+ Widget::InitParams toplevel_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ toplevel_params.native_widget =
+ new views::DesktopNativeWidgetAura(toplevel);
+ toplevel_params.delegate = delegate_;
+ toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ toplevel_params.bounds = bounds;
+ toplevel_params.remove_standard_frame = true;
+ toplevel->Init(toplevel_params);
+ return toplevel;
+ }
+
+ std::unique_ptr<ui::MouseEvent> CreateMouseEvent(
+ const gfx::Point& pointer_location,
+ ui::EventType event_type,
+ int flags) {
+ std::unique_ptr<ui::MouseEvent> mouse_event =
+ std::make_unique<ui::MouseEvent>(event_type, pointer_location,
+ pointer_location,
+ base::TimeTicks::Now(), flags, flags);
+ return mouse_event;
+ }
+
+ HitTestNonClientFrameView* frame_view_ = nullptr;
+ HitTestWidgetDelegate* delegate_ = nullptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostPlatformTest);
+};
+
+TEST_F(DesktopWindowTreeHostPlatformTest, HitTest) {
+ gfx::Rect bounds(0, 0, 100, 100);
+ std::unique_ptr<Widget> widget(BuildTopLevelDesktopWidget(bounds));
+ widget->Show();
+
+ aura::Window* window = widget->GetNativeWindow();
+ DesktopWindowTreeHostPlatform* host =
+ static_cast<DesktopWindowTreeHostPlatform*>(window->GetHost());
+
+ // Install a fake move/resize handler to intercept the move/resize call.
+ WindowEventFilter* non_client_filter =
+ host->non_client_window_event_filter_.get();
+ std::unique_ptr<FakeWmMoveResizeHandler> handler =
+ std::make_unique<FakeWmMoveResizeHandler>(host->platform_window());
+ non_client_filter->SetWmMoveResizeHandler(handler.get());
+
+ delegate_->set_can_resize(true);
+
+ // It is not important to use pointer locations corresponding to the hittests
+ // values used in the browser itself, because we fake the hit test results,
+ // which non client frame view sends back. Thus, just make sure the content
+ // window is able to receive these events.
+ gfx::Point pointer_location(10, 10);
+
+ constexpr int hittest_values[] = {
+ HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT,
+ HTRIGHT, HTTOP, HTTOPLEFT, HTTOPRIGHT, HTNOWHERE,
+ HTBORDER, HTCLIENT, HTCLOSE, HTERROR, HTGROWBOX,
+ HTHELP, HTHSCROLL, HTMENU, HTMAXBUTTON, HTMINBUTTON,
+ HTREDUCE, HTSIZE, HTSYSMENU, HTTRANSPARENT, HTVSCROLL,
+ HTZOOM,
+ };
+
+ for (int hittest : hittest_values) {
+ handler->Reset();
+
+ // Set the desired hit test result value, which will be returned, when
+ // WindowEventFilter starts to perform hit testing.
+ frame_view_->set_hit_test_result(hittest);
+
+ gfx::Rect bounds = window->GetBoundsInScreen();
+
+ // The wm move/resize handler receives pointer location in the global screen
+ // coordinate, whereas event dispatcher receives event locations on a local
+ // system coordinate. Thus, add an offset of a new possible origin value of
+ // a window to the expected pointer location.
+ gfx::Point expected_pointer_location(pointer_location);
+ expected_pointer_location.Offset(bounds.x(), bounds.y());
+
+ if (hittest == HTCAPTION) {
+ // Move the window on HTCAPTION hit test value.
+ bounds =
+ gfx::Rect(gfx::Point(bounds.x() + 2, bounds.y() + 4), bounds.size());
+ handler->set_bounds(bounds);
+ } else if (IsNonClientComponent(hittest)) {
+ // Resize the window on other than HTCAPTION non client hit test values.
+ bounds = gfx::Rect(
+ gfx::Point(bounds.origin()),
+ gfx::Size(bounds.size().width() + 5, bounds.size().height() + 10));
+ handler->set_bounds(bounds);
+ }
+
+ // Send mouse down event and make sure the WindowEventFilter calls the
+ // move/resize handler to start interactive move/resize with the |hittest|
+ // value we specified.
+ auto mouse_down_event = CreateMouseEvent(
+ pointer_location, ui::ET_MOUSE_PRESSED, ui::EF_LEFT_MOUSE_BUTTON);
+ host->DispatchEvent(mouse_down_event.get());
+
+ // The test expectation is based on the hit test component. If it is a
+ // non-client component, which results in a call to move/resize, the handler
+ // must receive the hittest value and the pointer location in global screen
+ // coordinate system. In other cases, it must not.
+ SetExpectationBasedOnHittestValue(hittest, *handler.get(),
+ expected_pointer_location);
+ // Make sure the bounds of the content window are correct.
+ EXPECT_EQ(window->GetBoundsInScreen().ToString(), bounds.ToString());
+
+ // Dispatch mouse up event to release mouse pressed handler and be able to
+ // consume future events.
+ auto mouse_up_event = CreateMouseEvent(
+ pointer_location, ui::ET_MOUSE_RELEASED, ui::EF_LEFT_MOUSE_BUTTON);
+ host->DispatchEvent(mouse_up_event.get());
+ }
+}
+
+} // namespace views
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 4e04197810d..0ab1728d69b 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
@@ -476,8 +476,7 @@ void DesktopWindowTreeHostX11::CloseNow() {
// If we have children, close them. Use a copy for iteration because they'll
// remove themselves.
std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
- for (std::set<DesktopWindowTreeHostX11*>::iterator it =
- window_children_copy.begin(); it != window_children_copy.end();
+ for (auto it = window_children_copy.begin(); it != window_children_copy.end();
++it) {
(*it)->CloseNow();
}
@@ -1006,7 +1005,6 @@ void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
if (is_fullscreen_ == fullscreen)
return;
is_fullscreen_ = fullscreen;
- OnFullscreenStateChanged();
if (is_fullscreen_)
delayed_resize_task_.Cancel();
@@ -1372,10 +1370,6 @@ void DesktopWindowTreeHostX11::OnDisplayMetricsChanged(
}
}
-void DesktopWindowTreeHostX11::OnMaximizedStateChanged() {}
-
-void DesktopWindowTreeHostX11::OnFullscreenStateChanged() {}
-
////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostX11, private:
@@ -1677,12 +1671,10 @@ void DesktopWindowTreeHostX11::OnWMStateUpdated() {
void DesktopWindowTreeHostX11::UpdateWindowProperties(
const base::flat_set<XAtom>& new_window_properties) {
bool was_minimized = IsMinimized();
- bool was_maximized = IsMaximized();
window_properties_ = new_window_properties;
bool is_minimized = IsMinimized();
- bool is_maximized = IsMaximized();
// Propagate the window minimization information to the content window, so
// the render side can update its visibility properly. OnWMStateUpdated() is
@@ -1729,9 +1721,6 @@ void DesktopWindowTreeHostX11::UpdateWindowProperties(
is_always_on_top_ = ui::HasWMSpecProperty(
window_properties_, gfx::GetAtom("_NET_WM_STATE_ABOVE"));
- if (was_maximized != is_maximized)
- OnMaximizedStateChanged();
-
// Now that we have different window properties, we may need to relayout the
// window. (The windows code doesn't need this because their window change is
// synchronous.)
@@ -1935,7 +1924,7 @@ void DesktopWindowTreeHostX11::SerializeImageRepresentation(
int height = rep.GetHeight();
data->push_back(height);
- const SkBitmap& bitmap = rep.sk_bitmap();
+ const SkBitmap& bitmap = rep.GetBitmap();
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
@@ -2367,7 +2356,7 @@ gfx::Rect DesktopWindowTreeHostX11::ToPixelRect(
return gfx::ToEnclosingRect(rect_in_pixels);
}
-std::unique_ptr<base::OnceClosure>
+std::unique_ptr<base::Closure>
DesktopWindowTreeHostX11::DisableEventListening() {
// Allows to open multiple file-pickers. See https://crbug.com/678982
modal_dialog_counter_++;
@@ -2378,9 +2367,9 @@ DesktopWindowTreeHostX11::DisableEventListening() {
window(), std::make_unique<aura::NullWindowTargeter>());
}
- return std::make_unique<base::OnceClosure>(
- base::BindOnce(&DesktopWindowTreeHostX11::EnableEventListening,
- weak_factory_.GetWeakPtr()));
+ return std::make_unique<base::Closure>(
+ base::Bind(&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 cc9d5fb4823..2600a0621f3 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::OnceClosure> DisableEventListening();
+ std::unique_ptr<base::Closure> DisableEventListening();
// Returns a map of KeyboardEvent code to KeyboardEvent key values.
base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override;
@@ -184,12 +184,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) override;
- // Called after the window is maximized or restored.
- virtual void OnMaximizedStateChanged();
-
- // Called after the window is fullscreened or unfullscreened.
- virtual void OnFullscreenStateChanged();
-
private:
friend class DesktopWindowTreeHostX11HighDPITest;
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index 73507805813..2f3f85b16b1 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -9,6 +9,7 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
@@ -50,11 +51,8 @@ class WMStateWaiter : public X11PropertyChangeWaiter {
// X11PropertyChangeWaiter:
bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override {
std::vector<Atom> hints;
- if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &hints)) {
- auto it = std::find(hints.cbegin(), hints.cend(), gfx::GetAtom(hint_));
- bool hint_set = (it != hints.cend());
- return hint_set != wait_till_set_;
- }
+ if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &hints))
+ return base::ContainsValue(hints, gfx::GetAtom(hint_)) != wait_till_set_;
return true;
}
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 530b079289b..3b01fb995b4 100644
--- a/chromium/ui/views/widget/desktop_aura/window_event_filter.cc
+++ b/chromium/ui/views/widget/desktop_aura/window_event_filter.cc
@@ -6,6 +6,7 @@
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_tree_host.h"
@@ -14,6 +15,7 @@
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
+#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#include "ui/views/widget/native_widget_aura.h"
@@ -21,6 +23,28 @@
namespace views {
+namespace {
+
+bool CanPerformDragOrResize(int hittest) {
+ switch (hittest) {
+ case HTBOTTOM:
+ case HTBOTTOMLEFT:
+ case HTBOTTOMRIGHT:
+ case HTCAPTION:
+ case HTLEFT:
+ case HTRIGHT:
+ case HTTOP:
+ case HTTOPLEFT:
+ case HTTOPRIGHT:
+ return true;
+ default:
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
WindowEventFilter::WindowEventFilter(DesktopWindowTreeHost* window_tree_host)
: window_tree_host_(window_tree_host), click_component_(HTNOWHERE) {}
@@ -53,6 +77,12 @@ void WindowEventFilter::OnMouseEvent(ui::MouseEvent* event) {
}
}
+void WindowEventFilter::SetWmMoveResizeHandler(
+ ui::WmMoveResizeHandler* handler) {
+ DCHECK(!handler_);
+ handler_ = handler;
+}
+
void WindowEventFilter::OnClickedCaption(ui::MouseEvent* event,
int previous_click_component) {
aura::Window* target = static_cast<aura::Window*>(event->target());
@@ -149,6 +179,18 @@ void WindowEventFilter::LowerWindow() {}
void WindowEventFilter::MaybeDispatchHostWindowDragMovement(
int hittest,
- ui::MouseEvent* event) {}
+ ui::MouseEvent* event) {
+ if (handler_ && event->IsLeftMouseButton() &&
+ CanPerformDragOrResize(hittest)) {
+ // Some platforms (eg X11) may require last pointer location not in the
+ // local surface coordinates, but rather in the screen coordinates for
+ // interactive move/resize.
+ const gfx::Point last_pointer_location =
+ aura::Env::GetInstance()->last_mouse_location();
+ handler_->DispatchHostWindowDragMovement(hittest, last_pointer_location);
+ event->StopPropagation();
+ return;
+ }
+}
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/window_event_filter.h b/chromium/ui/views/widget/desktop_aura/window_event_filter.h
index a9bc0387c25..d3d7214f021 100644
--- a/chromium/ui/views/widget/desktop_aura/window_event_filter.h
+++ b/chromium/ui/views/widget/desktop_aura/window_event_filter.h
@@ -10,6 +10,10 @@
#include "ui/events/event_handler.h"
#include "ui/views/views_export.h"
+namespace ui {
+class WmMoveResizeHandler;
+}
+
namespace views {
class DesktopWindowTreeHost;
@@ -24,6 +28,11 @@ class VIEWS_EXPORT WindowEventFilter : public ui::EventHandler {
// Overridden from ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override;
+ // Sets a move resize handler. Currently initialized only by ozone platforms.
+ // See WaylandWindow::WaylandWindow in the wayland_window.cc file for an
+ // example.
+ void SetWmMoveResizeHandler(ui::WmMoveResizeHandler* handler);
+
private:
// Called when the user clicked the caption area.
void OnClickedCaption(ui::MouseEvent* event, int previous_click_component);
@@ -52,6 +61,11 @@ class VIEWS_EXPORT WindowEventFilter : public ui::EventHandler {
// components.
int click_component_;
+ // A handler, which is used for interactive move/resize events if set and
+ // unless MaybeDispatchHostWindowDragMovement is overridden by a derived
+ // class.
+ ui::WmMoveResizeHandler* handler_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(WindowEventFilter);
};
diff --git a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
index e0a11a00d46..a688da8c12b 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -11,6 +11,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/stl_util.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
@@ -42,9 +43,8 @@ class MinimizeWaiter : public X11PropertyChangeWaiter {
bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override {
std::vector<Atom> wm_states;
if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) {
- auto it = std::find(wm_states.cbegin(), wm_states.cend(),
- gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
- return it == wm_states.cend();
+ return !base::ContainsValue(wm_states,
+ gfx::GetAtom("_NET_WM_STATE_HIDDEN"));
}
return true;
}
@@ -80,8 +80,7 @@ class StackingClientListWaiter : public X11PropertyChangeWaiter {
std::vector<XID> stack;
ui::GetXWindowStack(ui::GetX11RootWindow(), &stack);
for (size_t i = 0; i < expected_windows_.size(); ++i) {
- auto it = std::find(stack.cbegin(), stack.cend(), expected_windows_[i]);
- if (it == stack.cend())
+ if (!base::ContainsValue(stack, expected_windows_[i]))
return true;
}
return false;
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index e6661017075..28c63b02b81 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -4,6 +4,9 @@
#include "ui/views/widget/native_widget_aura.h"
+#include <memory>
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
@@ -57,8 +60,7 @@
#if defined(OS_WIN)
#include "base/win/scoped_gdi_object.h"
-#include "base/win/win_client_metrics.h"
-#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/gfx/platform_font_win.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
#endif
@@ -1155,8 +1157,7 @@ void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
}
const aura::Window::Windows& child_windows = native_view->children();
- for (aura::Window::Windows::const_iterator i = child_windows.begin();
- i != child_windows.end(); ++i) {
+ for (auto i = child_windows.begin(); i != child_windows.end(); ++i) {
GetAllChildWidgets((*i), children);
}
}
@@ -1192,8 +1193,7 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
// First notify all the widgets that they are being disassociated
// from their previous parent.
- for (Widget::Widgets::iterator it = widgets.begin();
- it != widgets.end(); ++it) {
+ for (auto it = widgets.begin(); it != widgets.end(); ++it) {
(*it)->NotifyNativeViewHierarchyWillChange();
}
@@ -1217,8 +1217,7 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
}
// And now, notify them that they have a brand new parent.
- for (Widget::Widgets::iterator it = widgets.begin();
- it != widgets.end(); ++it) {
+ for (auto it = widgets.begin(); it != widgets.end(); ++it) {
(*it)->NotifyNativeViewHierarchyChanged();
}
}
@@ -1226,11 +1225,8 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
// static
gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
#if defined(OS_WIN)
- NONCLIENTMETRICS_XP ncm;
- base::win::GetNonClientMetrics(&ncm);
- l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
- base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
- return gfx::FontList(gfx::Font(caption_font.get()));
+ return gfx::FontList(gfx::PlatformFontWin::GetSystemFont(
+ gfx::PlatformFontWin::SystemFont::kCaption));
#else
return gfx::FontList();
#endif
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
index 5bb34bd75c3..e8e387ccd3c 100644
--- a/chromium/ui/views/widget/native_widget_mac.h
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -15,6 +15,12 @@
class NativeWidgetMacNSWindow;
#endif
+namespace views_bridge_mac {
+namespace mojom {
+class BridgedNativeWidget;
+} // namespace mojom
+} // namespace views_bridge_mac
+
namespace views {
namespace test {
class HitTestNativeWidgetMac;
@@ -22,7 +28,8 @@ class MockNativeWidgetMac;
class WidgetTest;
}
-class BridgedNativeWidget;
+class BridgeFactoryHost;
+class BridgedNativeWidgetImpl;
class BridgedNativeWidgetHostImpl;
class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
@@ -30,15 +37,8 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
explicit NativeWidgetMac(internal::NativeWidgetDelegate* delegate);
~NativeWidgetMac() override;
- // 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);
-
// Informs |delegate_| that the native widget is about to be destroyed.
- // BridgedNativeWidget::OnWindowWillClose() invokes this early when the
+ // BridgedNativeWidgetImpl::OnWindowWillClose() invokes this early when the
// NSWindowDelegate informs the bridge that the window is being closed (later,
// invoking OnWindowDestroyed()).
void WindowDestroying();
@@ -144,7 +144,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
std::string GetName() const override;
protected:
- // Creates the NSWindow that will be passed to the BridgedNativeWidget.
+ // Creates the NSWindow that will be passed to the BridgedNativeWidgetImpl.
// 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
@@ -153,11 +153,17 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
virtual NativeWidgetMacNSWindow* CreateNSWindow(
const Widget::InitParams& params);
+ // Return the BridgeFactoryHost that is to be used for creating this window
+ // and all of its child windows. This will return nullptr if the native
+ // windows are to be created in the current process.
+ virtual BridgeFactoryHost* GetBridgeFactoryHost();
+
// Optional hook for subclasses invoked by WindowDestroying().
virtual void OnWindowDestroying(NSWindow* window) {}
internal::NativeWidgetDelegate* delegate() { return delegate_; }
- BridgedNativeWidget* bridge() const;
+ views_bridge_mac::mojom::BridgedNativeWidget* bridge() const;
+ BridgedNativeWidgetImpl* bridge_impl() const;
BridgedNativeWidgetHostImpl* bridge_host_for_testing() const {
return bridge_host_.get();
}
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index decbcdf69ac..4f75293c284 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -10,7 +10,6 @@
#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"
#include "base/threading/thread_task_runner_handle.h"
@@ -25,16 +24,15 @@
#import "ui/gfx/mac/nswindow_frame_controls.h"
#include "ui/native_theme/native_theme.h"
#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"
-#import "ui/views/cocoa/views_nswindow_delegate.h"
#include "ui/views/widget/drop_helper.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/native_frame_view.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+#import "ui/views_bridge_mac/views_nswindow_delegate.h"
using views_bridge_mac::mojom::WindowVisibilityState;
@@ -44,17 +42,6 @@ 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
@@ -92,22 +79,6 @@ NativeWidgetMac::~NativeWidgetMac() {
CloseNow();
}
-// static
-BridgedNativeWidget* NativeWidgetMac::GetBridgeForNativeWindow(
- gfx::NativeWindow window) {
- if (NativeWidgetMac* widget = GetNativeWidgetMacForNativeWindow(window))
- return widget->bridge();
- return nullptr; // Not created by NativeWidgetMac.
-}
-
-// 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() {
OnWindowDestroying(GetNativeWindow());
delegate_->OnNativeWidgetDestroying();
@@ -137,9 +108,29 @@ int NativeWidgetMac::SheetPositionY() {
void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
ownership_ = params.ownership;
name_ = params.name;
- base::scoped_nsobject<NativeWidgetMacNSWindow> window(
- [CreateNSWindow(params) retain]);
- bridge()->SetWindow(window);
+ BridgedNativeWidgetHostImpl* parent_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow([params.parent window]);
+
+ // Determine the factory through which to create the bridge
+ BridgeFactoryHost* bridge_factory_host =
+ parent_host ? parent_host->bridge_factory_host() : GetBridgeFactoryHost();
+ if (bridge_factory_host) {
+ // Compute the parameters to describe the NSWindow.
+ // TODO(ccameron): This is not yet adequate to capture all NSWindow
+ // sub-classes that may be used. Make the parameter structure more
+ // expressive.
+ auto create_window_params =
+ views_bridge_mac::mojom::CreateWindowParams::New();
+ create_window_params->style_mask = StyleMaskForParams(params);
+
+ bridge_host_->CreateRemoteBridge(bridge_factory_host,
+ std::move(create_window_params));
+ } else {
+ base::scoped_nsobject<NativeWidgetMacNSWindow> window(
+ [CreateNSWindow(params) retain]);
+ bridge_host_->CreateLocalBridge(std::move(window));
+ }
+ bridge_host_->SetParent(parent_host);
bridge_host_->InitWindow(params);
// Only set always-on-top here if it is true since setting it may affect how
@@ -151,8 +142,8 @@ void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
DCHECK(GetWidget()->GetRootView());
bridge_host_->SetRootView(GetWidget()->GetRootView());
- bridge()->CreateContentView(GetWidget()->GetRootView()->bounds());
- bridge()->CreateDragDropClient(GetWidget()->GetRootView());
+ bridge()->CreateContentView(bridge_host_->GetRootViewNSViewId(),
+ GetWidget()->GetRootView()->bounds());
if (auto* focus_manager = GetWidget()->GetFocusManager()) {
bridge()->MakeFirstResponder();
bridge_host_->SetFocusManager(focus_manager);
@@ -201,7 +192,7 @@ gfx::NativeView NativeWidgetMac::GetNativeView() const {
}
gfx::NativeWindow NativeWidgetMac::GetNativeWindow() const {
- return bridge() ? bridge()->ns_window() : nil;
+ return bridge_host_ ? bridge_host_->GetLocalNSWindow() : nil;
}
Widget* NativeWidgetMac::GetTopLevelWidget() {
@@ -220,31 +211,32 @@ const ui::Layer* NativeWidgetMac::GetLayer() const {
}
void NativeWidgetMac::ReorderNativeViews() {
- if (bridge())
- bridge()->ReorderChildViews();
+ if (bridge_host_)
+ bridge_host_->ReorderChildViews();
}
void NativeWidgetMac::ViewRemoved(View* view) {
- DragDropClientMac* client = bridge() ? bridge()->drag_drop_client() : nullptr;
+ DragDropClientMac* client =
+ bridge_host_ ? bridge_host_->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_host_)
+ bridge_host_->SetNativeWindowProperty(name, value);
}
void* NativeWidgetMac::GetNativeWindowProperty(const char* name) const {
- if (bridge())
- return bridge()->GetNativeWindowProperty(name);
+ if (bridge_host_)
+ return bridge_host_->GetNativeWindowProperty(name);
return nullptr;
}
TooltipManager* NativeWidgetMac::GetTooltipManager() const {
- if (bridge())
- return bridge()->tooltip_manager();
+ if (bridge_host_)
+ return bridge_host_->tooltip_manager();
return nullptr;
}
@@ -268,12 +260,7 @@ ui::InputMethod* NativeWidgetMac::GetInputMethod() {
}
void NativeWidgetMac::CenterWindow(const gfx::Size& size) {
- SetSize(
- BridgedNativeWidget::GetWindowSizeForClientSize(GetNativeWindow(), size));
- // Note that this is not the precise center of screen, but it is the standard
- // location for windows like dialogs to appear on screen for Mac.
- // TODO(tapted): If there is a parent window, center in that instead.
- [GetNativeWindow() center];
+ bridge()->SetSizeAndCenter(size, GetWidget()->GetMinimumSize());
}
void NativeWidgetMac::GetWindowPlacement(
@@ -311,7 +298,7 @@ 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_host_->parent() || modal_type == ui::MODAL_TYPE_WINDOW);
// Everything happens upon show.
}
@@ -338,19 +325,14 @@ void NativeWidgetMac::SetBounds(const gfx::Rect& bounds) {
}
void NativeWidgetMac::SetBoundsConstrained(const gfx::Rect& bounds) {
- if (!bridge())
+ if (!bridge_host_)
return;
-
gfx::Rect new_bounds(bounds);
- NativeWidgetPrivate* ancestor =
- bridge() && bridge()->parent()
- ? GetNativeWidgetForNativeWindow(bridge()->parent()->GetNSWindow())
- : nullptr;
- if (!ancestor) {
- new_bounds = ConstrainBoundsToDisplayWorkArea(new_bounds);
- } else {
+ if (bridge_host_->parent()) {
new_bounds.AdjustToFit(
- gfx::Rect(ancestor->GetWindowBoundsInScreen().size()));
+ gfx::Rect(bridge_host_->parent()->GetWindowBoundsInScreen().size()));
+ } else {
+ new_bounds = ConstrainBoundsToDisplayWorkArea(new_bounds);
}
SetBounds(new_bounds);
}
@@ -395,8 +377,8 @@ void NativeWidgetMac::Show(ui::WindowShowState show_state,
case ui::SHOW_STATE_DEFAULT:
case ui::SHOW_STATE_NORMAL:
case ui::SHOW_STATE_INACTIVE:
- break;
case ui::SHOW_STATE_MINIMIZED:
+ break;
case ui::SHOW_STATE_MAXIMIZED:
case ui::SHOW_STATE_FULLSCREEN:
NOTIMPLEMENTED();
@@ -405,10 +387,12 @@ void NativeWidgetMac::Show(ui::WindowShowState show_state,
NOTREACHED();
break;
}
- bridge()->SetVisibilityState(
- show_state == ui::SHOW_STATE_INACTIVE
- ? WindowVisibilityState::kShowInactive
- : WindowVisibilityState::kShowAndActivateWindow);
+ auto window_state = WindowVisibilityState::kShowAndActivateWindow;
+ if (show_state == ui::SHOW_STATE_INACTIVE)
+ window_state = WindowVisibilityState::kShowInactive;
+ else if (show_state == ui::SHOW_STATE_MINIMIZED)
+ window_state = WindowVisibilityState::kHideWindow;
+ bridge()->SetVisibilityState(window_state);
// Ignore the SetInitialFocus() result. BridgedContentView should get
// firstResponder status regardless.
@@ -517,7 +501,8 @@ 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_host_->drag_drop_client()->StartDragAndDrop(view, data, operation,
+ source);
}
void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
@@ -535,8 +520,8 @@ void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
}
void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
- if (bridge())
- bridge()->SetCursor(cursor);
+ if (bridge_impl())
+ bridge_impl()->SetCursor(cursor);
}
bool NativeWidgetMac::IsMouseEventsEnabled() const {
@@ -568,20 +553,21 @@ Widget::MoveLoopResult NativeWidgetMac::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
- if (!bridge())
+ if (!bridge_impl())
return Widget::MOVE_LOOP_CANCELED;
- return bridge()->RunMoveLoop(drag_offset);
+ return bridge_impl()->RunMoveLoop(drag_offset) ? Widget::MOVE_LOOP_SUCCESSFUL
+ : Widget::MOVE_LOOP_CANCELED;
}
void NativeWidgetMac::EndMoveLoop() {
- if (bridge())
- bridge()->EndMoveLoop();
+ if (bridge_impl())
+ bridge_impl()->EndMoveLoop();
}
void NativeWidgetMac::SetVisibilityChangedAnimationsEnabled(bool value) {
- if (bridge())
- bridge()->SetAnimationEnabled(value);
+ if (bridge_impl())
+ bridge_impl()->SetAnimationEnabled(value);
}
void NativeWidgetMac::SetVisibilityAnimationDuration(
@@ -590,9 +576,25 @@ void NativeWidgetMac::SetVisibilityAnimationDuration(
}
void NativeWidgetMac::SetVisibilityAnimationTransition(
- Widget::VisibilityTransition transition) {
+ Widget::VisibilityTransition widget_transitions) {
+ views_bridge_mac::mojom::VisibilityTransition transitions =
+ views_bridge_mac::mojom::VisibilityTransition::kNone;
+ switch (widget_transitions) {
+ case Widget::ANIMATE_NONE:
+ transitions = views_bridge_mac::mojom::VisibilityTransition::kNone;
+ break;
+ case Widget::ANIMATE_SHOW:
+ transitions = views_bridge_mac::mojom::VisibilityTransition::kShow;
+ break;
+ case Widget::ANIMATE_HIDE:
+ transitions = views_bridge_mac::mojom::VisibilityTransition::kHide;
+ break;
+ case Widget::ANIMATE_BOTH:
+ transitions = views_bridge_mac::mojom::VisibilityTransition::kBoth;
+ break;
+ }
if (bridge())
- bridge()->set_transitions_to_animate(transition);
+ bridge()->SetTransitionsToAnimate(transitions);
}
bool NativeWidgetMac::IsTranslucentWindowOpacitySupported() const {
@@ -631,7 +633,15 @@ NativeWidgetMacNSWindow* NativeWidgetMac::CreateNSWindow(
defer:NO] autorelease];
}
-BridgedNativeWidget* NativeWidgetMac::bridge() const {
+BridgeFactoryHost* NativeWidgetMac::GetBridgeFactoryHost() {
+ return nullptr;
+}
+
+views_bridge_mac::mojom::BridgedNativeWidget* NativeWidgetMac::bridge() const {
+ return bridge_host_ ? bridge_host_->bridge() : nullptr;
+}
+
+BridgedNativeWidgetImpl* NativeWidgetMac::bridge_impl() const {
return bridge_host_ ? bridge_host_->bridge_impl() : nullptr;
}
@@ -690,32 +700,31 @@ NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
// static
NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
gfx::NativeWindow window) {
- if (NativeWidgetMac* widget = GetNativeWidgetMacForNativeWindow(window))
- return widget;
+ if (BridgedNativeWidgetHostImpl* bridge_host_impl =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow(window)) {
+ return bridge_host_impl->native_widget_mac();
+ }
return nullptr; // Not created by NativeWidgetMac.
}
// static
NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
gfx::NativeView native_view) {
- BridgedNativeWidget* bridge =
- NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
- if (!bridge)
+ BridgedNativeWidgetHostImpl* bridge_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ if (!bridge_host)
return nullptr;
-
- NativeWidgetPrivate* ancestor =
- bridge->parent() ? GetTopLevelNativeWidget(
- [bridge->parent()->GetNSWindow() contentView])
- : nullptr;
- return ancestor ? ancestor : bridge->native_widget_mac();
+ while (bridge_host->parent())
+ bridge_host = bridge_host->parent();
+ return bridge_host->native_widget_mac();
}
// static
void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
Widget::Widgets* children) {
- BridgedNativeWidget* bridge =
- NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
- if (!bridge) {
+ BridgedNativeWidgetHostImpl* bridge_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ if (!bridge_host) {
// The NSWindow is not itself a views::Widget, but it may have children that
// are. Support returning Widgets that are parented to the NSWindow, except:
// - Ignore requests for children of an NSView that is not a contentView.
@@ -738,67 +747,101 @@ void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
// If |native_view| is a subview of the contentView, it will share an
// NSWindow, but will itself be a native child of the Widget. That is, adding
- // bridge->..->GetWidget() to |children| would be adding the _parent_ of
+ // bridge_host->..->GetWidget() to |children| would be adding the _parent_ of
// |native_view|, not the Widget for |native_view|. |native_view| doesn't have
// a corresponding Widget of its own in this case (and so can't have Widget
// children of its own on Mac).
- if (bridge->ns_view() != native_view)
+ if (bridge_host->native_widget_mac()->GetNativeView() != native_view)
return;
// Code expects widget for |native_view| to be added to |children|.
- if (bridge->native_widget_mac()->GetWidget())
- children->insert(bridge->native_widget_mac()->GetWidget());
+ if (bridge_host->native_widget_mac()->GetWidget())
+ children->insert(bridge_host->native_widget_mac()->GetWidget());
- // When the NSWindow *is* a Widget, only consider child_windows(). I.e. do not
- // look through -[NSWindow childWindows] as done for the (!bridge) case above.
- // -childWindows does not support hidden windows, and anything in there which
- // is not in child_windows() would have been added by AppKit.
- for (BridgedNativeWidget* child : bridge->child_windows())
- GetAllChildWidgets(child->ns_view(), children);
+ // When the NSWindow *is* a Widget, only consider children(). I.e. do not
+ // look through -[NSWindow childWindows] as done for the (!bridge_host) case
+ // above. -childWindows does not support hidden windows, and anything in there
+ // which is not in children() would have been added by AppKit.
+ for (BridgedNativeWidgetHostImpl* child : bridge_host->children())
+ GetAllChildWidgets(child->native_widget_mac()->GetNativeView(), children);
}
// static
void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
Widget::Widgets* owned) {
- BridgedNativeWidget* bridge =
- NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
- if (!bridge) {
+ BridgedNativeWidgetHostImpl* bridge_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ if (!bridge_host) {
GetAllChildWidgets(native_view, owned);
return;
}
- if (bridge->ns_view() != native_view)
+ if (bridge_host->native_widget_mac()->GetNativeView() != native_view)
return;
- for (BridgedNativeWidget* child : bridge->child_windows())
- GetAllChildWidgets(child->ns_view(), owned);
+ for (BridgedNativeWidgetHostImpl* child : bridge_host->children())
+ GetAllChildWidgets(child->native_widget_mac()->GetNativeView(), owned);
}
// static
void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
gfx::NativeView new_parent) {
DCHECK_NE(native_view, new_parent);
+ DCHECK([new_parent window]);
if (!new_parent || [native_view superview] == new_parent) {
NOTREACHED();
return;
}
- BridgedNativeWidget* bridge =
- NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
- BridgedNativeWidget* parent_bridge =
- NativeWidgetMac::GetBridgeForNativeWindow([new_parent window]);
- DCHECK(bridge);
- if (Widget::GetWidgetForNativeView(native_view)->is_top_level() &&
- bridge->parent() == parent_bridge)
+ BridgedNativeWidgetHostImpl* bridge_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ DCHECK(bridge_host);
+ NSView* bridge_view = bridge_host->native_widget_mac()->GetNativeView();
+ NSWindow* bridge_window = bridge_host->native_widget_mac()->GetNativeWindow();
+ bool bridge_is_top_level =
+ bridge_host->native_widget_mac()->GetWidget()->is_top_level();
+ DCHECK([native_view isDescendantOf:bridge_view]);
+ DCHECK(bridge_window && ![bridge_window isSheet]);
+
+ BridgedNativeWidgetHostImpl* parent_bridge_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow([new_parent window]);
+
+ // Early out for no-op changes.
+ if (native_view == bridge_view && bridge_is_top_level &&
+ bridge_host->parent() == parent_bridge_host) {
return;
+ }
+ // First notify all the widgets that they are being disassociated from their
+ // previous parent.
Widget::Widgets widgets;
GetAllChildWidgets(native_view, &widgets);
-
- // First notify all the widgets that they are being disassociated
- // from their previous parent.
for (auto* child : widgets)
child->NotifyNativeViewHierarchyWillChange();
- bridge->ReparentNativeView(native_view, new_parent);
+ // Update |brige_host|'s parent only if
+ // BridgedNativeWidgetImpl::ReparentNativeView will.
+ if (native_view == bridge_view) {
+ bridge_host->SetParent(parent_bridge_host);
+ if (!bridge_is_top_level) {
+ // Make |bridge_host|'s NSView be a child of |new_parent| by adding it as
+ // a subview. Note that this will have the effect of removing
+ // |bridge_host|'s NSView from its NSWindow. The |NSWindow| must remain
+ // visible because it controls the bounds and visibility of the ui::Layer,
+ // so just hide it by setting alpha value to zero.
+ // TODO(ccameron): This path likely violates assumptions. Verify that this
+ // path is unused and remove it.
+ LOG(ERROR) << "Reparenting a non-top-level BridgedNativeWidget. This is "
+ "likely unsupported.";
+ [new_parent addSubview:native_view];
+ [bridge_window setAlphaValue:0];
+ [bridge_window setIgnoresMouseEvents:YES];
+ }
+ } else {
+ // TODO(ccameron): This path likely violates assumptions. Verify that this
+ // path is unused and remove it.
+ LOG(ERROR) << "Reparenting with a non-root BridgedNativeWidget NSView. "
+ "This is likely unsupported.";
+ [new_parent addSubview:native_view];
+ }
// And now, notify them that they have a brand new parent.
for (auto* child : widgets)
@@ -814,7 +857,7 @@ gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
// static
gfx::NativeView NativeWidgetPrivate::GetGlobalCapture(
gfx::NativeView native_view) {
- return [CocoaMouseCapture::GetGlobalCaptureWindow() contentView];
+ return BridgedNativeWidgetHostImpl::GetGlobalCaptureView();
}
} // namespace internal
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index ebb9ea6cd6d..4efaef021c4 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -28,9 +28,6 @@
#include "ui/events/test/event_generator.h"
#import "ui/gfx/mac/coordinate_conversion.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"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/native/native_view_host.h"
@@ -42,6 +39,9 @@
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/window/dialog_client_view.h"
#include "ui/views/window/dialog_delegate.h"
+#import "ui/views_bridge_mac/bridged_content_view.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
// Donates an implementation of -[NSAnimation stopAnimation] which calls the
// original implementation, then quits a nested run loop.
@@ -86,18 +86,14 @@
@interface FocusableTestNSView : NSView
@end
-@interface TestNativeParentWindow : NSWindow
-@property(assign, nonatomic) bool* deallocFlag;
-@end
-
namespace views {
namespace test {
-// BridgedNativeWidget friend to access private members.
+// BridgedNativeWidgetImpl friend to access private members.
class BridgedNativeWidgetTestApi {
public:
explicit BridgedNativeWidgetTestApi(NSWindow* window) {
- bridge_ = NativeWidgetMac::GetBridgeForNativeWindow(window);
+ bridge_ = BridgedNativeWidgetImpl::GetFromNativeWindow(window);
}
// Simulate a frame swap from the compositor.
@@ -116,7 +112,7 @@ class BridgedNativeWidgetTestApi {
}
private:
- BridgedNativeWidget* bridge_;
+ BridgedNativeWidgetImpl* bridge_;
DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTestApi);
};
@@ -148,30 +144,33 @@ class TestWindowNativeWidgetMac : public NativeWidgetMac {
DISALLOW_COPY_AND_ASSIGN(TestWindowNativeWidgetMac);
};
-// Tests for parts of NativeWidgetMac not covered by BridgedNativeWidget, which
-// need access to Cocoa APIs.
+// Tests for parts of NativeWidgetMac not covered by BridgedNativeWidgetImpl,
+// which need access to Cocoa APIs.
class NativeWidgetMacTest : public WidgetTest {
public:
NativeWidgetMacTest() {}
- // The content size of NSWindows made by MakeNativeParent().
- NSRect ParentRect() const { return NSMakeRect(100, 100, 300, 200); }
-
- // Make a native NSWindow with the given |style_mask| to use as a parent.
- TestNativeParentWindow* MakeNativeParentWithStyle(int style_mask) {
- native_parent_.reset([[TestNativeParentWindow alloc]
- initWithContentRect:ParentRect()
- styleMask:style_mask
- backing:NSBackingStoreBuffered
- defer:NO]);
- [native_parent_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
- [native_parent_ makeKeyAndOrderFront:nil];
- return native_parent_;
+ // Make an NSWindow with a close button and a title bar to use as a parent.
+ // This NSWindow is backed by a widget that is not exposed to the caller.
+ // To destroy the Widget, the native NSWindow must be closed.
+ NativeWidgetMacTestWindow* MakeClosableTitledNativeParent() {
+ NativeWidgetMacTestWindow* native_parent = nil;
+ Widget::InitParams parent_init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ parent_init_params.bounds = gfx::Rect(100, 100, 200, 200);
+ CreateWidgetWithTestWindow(parent_init_params, &native_parent);
+ return native_parent;
}
- // Make a borderless, native NSWindow to use as a parent.
- TestNativeParentWindow* MakeNativeParent() {
- return MakeNativeParentWithStyle(NSBorderlessWindowMask);
+ // Same as the above, but creates a borderless NSWindow.
+ NativeWidgetMacTestWindow* MakeBorderlessNativeParent() {
+ NativeWidgetMacTestWindow* native_parent = nil;
+ Widget::InitParams parent_init_params =
+ CreateParams(Widget::InitParams::TYPE_WINDOW);
+ parent_init_params.remove_standard_frame = true;
+ parent_init_params.bounds = gfx::Rect(100, 100, 200, 200);
+ CreateWidgetWithTestWindow(parent_init_params, &native_parent);
+ return native_parent;
}
// Create a Widget backed by the NativeWidgetMacTestWindow NSWindow subclass.
@@ -187,9 +186,6 @@ class NativeWidgetMacTest : public WidgetTest {
return widget;
}
- protected:
- base::scoped_nsobject<TestNativeParentWindow> native_parent_;
-
private:
DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacTest);
};
@@ -740,26 +736,27 @@ Widget* AttachPopupToNativeParent(NSWindow* native_parent) {
// Tests creating a views::Widget parented off a native NSWindow.
TEST_F(NativeWidgetMacTest, NonWidgetParent) {
- NSWindow* native_parent = MakeNativeParent();
+ NSWindow* native_parent = MakeBorderlessNativeParent();
Widget::Widgets children;
Widget::GetAllChildWidgets([native_parent contentView], &children);
- EXPECT_TRUE(children.empty());
+ EXPECT_EQ(1u, children.size());
Widget* child = AttachPopupToNativeParent(native_parent);
TestWidgetObserver child_observer(child);
- // GetTopLevelNativeWidget() only goes as far as there exists a Widget (i.e.
- // must stop at |child|.
+ // GetTopLevelNativeWidget() will go up through |native_parent|'s Widget.
internal::NativeWidgetPrivate* top_level_widget =
internal::NativeWidgetPrivate::GetTopLevelNativeWidget(
child->GetNativeView());
- EXPECT_EQ(child, top_level_widget->GetWidget());
+ EXPECT_EQ(Widget::GetWidgetForNativeWindow(native_parent),
+ top_level_widget->GetWidget());
+ EXPECT_NE(child, top_level_widget->GetWidget());
// To verify the parent, we need to use NativeWidgetMac APIs.
- BridgedNativeWidget* bridged_native_widget =
- NativeWidgetMac::GetBridgeForNativeWindow(child->GetNativeWindow());
- EXPECT_EQ(native_parent, bridged_native_widget->parent()->GetNSWindow());
+ BridgedNativeWidgetImpl* bridged_native_widget =
+ BridgedNativeWidgetImpl::GetFromNativeWindow(child->GetNativeWindow());
+ EXPECT_EQ(native_parent, bridged_native_widget->parent()->ns_window());
const gfx::Rect child_bounds(50, 50, 200, 100);
child->SetBounds(child_bounds);
@@ -774,8 +771,8 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
EXPECT_EQ(native_parent, [child->GetNativeWindow() parentWindow]);
Widget::GetAllChildWidgets([native_parent contentView], &children);
- ASSERT_EQ(1u, children.size());
- EXPECT_EQ(child, *children.begin());
+ ASSERT_EQ(2u, children.size());
+ EXPECT_EQ(1u, children.count(child));
// Only non-toplevel Widgets are positioned relative to the parent, so the
// bounds set above should be in screen coordinates.
@@ -786,7 +783,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
NSView* anchor_view = [[native_parent contentView] subviews][0];
EXPECT_TRUE(anchor_view);
[anchor_view removeFromSuperview];
- EXPECT_EQ(native_parent, bridged_native_widget->parent()->GetNSWindow());
+ EXPECT_EQ(native_parent, bridged_native_widget->parent()->ns_window());
// Closing the parent should close and destroy the child.
EXPECT_FALSE(child_observer.widget_closed());
@@ -794,6 +791,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
EXPECT_TRUE(child_observer.widget_closed());
EXPECT_EQ(0u, [[native_parent childWindows] count]);
+ [native_parent close];
}
// Tests that CloseAllSecondaryWidgets behaves in various configurations.
@@ -871,15 +869,16 @@ TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) {
TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
bool child_dealloced = false;
bool native_parent_dealloced = false;
+ NativeWidgetMacTestWindow* native_parent = nil;
{
base::mac::ScopedNSAutoreleasePool pool;
- TestNativeParentWindow* native_parent = MakeNativeParent();
+ native_parent = MakeBorderlessNativeParent();
[native_parent setDeallocFlag:&native_parent_dealloced];
NativeWidgetMacTestWindow* window;
Widget::InitParams init_params =
CreateParams(Widget::InitParams::TYPE_POPUP);
- init_params.parent = [native_parent_ contentView];
+ init_params.parent = [native_parent contentView];
init_params.bounds = gfx::Rect(0, 0, 100, 200);
CreateWidgetWithTestWindow(init_params, &window);
[window setDeallocFlag:&child_dealloced];
@@ -891,7 +890,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
// to the child window is released inside WidgetOwnerNSWindowAdapter::
// OnWindowWillClose().
base::mac::ScopedNSAutoreleasePool pool;
- [native_parent_.autorelease() close];
+ [native_parent close];
EXPECT_TRUE(child_dealloced);
}
EXPECT_TRUE(native_parent_dealloced);
@@ -900,7 +899,7 @@ TEST_F(NativeWidgetMacTest, NonWidgetParentLastReference) {
// Tests visibility for child of native NSWindow, reshowing after -[NSApp hide].
// Occasionally flaky (maybe due to [NSApp hide]). See https://crbug.com/777247.
TEST_F(NativeWidgetMacTest, DISABLED_VisibleAfterNativeParentShow) {
- NSWindow* native_parent = MakeNativeParent();
+ NSWindow* native_parent = MakeBorderlessNativeParent();
Widget* child = AttachPopupToNativeParent(native_parent);
child->Show();
EXPECT_TRUE(child->IsVisible());
@@ -925,7 +924,7 @@ TEST_F(NativeWidgetMacTest, VisibleAfterNativeParentDeminiaturize) {
if (base::mac::IsOS10_10())
return;
- NSWindow* native_parent = MakeNativeParent();
+ NSWindow* native_parent = MakeBorderlessNativeParent();
[native_parent makeKeyAndOrderFront:nil];
[native_parent miniaturize:nil];
Widget* child = AttachPopupToNativeParent(native_parent);
@@ -1173,9 +1172,9 @@ Widget* ShowWindowModalWidget(NSWindow* native_parent) {
} // namespace
// Tests object lifetime for the show/hide animations used for child-modal
-// windows. Parents the dialog off a native parent window (not a views::Widget).
+// windows.
TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) {
- NSWindow* native_parent = MakeNativeParent();
+ NSWindow* native_parent = MakeBorderlessNativeParent();
{
Widget* modal_dialog_widget = ShowChildModalWidgetAndWait(native_parent);
TestWidgetObserver widget_observer(modal_dialog_widget);
@@ -1228,7 +1227,7 @@ TEST_F(NativeWidgetMacTest, NativeWindowChildModalShowHide) {
// Tests that calls to Hide() a Widget cancel any in-progress show animation,
// and that clients can control the triggering of the animation.
TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
- NSWindow* native_parent = MakeNativeParent();
+ NSWindow* native_parent = MakeBorderlessNativeParent();
Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
new ModalDialogDelegate(ui::MODAL_TYPE_CHILD), nullptr,
[native_parent contentView]);
@@ -1247,7 +1246,7 @@ TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
EXPECT_TRUE([retained_animation isAnimating]);
// Hide without waiting for the animation to complete. Animation should cancel
- // and clear references from BridgedNativeWidget.
+ // and clear references from BridgedNativeWidgetImpl.
modal_dialog_widget->Hide();
EXPECT_FALSE([retained_animation isAnimating]);
EXPECT_FALSE(test_api.show_animation());
@@ -1286,8 +1285,7 @@ TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
// Tests behavior of window-modal dialogs, displayed as sheets.
TEST_F(NativeWidgetMacTest, WindowModalSheet) {
- NSWindow* native_parent =
- MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
+ NSWindow* native_parent = MakeClosableTitledNativeParent();
Widget* sheet_widget = views::DialogDelegate::CreateDialogWidget(
new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW), nullptr,
@@ -1328,7 +1326,7 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
Widget::Widgets children;
Widget::GetAllChildWidgets([native_parent contentView], &children);
- EXPECT_TRUE(children.empty());
+ ASSERT_EQ(2u, children.size());
sheet_widget->Show(); // Should run the above block, then animate the sheet.
EXPECT_TRUE(did_observe);
@@ -1336,8 +1334,8 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
// Ensure sheets are included as a child.
Widget::GetAllChildWidgets([native_parent contentView], &children);
- ASSERT_EQ(1u, children.size());
- EXPECT_EQ(sheet_widget, *children.begin());
+ ASSERT_EQ(2u, children.size());
+ EXPECT_TRUE(children.count(sheet_widget));
// Modal, so the close button in the parent window should get disabled.
EXPECT_FALSE([parent_close_button isEnabled]);
@@ -1348,9 +1346,9 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
// TODO(tapted): Ideally [native_parent orderOut:nil] would also work here.
// But it does not. AppKit's childWindow management breaks down after an
- // -orderOut: (see BridgedNativeWidget::OnVisibilityChanged()). For regular
- // child windows, BridgedNativeWidget fixes the behavior with its own
- // management. However, it can't do that for sheets without encountering
+ // -orderOut: (see BridgedNativeWidgetImpl::OnVisibilityChanged()). For
+ // regular child windows, BridgedNativeWidgetImpl fixes the behavior with its
+ // own management. However, it can't do that for sheets without encountering
// http://crbug.com/605098 and http://crbug.com/667602. -[NSApp hide:] makes
// the NSWindow hidden in a different way, which does not break like
// -orderOut: does. Which is good, because a user can always do -[NSApp
@@ -1368,41 +1366,24 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
sheet_widget->Close();
EXPECT_TRUE(sheet_widget->IsVisible());
- did_observe = false;
-
- // Experimentally (on 10.10), this notification is posted from within the
- // -[NSWindow orderOut:] call that is triggered from -[ViewsNSWindowDelegate
- // sheetDidEnd:]. |sheet_widget| will be destroyed next, so it's still safe to
- // use in the block. However, since the orderOut just happened, it's not very
- // interesting.
- observer = [[NSNotificationCenter defaultCenter]
- addObserverForName:NSWindowDidEndSheetNotification
- object:native_parent
- queue:nil
- usingBlock:^(NSNotification* note) {
- EXPECT_TRUE([sheet_window delegate]);
- *did_observe_ptr = true;
- }];
-
// Pump in order to trigger -[NSWindow endSheet:..], which will block while
// the animation runs, then delete |sheet_widget|.
EXPECT_TRUE([sheet_window delegate]);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE([sheet_window delegate]);
-
- EXPECT_TRUE(did_observe); // Also ensures the Close() actually uses sheets.
[[NSNotificationCenter defaultCenter] removeObserver:observer];
EXPECT_TRUE(widget_observer.widget_closed());
EXPECT_TRUE([parent_close_button isEnabled]);
+
+ [native_parent close];
}
// Tests behavior when closing a window that is a sheet, or that hosts a sheet,
// and reshowing a sheet on a window after the sheet was closed with -[NSWindow
// close].
TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
- NSWindow* native_parent =
- MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
+ NSWindow* native_parent = MakeClosableTitledNativeParent();
{
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
@@ -1496,8 +1477,7 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
// eventually complete on a destroyed NSWindowDelegate. Regression test for
// https://crbug.com/851376.
TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) {
- NSWindow* native_parent =
- MakeNativeParentWithStyle(NSClosableWindowMask | NSTitledWindowMask);
+ NSWindow* native_parent = MakeClosableTitledNativeParent();
{
base::mac::ScopedNSAutoreleasePool pool;
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
@@ -1541,17 +1521,16 @@ TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) {
}
// Test calls to Widget::ReparentNativeView() that result in a no-op on Mac.
-// Tests with both native and non-native parents.
TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
- NSWindow* parent = MakeNativeParent();
+ NSWindow* parent = MakeBorderlessNativeParent();
Widget* dialog = views::DialogDelegate::CreateDialogWidget(
new DialogDelegateView, nullptr, [parent contentView]);
- BridgedNativeWidget* bridge =
- NativeWidgetMac::GetBridgeForNativeWindow(dialog->GetNativeWindow());
+ BridgedNativeWidgetImpl* bridge =
+ BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow());
- EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+ EXPECT_EQ(bridge->parent()->ns_window(), parent);
Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
- EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+ EXPECT_EQ(bridge->parent()->ns_window(), parent);
[parent close];
@@ -1559,11 +1538,12 @@ TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
parent = parent_widget->GetNativeWindow();
dialog = views::DialogDelegate::CreateDialogWidget(
new DialogDelegateView, nullptr, [parent contentView]);
- bridge = NativeWidgetMac::GetBridgeForNativeWindow(dialog->GetNativeWindow());
+ bridge =
+ BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow());
- EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+ EXPECT_EQ(bridge->parent()->ns_window(), parent);
Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
- EXPECT_EQ(bridge->parent()->GetNSWindow(), parent);
+ EXPECT_EQ(bridge->parent()->ns_window(), parent);
parent_widget->CloseNow();
}
@@ -1778,7 +1758,7 @@ TEST_F(NativeWidgetMacTest, DISABLED_DoesHideTitle) {
// The default window with a title should look different from the
// window with an empty title.
- EXPECT_FALSE([empty_title_data isEqualToData:this_title_data]);
+ EXPECT_NSNE(empty_title_data, this_title_data);
delegate.set_should_show_title(false);
delegate.set_title(base::ASCIIToUTF16("This is another title"));
@@ -1788,7 +1768,7 @@ TEST_F(NativeWidgetMacTest, DISABLED_DoesHideTitle) {
// With our magic setting, the window with a title should look the
// same as the window with an empty title.
EXPECT_TRUE([ns_window _isTitleHidden]);
- EXPECT_TRUE([empty_title_data isEqualToData:hidden_title_data]);
+ EXPECT_NSEQ(empty_title_data, hidden_title_data);
widget->CloseNow();
}
@@ -2068,13 +2048,16 @@ TEST_F(NativeWidgetMacTest, ReparentNativeViewTypes) {
CreateParams(Widget::InitParams::TYPE_POPUP);
toplevel_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
toplevel1->Init(toplevel_params);
+ toplevel1->Show();
std::unique_ptr<Widget> toplevel2(new Widget);
toplevel2->Init(toplevel_params);
+ toplevel2->Show();
Widget* child = new Widget;
Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
child->Init(child_params);
+ child->Show();
Widget::ReparentNativeView(child->GetNativeView(),
toplevel1->GetNativeView());
@@ -2106,8 +2089,8 @@ class NativeWidgetMacFullKeyboardAccessTest : public NativeWidgetMacTest {
NativeWidgetMacTest::SetUp();
widget_ = CreateTopLevelPlatformWidget();
- bridge_ =
- NativeWidgetMac::GetBridgeForNativeWindow(widget_->GetNativeWindow());
+ bridge_ = BridgedNativeWidgetImpl::GetFromNativeWindow(
+ widget_->GetNativeWindow());
fake_full_keyboard_access_ =
ui::test::ScopedFakeFullKeyboardAccess::GetInstance();
DCHECK(fake_full_keyboard_access_);
@@ -2120,7 +2103,7 @@ class NativeWidgetMacFullKeyboardAccessTest : public NativeWidgetMacTest {
}
Widget* widget_ = nullptr;
- BridgedNativeWidget* bridge_ = nullptr;
+ BridgedNativeWidgetImpl* bridge_ = nullptr;
ui::test::ScopedFakeFullKeyboardAccess* fake_full_keyboard_access_ = nullptr;
};
@@ -2179,8 +2162,7 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
widget_ = CreateTopLevelPlatformWidget();
- ASSERT_EQ(1u, [[widget_->GetNativeView() subviews] count]);
- compositor_view_ = [[widget_->GetNativeView() subviews] firstObject];
+ starting_subviews_.reset([[widget_->GetNativeView() subviews] copy]);
native_host_parent_ = new View();
widget_->GetContentsView()->AddChildView(native_host_parent_);
@@ -2193,9 +2175,10 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
hosts_.push_back(std::move(holder));
}
EXPECT_EQ(kNativeViewCount, native_host_parent_->child_count());
- EXPECT_TRUE(([[widget_->GetNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
- ]]));
+ EXPECT_NSEQ([widget_->GetNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
+ ]]));
}
void TearDown() override {
@@ -2205,10 +2188,12 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
NSView* GetContentNativeView() { return widget_->GetNativeView(); }
+ NSArray<NSView*>* GetStartingSubviews() { return starting_subviews_; }
+
Widget* widget_ = nullptr;
View* native_host_parent_ = nullptr;
- NSView* compositor_view_ = nil;
std::vector<std::unique_ptr<NativeHostHolder>> hosts_;
+ base::scoped_nsobject<NSArray<NSView*>> starting_subviews_;
private:
DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacViewsOrderTest);
@@ -2218,61 +2203,65 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
// z-order.
TEST_F(NativeWidgetMacViewsOrderTest, NativeViewAttached) {
hosts_[1]->Detach();
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[2]->view()
- ]]));
+ EXPECT_NSEQ([GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[2]->view()
+ ]]));
hosts_[1]->AttachNativeView();
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
- hosts_[2]->view()
- ]]));
+ EXPECT_NSEQ([GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
+ ]]));
}
// Tests that NativeViews order changes according to views::View hierarchy.
TEST_F(NativeWidgetMacViewsOrderTest, ReorderViews) {
native_host_parent_->ReorderChildView(hosts_[2]->host(), 1);
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
- hosts_[1]->view()
- ]]));
+ EXPECT_NSEQ([GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[2]->view(), hosts_[1]->view()
+ ]]));
native_host_parent_->RemoveChildView(hosts_[2]->host());
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[1]->view()
- ]]));
+ EXPECT_NSEQ([GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[1]->view()
+ ]]));
View* new_parent = new View();
native_host_parent_->RemoveChildView(hosts_[1]->host());
native_host_parent_->AddChildView(new_parent);
new_parent->AddChildView(hosts_[1]->host());
new_parent->AddChildView(hosts_[2]->host());
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
- hosts_[2]->view()
- ]]));
+ EXPECT_NSEQ([GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
+ ]]));
native_host_parent_->ReorderChildView(new_parent, 0);
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[1]->view(), hosts_[2]->view(),
- hosts_[0]->view()
- ]]));
+ EXPECT_NSEQ([GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[1]->view(), hosts_[2]->view(), hosts_[0]->view()
+ ]]));
}
// Test that unassociated native views stay on top after reordering.
TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) {
base::scoped_nsobject<NSView> child_view([[NSView alloc] init]);
[GetContentNativeView() addSubview:child_view];
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
- hosts_[2]->view(), child_view
- ]]));
+ EXPECT_NSEQ(
+ [GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view(), child_view
+ ]]));
native_host_parent_->ReorderChildView(hosts_[2]->host(), 1);
- EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
- compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
- hosts_[1]->view(), child_view
- ]]));
+ EXPECT_NSEQ(
+ [GetContentNativeView() subviews],
+ ([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
+ hosts_[0]->view(), hosts_[2]->view(), hosts_[1]->view(), child_view
+ ]]));
}
// Test -[NSWindowDelegate windowShouldClose:].
@@ -2421,18 +2410,3 @@ TEST_F(NativeWidgetMacTest, TouchBar) {
}
@end
-@implementation TestNativeParentWindow {
- bool* deallocFlag_;
-}
-
-@synthesize deallocFlag = deallocFlag_;
-
-- (void)dealloc {
- if (deallocFlag_) {
- DCHECK(!*deallocFlag_);
- *deallocFlag_ = true;
- }
- [super dealloc];
-}
-
-@end
diff --git a/chromium/ui/views/widget/widget.cc b/chromium/ui/views/widget/widget.cc
index 5ad48b616fa..0353201e793 100644
--- a/chromium/ui/views/widget/widget.cc
+++ b/chromium/ui/views/widget/widget.cc
@@ -1058,11 +1058,13 @@ bool Widget::OnNativeWidgetActivationChanged(bool active) {
}
void Widget::OnNativeFocus() {
- WidgetFocusManager::GetInstance()->OnNativeFocusChanged(GetNativeView());
+ WidgetFocusManager::GetInstance(GetNativeWindow())
+ ->OnNativeFocusChanged(GetNativeView());
}
void Widget::OnNativeBlur() {
- WidgetFocusManager::GetInstance()->OnNativeFocusChanged(nullptr);
+ WidgetFocusManager::GetInstance(GetNativeWindow())
+ ->OnNativeFocusChanged(nullptr);
}
void Widget::OnNativeWidgetVisibilityChanging(bool visible) {
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index 24c23336a45..352e4fbfe64 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -2034,11 +2034,6 @@ TEST_F(WidgetWindowTitleTest, SetWindowTitleChanged_DesktopNativeWidget) {
#endif // !OS_CHROMEOS
TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
- // TODO: test uses GetContext(), which is not applicable to aura-mus.
- // http://crbug.com/663809.
- if (IsMus())
- return;
-
Widget* widget = new Widget;
Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_POPUP);
@@ -2049,10 +2044,14 @@ TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
widget->SetSize(gfx::Size(100, 100));
widget->Show();
- ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
+ ui::test::EventGenerator generator(
+ IsMus() ? widget->GetNativeWindow() : GetContext(),
+ widget->GetNativeWindow());
WidgetDeletionObserver deletion_observer(widget);
- generator.ClickLeftButton();
+ generator.PressLeftButton();
+ if (deletion_observer.IsWidgetAlive())
+ generator.ReleaseLeftButton();
EXPECT_FALSE(deletion_observer.IsWidgetAlive());
// Yay we did not crash!
@@ -4080,7 +4079,7 @@ class CompositingWidgetTest : public views::test::WidgetTest {
const Widget::InitParams::WindowOpacity opacity) {
for (const auto& widget_type : widget_types_) {
#if defined(OS_MACOSX)
- // Tooltips are native on Mac. See BridgedNativeWidget::Init.
+ // Tooltips are native on Mac. See BridgedNativeWidgetImpl::Init.
if (widget_type == Widget::InitParams::TYPE_TOOLTIP)
continue;
#elif defined(OS_WIN)
diff --git a/chromium/ui/views/widget/widget_utils_mac.mm b/chromium/ui/views/widget/widget_utils_mac.mm
index 58d0a437fb0..990e17faf2f 100644
--- a/chromium/ui/views/widget/widget_utils_mac.mm
+++ b/chromium/ui/views/widget/widget_utils_mac.mm
@@ -4,13 +4,13 @@
#include "ui/views/widget/widget_utils_mac.h"
-#import "ui/views/cocoa/bridged_native_widget.h"
+#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
namespace views {
gfx::Size GetWindowSizeForClientSize(Widget* widget, const gfx::Size& size) {
DCHECK(widget);
- return BridgedNativeWidget::GetWindowSizeForClientSize(
+ return BridgedNativeWidgetImpl::GetWindowSizeForClientSize(
widget->GetNativeWindow(), size);
}
diff --git a/chromium/ui/views/widget/window_reorderer.cc b/chromium/ui/views/widget/window_reorderer.cc
index 2f83b18fbd9..2f459a861d6 100644
--- a/chromium/ui/views/widget/window_reorderer.cc
+++ b/chromium/ui/views/widget/window_reorderer.cc
@@ -166,14 +166,13 @@ void WindowReorderer::ReorderChildWindows() {
// |view_with_layer_order| backwards and stack windows at the bottom so that
// windows not associated to a view are stacked above windows with an
// associated view.
- for (std::vector<View*>::reverse_iterator it = view_with_layer_order.rbegin();
+ for (auto it = view_with_layer_order.rbegin();
it != view_with_layer_order.rend(); ++it) {
View* view = *it;
ui::Layer* layer = view->layer();
aura::Window* window = NULL;
- std::map<View*, aura::Window*>::iterator hosted_window_it =
- hosted_windows.find(view);
+ auto hosted_window_it = hosted_windows.find(view);
if (hosted_window_it != hosted_windows.end()) {
window = hosted_window_it->second;
layer = window->layer();
diff --git a/chromium/ui/views/widget/window_reorderer_unittest.cc b/chromium/ui/views/widget/window_reorderer_unittest.cc
index 579e622ee73..faecf6bf9ab 100644
--- a/chromium/ui/views/widget/window_reorderer_unittest.cc
+++ b/chromium/ui/views/widget/window_reorderer_unittest.cc
@@ -39,9 +39,8 @@ void SetWindowAndLayerName(aura::Window* window, const std::string& name) {
// first) of |parent|. The format of the string is "name1 name2 name3 ...".
std::string ChildWindowNamesAsString(const aura::Window& parent) {
std::string names;
- typedef std::vector<aura::Window*> Windows;
- for (Windows::const_iterator it = parent.children().begin();
- it != parent.children().end(); ++it) {
+ for (auto it = parent.children().begin(); it != parent.children().end();
+ ++it) {
if (!names.empty())
names += " ";
names += (*it)->GetName();
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index 54eb0fcd0bf..9afbcf6ca30 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -1000,12 +1000,14 @@ void HWNDMessageHandler::OnBlur() {}
void HWNDMessageHandler::OnCaretBoundsChanged(
const ui::TextInputClient* client) {
- if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
- return;
-
if (!ax_system_caret_)
ax_system_caret_ = std::make_unique<ui::AXSystemCaretWin>(hwnd());
+ if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) {
+ ax_system_caret_->Hide();
+ return;
+ }
+
const gfx::Rect dip_caret_bounds(client->GetCaretBounds());
gfx::Rect caret_bounds =
display::win::ScreenWin::DIPToScreenRect(hwnd(), dip_caret_bounds);
@@ -1015,7 +1017,10 @@ void HWNDMessageHandler::OnCaretBoundsChanged(
}
void HWNDMessageHandler::OnTextInputStateChanged(
- const ui::TextInputClient* client) {}
+ const ui::TextInputClient* client) {
+ if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ OnCaretBoundsChanged(client);
+}
void HWNDMessageHandler::OnInputMethodDestroyed(
const ui::InputMethod* input_method) {
@@ -1586,8 +1591,7 @@ LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) {
base::Bind(&HWNDMessageHandler::OnSessionChange,
base::Unretained(this))));
- float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd());
- dpi_ = display::win::GetDPIFromScalingFactor(scale_factor);
+ dpi_ = display::win::ScreenWin::GetDPIForHWND(hwnd());
// TODO(beng): move more of NWW::OnCreate here.
return 0;
@@ -1642,7 +1646,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::ScreenWin::GetScaleFactorForDPI(dpi);
}
// The first WM_DPICHANGED originates from EnableChildWindowDpiMessage during
@@ -2967,8 +2971,8 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message,
event_type, touch_point, event_time,
ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
mapped_pointer_id, radius_x, radius_y, pressure,
- pointer_touch_info.orientation, 0.0f, 0.0f, 0.0f),
- ui::GetModifiersFromKeyState(), rotation_angle);
+ rotation_angle),
+ ui::GetModifiersFromKeyState());
event.latency()->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, event_time, 1);
diff --git a/chromium/ui/views/win/pen_event_processor.cc b/chromium/ui/views/win/pen_event_processor.cc
index b820c51be5e..e1429935534 100644
--- a/chromium/ui/views/win/pen_event_processor.cc
+++ b/chromium/ui/views/win/pen_event_processor.cc
@@ -56,12 +56,14 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateEvent(
// convert pressure into a float [0, 1]. The range of the pressure is
// [0, 1024] as specified on MSDN.
float pressure = static_cast<float>(pointer_pen_info.pressure) / 1024;
- float rotation = pointer_pen_info.rotation;
+ int rotation_angle = static_cast<int>(pointer_pen_info.rotation) % 180;
+ if (rotation_angle < 0)
+ rotation_angle += 180;
int tilt_x = pointer_pen_info.tiltX;
int tilt_y = pointer_pen_info.tiltY;
ui::PointerDetails pointer_details(
input_type, mapped_pointer_id, /* radius_x */ 0.0f, /* radius_y */ 0.0f,
- pressure, rotation, tilt_x, tilt_y, /* tangential_pressure */ 0.0f);
+ pressure, rotation_angle, tilt_x, tilt_y, /* tangential_pressure */ 0.0f);
// If the flag is disabled, we send mouse events for all pen inputs.
if (!direct_manipulation_enabled_) {
@@ -186,12 +188,9 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateTouchEvent(
const base::TimeTicks event_time = ui::EventTimeForNow();
- int rotation_angle = static_cast<int>(pointer_details.twist) % 180;
- if (rotation_angle < 0)
- rotation_angle += 180;
std::unique_ptr<ui::TouchEvent> event = std::make_unique<ui::TouchEvent>(
event_type, point, event_time, pointer_details,
- flags | ui::GetModifiersFromKeyState(), rotation_angle);
+ flags | ui::GetModifiersFromKeyState());
event->set_hovering(event_type == ui::ET_TOUCH_RELEASED);
event->latency()->AddLatencyNumberWithTimestamp(
ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, event_time, 1);
diff --git a/chromium/ui/views/window/custom_frame_view.cc b/chromium/ui/views/window/custom_frame_view.cc
index 0ae8ebd9ad3..01a5c58eb39 100644
--- a/chromium/ui/views/window/custom_frame_view.cc
+++ b/chromium/ui/views/window/custom_frame_view.cc
@@ -522,8 +522,7 @@ void CustomFrameView::LayoutWindowControls() {
button_order->trailing_buttons();
ImageButton* button = NULL;
- for (std::vector<views::FrameButton>::const_iterator it =
- leading_buttons.begin(); it != leading_buttons.end(); ++it) {
+ for (auto it = leading_buttons.begin(); it != leading_buttons.end(); ++it) {
button = GetImageButton(*it);
if (!button)
continue;
@@ -538,8 +537,8 @@ void CustomFrameView::LayoutWindowControls() {
// Trailing buttions are laid out in a RTL fashion
next_button_x = width() - FrameBorderThickness();
- for (std::vector<views::FrameButton>::const_reverse_iterator it =
- trailing_buttons.rbegin(); it != trailing_buttons.rend(); ++it) {
+ for (auto it = trailing_buttons.rbegin(); it != trailing_buttons.rend();
+ ++it) {
button = GetImageButton(*it);
if (!button)
continue;
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index 40cc9f35cfa..7c5c56f4c27 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -17,6 +17,7 @@
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/event_utils.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/style/platform_style.h"
@@ -164,6 +165,13 @@ gfx::Size DialogClientView::GetMaximumSize() const {
return max_size;
}
+void DialogClientView::VisibilityChanged(View* starting_from, bool is_visible) {
+ ClientView::VisibilityChanged(starting_from, is_visible);
+
+ if (is_visible)
+ view_shown_time_stamp_ = base::TimeTicks::Now();
+}
+
void DialogClientView::Layout() {
button_row_container_->SetSize(
gfx::Size(width(), button_row_container_->GetHeightForWidth(width())));
@@ -234,6 +242,9 @@ void DialogClientView::ButtonPressed(Button* sender, const ui::Event& event) {
if (!GetDialogDelegate())
return;
+ if (IsPossiblyUnintendedInteraction(view_shown_time_stamp_, event))
+ return;
+
if (sender == ok_button_)
AcceptWindow();
else if (sender == cancel_button_)
@@ -242,6 +253,10 @@ void DialogClientView::ButtonPressed(Button* sender, const ui::Event& event) {
NOTREACHED();
}
+void DialogClientView::ResetViewShownTimeStampForTesting() {
+ view_shown_time_stamp_ = base::TimeTicks();
+}
+
////////////////////////////////////////////////////////////////////////////////
// DialogClientView, private:
diff --git a/chromium/ui/views/window/dialog_client_view.h b/chromium/ui/views/window/dialog_client_view.h
index 108d9776d0b..3981e4f8b6c 100644
--- a/chromium/ui/views/window/dialog_client_view.h
+++ b/chromium/ui/views/window/dialog_client_view.h
@@ -7,6 +7,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/time/time.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/window/client_view.h"
@@ -54,6 +55,7 @@ class VIEWS_EXPORT DialogClientView : public ClientView,
gfx::Size CalculatePreferredSize() const override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
+ void VisibilityChanged(View* starting_from, bool is_visible) override;
void Layout() override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
@@ -66,6 +68,11 @@ class VIEWS_EXPORT DialogClientView : public ClientView,
void set_minimum_size(const gfx::Size& size) { minimum_size_ = size; }
+ // Resets the time when view has been shown. Tests may need to call this
+ // method if they use events that could be otherwise treated as unintended.
+ // See IsPossiblyUnintendedInteraction().
+ void ResetViewShownTimeStampForTesting();
+
private:
enum {
// The number of buttons that DialogClientView can support.
@@ -134,6 +141,9 @@ class VIEWS_EXPORT DialogClientView : public ClientView,
// SetupLayout(). Everything will be manually updated afterwards.
bool adding_or_removing_views_ = false;
+ // Time when view has been shown.
+ base::TimeTicks view_shown_time_stamp_;
+
DISALLOW_COPY_AND_ASSIGN(DialogClientView);
};
diff --git a/chromium/ui/views/window/dialog_client_view_unittest.cc b/chromium/ui/views/window/dialog_client_view_unittest.cc
index d3f0d56cf04..4c4e67e7dbc 100644
--- a/chromium/ui/views/window/dialog_client_view_unittest.cc
+++ b/chromium/ui/views/window/dialog_client_view_unittest.cc
@@ -8,11 +8,16 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "ui/base/ui_base_types.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/event.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/metrics.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/test/test_layout_provider.h"
#include "ui/views/test/test_views.h"
@@ -505,4 +510,24 @@ TEST_F(DialogClientViewTest, FocusChangingButtons) {
EXPECT_EQ(nullptr, focus_manager->GetFocusedView());
}
+// Ensures that clicks are ignored for short time after view has been shown.
+TEST_F(DialogClientViewTest, IgnorePossiblyUnintendedClicks) {
+ widget()->Show();
+ SetDialogButtons(ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK);
+
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+ client_view()->ButtonPressed(client_view()->ok_button(), mouse_event);
+ client_view()->ButtonPressed(client_view()->cancel_button(), mouse_event);
+ EXPECT_FALSE(widget()->IsClosed());
+
+ client_view()->ButtonPressed(
+ client_view()->cancel_button(),
+ ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+ ui::EventTimeForNow() + base::TimeDelta::FromMilliseconds(
+ GetDoubleClickInterval()),
+ ui::EF_NONE, ui::EF_NONE));
+ EXPECT_TRUE(widget()->IsClosed());
+}
+
} // namespace views