summaryrefslogtreecommitdiff
path: root/chromium/ui
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui')
-rw-r--r--chromium/ui/accessibility/BUILD.gn43
-rw-r--r--chromium/ui/accessibility/accessibility_switches.cc29
-rw-r--r--chromium/ui/accessibility/accessibility_switches.h22
-rw-r--r--chromium/ui/accessibility/ax_action_data.h6
-rw-r--r--chromium/ui/accessibility/ax_assistant_structure.cc16
-rw-r--r--chromium/ui/accessibility/ax_enum_util.cc90
-rw-r--r--chromium/ui/accessibility/ax_enums.mojom27
-rw-r--r--chromium/ui/accessibility/ax_event_generator.cc5
-rw-r--r--chromium/ui/accessibility/ax_event_generator_unittest.cc15
-rw-r--r--chromium/ui/accessibility/ax_language_info.h49
-rw-r--r--chromium/ui/accessibility/ax_language_info_unittest.cc70
-rw-r--r--chromium/ui/accessibility/ax_node.cc570
-rw-r--r--chromium/ui/accessibility/ax_node.h116
-rw-r--r--chromium/ui/accessibility/ax_node_data.cc226
-rw-r--r--chromium/ui/accessibility/ax_node_data.h135
-rw-r--r--chromium/ui/accessibility/ax_node_data_unittest.cc30
-rw-r--r--chromium/ui/accessibility/ax_node_position_unittest.cc6
-rw-r--r--chromium/ui/accessibility/ax_relative_bounds.cc3
-rw-r--r--chromium/ui/accessibility/ax_relative_bounds.h6
-rw-r--r--chromium/ui/accessibility/ax_role_properties.cc252
-rw-r--r--chromium/ui/accessibility/ax_role_properties.h92
-rw-r--r--chromium/ui/accessibility/ax_table_fuzzer.cc183
-rw-r--r--chromium/ui/accessibility/ax_table_info.cc280
-rw-r--r--chromium/ui/accessibility/ax_table_info.h28
-rw-r--r--chromium/ui/accessibility/ax_table_info_unittest.cc507
-rw-r--r--chromium/ui/accessibility/ax_tree.cc58
-rw-r--r--chromium/ui/accessibility/ax_tree.h36
-rw-r--r--chromium/ui/accessibility/ax_tree_combiner.cc5
-rw-r--r--chromium/ui/accessibility/ax_tree_unittest.cc497
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb2
-rw-r--r--chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb14
-rw-r--r--chromium/ui/accessibility/fuzz_corpus/ax_table_fuzzer_seed.binbin0 -> 86 bytes
-rw-r--r--chromium/ui/accessibility/mojom/BUILD.gn1
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data.mojom7
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data.typemap4
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc22
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h10
-rw-r--r--chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc27
-rw-r--r--chromium/ui/accessibility/mojom/ax_relative_bounds.mojom15
-rw-r--r--chromium/ui/accessibility/mojom/ax_relative_bounds.typemap19
-rw-r--r--chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.cc35
-rw-r--r--chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h32
-rw-r--r--chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc30
-rw-r--r--chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc1
-rw-r--r--chromium/ui/accessibility/mojom/typemaps.gni1
-rw-r--r--chromium/ui/accessibility/platform/DEPS5
-rw-r--r--chromium/ui/accessibility/platform/atk_util_auralinux.cc56
-rw-r--r--chromium/ui/accessibility/platform/atk_util_auralinux.h28
-rw-r--r--chromium/ui/accessibility/platform/atk_util_auralinux_unittest.cc79
-rw-r--r--chromium/ui/accessibility/platform/atk_util_auralinux_x11.cc60
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node.cc2
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc163
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux.h28
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc77
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.cc102
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_base.h22
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate.h22
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc20
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h20
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_mac.mm5
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win.cc238
-rw-r--r--chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc16
-rw-r--r--chromium/ui/accessibility/platform/ax_system_caret_win.cc12
-rw-r--r--chromium/ui/accessibility/platform/ax_unique_id.cc27
-rw-r--r--chromium/ui/accessibility/platform/ax_unique_id.h7
-rw-r--r--chromium/ui/accessibility/platform/ax_unique_id_unittest.cc4
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.cc113
-rw-r--r--chromium/ui/accessibility/platform/test_ax_node_wrapper.h12
-rw-r--r--chromium/ui/android/BUILD.gn7
-rw-r--r--chromium/ui/android/delegated_frame_host_android.cc184
-rw-r--r--chromium/ui/android/delegated_frame_host_android.h32
-rw-r--r--chromium/ui/android/delegated_frame_host_android_unittest.cc65
-rw-r--r--chromium/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java64
-rw-r--r--chromium/ui/android/resources/resource_manager_impl.cc7
-rw-r--r--chromium/ui/android/resources/resource_manager_impl_unittest.cc2
-rw-r--r--chromium/ui/android/window_android.cc64
-rw-r--r--chromium/ui/android/window_android.h8
-rw-r--r--chromium/ui/aura/BUILD.gn50
-rw-r--r--chromium/ui/aura/DEPS1
-rw-r--r--chromium/ui/aura/client/aura_constants.cc2
-rw-r--r--chromium/ui/aura/client/aura_constants.h13
-rw-r--r--chromium/ui/aura/env.cc121
-rw-r--r--chromium/ui/aura/env.h35
-rw-r--r--chromium/ui/aura/env_observer.h3
-rw-r--r--chromium/ui/aura/gestures/gesture_recognizer_unittest.cc2
-rw-r--r--chromium/ui/aura/hit_test_data_provider_aura.cc141
-rw-r--r--chromium/ui/aura/hit_test_data_provider_aura.h43
-rw-r--r--chromium/ui/aura/hit_test_data_provider_aura_unittest.cc339
-rw-r--r--chromium/ui/aura/local/window_port_local.cc76
-rw-r--r--chromium/ui/aura/local/window_port_local.h11
-rw-r--r--chromium/ui/aura/mus/DEPS1
-rw-r--r--chromium/ui/aura/mus/client_surface_embedder.cc13
-rw-r--r--chromium/ui/aura/mus/client_surface_embedder.h4
-rw-r--r--chromium/ui/aura/mus/embed_root.h2
-rw-r--r--chromium/ui/aura/mus/focus_synchronizer.cc13
-rw-r--r--chromium/ui/aura/mus/gesture_recognizer_impl_mus.cc73
-rw-r--r--chromium/ui/aura/mus/gesture_recognizer_impl_mus.h51
-rw-r--r--chromium/ui/aura/mus/gesture_synchronizer_unittest.cc36
-rw-r--r--chromium/ui/aura/mus/input_method_mus.cc3
-rw-r--r--chromium/ui/aura/mus/mus_context_factory.cc43
-rw-r--r--chromium/ui/aura/mus/mus_context_factory.h8
-rw-r--r--chromium/ui/aura/mus/property_converter.cc8
-rw-r--r--chromium/ui/aura/mus/property_utils.cc34
-rw-r--r--chromium/ui/aura/mus/property_utils.h10
-rw-r--r--chromium/ui/aura/mus/text_input_client_impl.cc41
-rw-r--r--chromium/ui/aura/mus/window_mus.h10
-rw-r--r--chromium/ui/aura/mus/window_port_mus.cc196
-rw-r--r--chromium/ui/aura/mus/window_port_mus.h43
-rw-r--r--chromium/ui/aura/mus/window_port_mus_unittest.cc110
-rw-r--r--chromium/ui/aura/mus/window_tree_client.cc176
-rw-r--r--chromium/ui/aura/mus/window_tree_client.h48
-rw-r--r--chromium/ui/aura/mus/window_tree_client_delegate.h7
-rw-r--r--chromium/ui/aura/mus/window_tree_client_observer.h10
-rw-r--r--chromium/ui/aura/mus/window_tree_client_unittest.cc328
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus.cc10
-rw-r--r--chromium/ui/aura/mus/window_tree_host_mus.h7
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_unittest.cc158
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win.cc540
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win.h217
-rw-r--r--chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc211
-rw-r--r--chromium/ui/aura/test/ui_controls_factory_ozone.cc80
-rw-r--r--chromium/ui/aura/window.cc65
-rw-r--r--chromium/ui/aura/window.h57
-rw-r--r--chromium/ui/aura/window_delegate.h11
-rw-r--r--chromium/ui/aura/window_event_dispatcher.cc13
-rw-r--r--chromium/ui/aura/window_event_dispatcher.h2
-rw-r--r--chromium/ui/aura/window_event_dispatcher_observer.h6
-rw-r--r--chromium/ui/aura/window_event_dispatcher_unittest.cc42
-rw-r--r--chromium/ui/aura/window_observer.cc18
-rw-r--r--chromium/ui/aura/window_observer.h34
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.cc229
-rw-r--r--chromium/ui/aura/window_occlusion_tracker.h102
-rw-r--r--chromium/ui/aura/window_occlusion_tracker_unittest.cc911
-rw-r--r--chromium/ui/aura/window_port.cc2
-rw-r--r--chromium/ui/aura/window_port.h27
-rw-r--r--chromium/ui/aura/window_port_for_shutdown.cc13
-rw-r--r--chromium/ui/aura/window_port_for_shutdown.h12
-rw-r--r--chromium/ui/aura/window_targeter.cc39
-rw-r--r--chromium/ui/aura/window_targeter.h4
-rw-r--r--chromium/ui/aura/window_tree_host.cc82
-rw-r--r--chromium/ui/aura/window_tree_host.h39
-rw-r--r--chromium/ui/aura/window_tree_host_observer.h6
-rw-r--r--chromium/ui/aura/window_tree_host_platform.cc28
-rw-r--r--chromium/ui/aura/window_tree_host_platform.h17
-rw-r--r--chromium/ui/aura/window_tree_host_unittest.cc35
-rw-r--r--chromium/ui/aura/window_unittest.cc28
-rw-r--r--chromium/ui/aura_extra/BUILD.gn15
-rw-r--r--chromium/ui/aura_extra/DEPS3
-rw-r--r--chromium/ui/aura_extra/skia_vector_resource.cc83
-rw-r--r--chromium/ui/aura_extra/skia_vector_resource.h24
-rw-r--r--chromium/ui/base/BUILD.gn40
-rw-r--r--chromium/ui/base/accelerators/accelerator.cc3
-rw-r--r--chromium/ui/base/accelerators/accelerator_unittest.cc8
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util.cc9
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util.h5
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util_linux.cc12
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h6
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util_linux_unittest.cc25
-rw-r--r--chromium/ui/base/accelerators/menu_label_accelerator_util_unittest.cc26
-rw-r--r--chromium/ui/base/base_window.h9
-rw-r--r--chromium/ui/base/class_property.cc2
-rw-r--r--chromium/ui/base/clipboard/clipboard.cc18
-rw-r--r--chromium/ui/base/clipboard/clipboard.h4
-rw-r--r--chromium/ui/base/clipboard/clipboard_android.cc6
-rw-r--r--chromium/ui/base/clipboard/clipboard_aura.cc85
-rw-r--r--chromium/ui/base/clipboard/clipboard_aura.h5
-rw-r--r--chromium/ui/base/clipboard/clipboard_aurax11.cc33
-rw-r--r--chromium/ui/base/clipboard/clipboard_mac.mm41
-rw-r--r--chromium/ui/base/clipboard/clipboard_test_template.h155
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_mac.h13
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_mac.mm27
-rw-r--r--chromium/ui/base/clipboard/clipboard_util_mac_unittest.mm14
-rw-r--r--chromium/ui/base/clipboard/clipboard_win.cc12
-rw-r--r--chromium/ui/base/cocoa/accessibility_focus_overrider.h48
-rw-r--r--chromium/ui/base/cocoa/accessibility_focus_overrider.mm62
-rw-r--r--chromium/ui/base/cocoa/bubble_closer.h3
-rw-r--r--chromium/ui/base/cocoa/bubble_closer.mm2
-rw-r--r--chromium/ui/base/cocoa/constrained_window/constrained_window_animation.h2
-rw-r--r--chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm4
-rw-r--r--chromium/ui/base/cocoa/find_pasteboard.mm5
-rw-r--r--chromium/ui/base/cocoa/focus_tracker.h2
-rw-r--r--chromium/ui/base/cocoa/focus_tracker.mm2
-rw-r--r--chromium/ui/base/cocoa/focus_window_set.mm8
-rw-r--r--chromium/ui/base/cocoa/hover_button.h84
-rw-r--r--chromium/ui/base/cocoa/hover_button.mm210
-rw-r--r--chromium/ui/base/cocoa/hover_button_unittest.mm200
-rw-r--r--chromium/ui/base/cocoa/hover_image_button.h37
-rw-r--r--chromium/ui/base/cocoa/hover_image_button.mm52
-rw-r--r--chromium/ui/base/cocoa/hover_image_button_unittest.mm48
-rw-r--r--chromium/ui/base/cocoa/menu_controller.h9
-rw-r--r--chromium/ui/base/cocoa/menu_controller.mm20
-rw-r--r--chromium/ui/base/cocoa/menu_controller_unittest.mm6
-rw-r--r--chromium/ui/base/cocoa/remote_accessibility_api.h35
-rw-r--r--chromium/ui/base/cocoa/remote_accessibility_api.mm27
-rw-r--r--chromium/ui/base/cocoa/remote_layer_api.h4
-rw-r--r--chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm8
-rw-r--r--chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.cc108
-rw-r--r--chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h90
-rw-r--r--chromium/ui/base/dragdrop/cocoa_dnd_util.mm4
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc24
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm2
-rw-r--r--chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc4
-rw-r--r--chromium/ui/base/idle/idle_mac.mm2
-rw-r--r--chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc2
-rw-r--r--chromium/ui/base/ime/ime_text_span.h3
-rw-r--r--chromium/ui/base/ime/text_input_flags.h3
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc317
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h29
-rw-r--r--chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc21
-rw-r--r--chromium/ui/base/ime/win/tsf_bridge.cc24
-rw-r--r--chromium/ui/base/ime/win/tsf_input_scope.cc2
-rw-r--r--chromium/ui/base/l10n/l10n_util.cc4
-rw-r--r--chromium/ui/base/l10n/l10n_util_mac.mm2
-rw-r--r--chromium/ui/base/layout.cc2
-rw-r--r--chromium/ui/base/material_design/material_design_controller.cc162
-rw-r--r--chromium/ui/base/material_design/material_design_controller.h60
-rw-r--r--chromium/ui/base/material_design/material_design_controller_observer.h2
-rw-r--r--chromium/ui/base/material_design/material_design_controller_unittest.cc190
-rw-r--r--chromium/ui/base/models/menu_model.h3
-rw-r--r--chromium/ui/base/models/simple_menu_model.cc9
-rw-r--r--chromium/ui/base/models/simple_menu_model.h3
-rw-r--r--chromium/ui/base/mojo/clipboard_client.cc8
-rw-r--r--chromium/ui/base/page_transition_types.h2
-rw-r--r--chromium/ui/base/pointer/OWNERS (renamed from chromium/ui/base/touch/OWNERS)0
-rw-r--r--chromium/ui/base/pointer/pointer_device.cc (renamed from chromium/ui/base/touch/touch_device.cc)2
-rw-r--r--chromium/ui/base/pointer/pointer_device.h (renamed from chromium/ui/base/touch/touch_device.h)9
-rw-r--r--chromium/ui/base/pointer/pointer_device_android.cc (renamed from chromium/ui/base/touch/touch_device_android.cc)4
-rw-r--r--chromium/ui/base/pointer/pointer_device_ios.cc (renamed from chromium/ui/base/touch/touch_device_ios.cc)2
-rw-r--r--chromium/ui/base/pointer/pointer_device_linux.cc (renamed from chromium/ui/base/touch/touch_device_linux.cc)2
-rw-r--r--chromium/ui/base/pointer/pointer_device_util.cc (renamed from chromium/ui/base/touch/touch_device_util.cc)4
-rw-r--r--chromium/ui/base/pointer/pointer_device_win.cc (renamed from chromium/ui/base/touch/touch_device_win.cc)4
-rw-r--r--chromium/ui/base/pointer/touch_editing_controller.cc (renamed from chromium/ui/base/touch/touch_editing_controller.cc)2
-rw-r--r--chromium/ui/base/pointer/touch_editing_controller.h (renamed from chromium/ui/base/touch/touch_editing_controller.h)15
-rw-r--r--chromium/ui/base/resource/resource_bundle.cc4
-rw-r--r--chromium/ui/base/resource/resource_bundle_mac.mm2
-rw-r--r--chromium/ui/base/resource/resource_bundle_unittest.cc25
-rw-r--r--chromium/ui/base/ui_base_features.cc46
-rw-r--r--chromium/ui/base/ui_base_features.h22
-rw-r--r--chromium/ui/base/ui_base_switches.cc20
-rw-r--r--chromium/ui/base/ui_base_switches.h8
-rw-r--r--chromium/ui/base/win/mouse_wheel_util.cc3
-rw-r--r--chromium/ui/base/win/open_file_name_win.cc165
-rw-r--r--chromium/ui/base/win/open_file_name_win.h80
-rw-r--r--chromium/ui/base/win/open_file_name_win_unittest.cc256
-rw-r--r--chromium/ui/base/win/shell.cc4
-rw-r--r--chromium/ui/base/work_area_watcher_observer.h25
-rw-r--r--chromium/ui/base/x/BUILD.gn8
-rw-r--r--chromium/ui/base/x/x11_display_util.cc221
-rw-r--r--chromium/ui/base/x/x11_display_util.h32
-rw-r--r--chromium/ui/base/x/x11_util.cc42
-rw-r--r--chromium/ui/base/x/x11_util.h4
-rw-r--r--chromium/ui/compositor/compositor.cc73
-rw-r--r--chromium/ui/compositor/compositor.h36
-rw-r--r--chromium/ui/compositor/compositor_lock.cc21
-rw-r--r--chromium/ui/compositor/compositor_lock.h16
-rw-r--r--chromium/ui/compositor/compositor_switches.cc4
-rw-r--r--chromium/ui/compositor/compositor_switches.h1
-rw-r--r--chromium/ui/compositor/compositor_unittest.cc7
-rw-r--r--chromium/ui/compositor/host/host_context_factory_private.cc11
-rw-r--r--chromium/ui/compositor/layer.cc96
-rw-r--r--chromium/ui/compositor/layer.h27
-rw-r--r--chromium/ui/compositor/layer_unittest.cc113
-rw-r--r--chromium/ui/compositor/recyclable_compositor_mac.cc7
-rw-r--r--chromium/ui/compositor/test/test_compositor_host_ozone.cc10
-rw-r--r--chromium/ui/compositor_extra/shadow.cc1
-rw-r--r--chromium/ui/display/display_observer.h2
-rw-r--r--chromium/ui/display/mac/screen_mac.mm20
-rw-r--r--chromium/ui/display/manager/display_manager.cc79
-rw-r--r--chromium/ui/display/manager/display_manager.h13
-rw-r--r--chromium/ui/display/manager/display_manager_utilities.cc2
-rw-r--r--chromium/ui/display/unified_desktop_utils.h7
-rw-r--r--chromium/ui/display/util/BUILD.gn7
-rw-r--r--chromium/ui/events/BUILD.gn32
-rw-r--r--chromium/ui/events/android/keyboard_hook_android.cc8
-rw-r--r--chromium/ui/events/blink/blink_event_util.cc10
-rw-r--r--chromium/ui/events/blink/blink_features.cc11
-rw-r--r--chromium/ui/events/blink/blink_features.h12
-rw-r--r--chromium/ui/events/blink/event_with_callback.cc6
-rw-r--r--chromium/ui/events/blink/input_handler_proxy.cc34
-rw-r--r--chromium/ui/events/blink/input_handler_proxy.h4
-rw-r--r--chromium/ui/events/blink/input_handler_proxy_unittest.cc103
-rw-r--r--chromium/ui/events/blink/prediction/empty_predictor.cc4
-rw-r--r--chromium/ui/events/blink/prediction/empty_predictor.h2
-rw-r--r--chromium/ui/events/blink/prediction/input_predictor.h3
-rw-r--r--chromium/ui/events/blink/prediction/kalman_predictor.cc10
-rw-r--r--chromium/ui/events/blink/prediction/kalman_predictor.h4
-rw-r--r--chromium/ui/events/blink/prediction/least_squares_predictor.cc10
-rw-r--r--chromium/ui/events/blink/prediction/least_squares_predictor.h4
-rw-r--r--chromium/ui/events/blink/scroll_predictor.cc75
-rw-r--r--chromium/ui/events/blink/scroll_predictor.h33
-rw-r--r--chromium/ui/events/blink/scroll_predictor_unittest.cc87
-rw-r--r--chromium/ui/events/blink/web_input_event_builders_win.cc3
-rw-r--r--chromium/ui/events/devices/device_util_linux.cc5
-rw-r--r--chromium/ui/events/devices/input_device_manager.cc22
-rw-r--r--chromium/ui/events/devices/input_device_manager.h10
-rw-r--r--chromium/ui/events/devices/x11/device_data_manager_x11.cc2
-rw-r--r--chromium/ui/events/devices/x11/touch_factory_x11.cc2
-rw-r--r--chromium/ui/events/event.cc278
-rw-r--r--chromium/ui/events/event.h84
-rw-r--r--chromium/ui/events/event_constants.h10
-rw-r--r--chromium/ui/events/event_dispatcher.cc36
-rw-r--r--chromium/ui/events/event_dispatcher.h2
-rw-r--r--chromium/ui/events/event_dispatcher_unittest.cc68
-rw-r--r--chromium/ui/events/event_handler.cc6
-rw-r--r--chromium/ui/events/event_handler.h15
-rw-r--r--chromium/ui/events/event_observer.h35
-rw-r--r--chromium/ui/events/event_processor_unittest.cc4
-rw-r--r--chromium/ui/events/event_target.cc20
-rw-r--r--chromium/ui/events/event_target_unittest.cc24
-rw-r--r--chromium/ui/events/event_unittest.cc293
-rw-r--r--chromium/ui/events/event_utils.cc8
-rw-r--r--chromium/ui/events/events_exports.cc (renamed from chromium/ui/views/views_exports.cc)6
-rw-r--r--chromium/ui/events/gesture_detection/gesture_configuration.cc1
-rw-r--r--chromium/ui/events/gesture_detection/gesture_configuration.h11
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer.h8
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl.cc26
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl.h2
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc3
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl_mac.h2
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_impl_unittest.cc15
-rw-r--r--chromium/ui/events/gestures/gesture_recognizer_observer.h9
-rw-r--r--chromium/ui/events/keyboard_hook.h10
-rw-r--r--chromium/ui/events/keyboard_hook_base.cc5
-rw-r--r--chromium/ui/events/keyboard_hook_base.h4
-rw-r--r--chromium/ui/events/keycodes/dom/dom_keyboard_layout.cc18
-rw-r--r--chromium/ui/events/keycodes/dom/dom_keyboard_layout.h2
-rw-r--r--chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_base.cc3
-rw-r--r--chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc27
-rw-r--r--chromium/ui/events/mac/keyboard_hook_mac.mm8
-rw-r--r--chromium/ui/events/mojo/event.mojom54
-rw-r--r--chromium/ui/events/mojo/event_constants.mojom15
-rw-r--r--chromium/ui/events/mojo/event_struct_traits.cc185
-rw-r--r--chromium/ui/events/mojo/event_struct_traits.h1
-rw-r--r--chromium/ui/events/mojo/struct_traits_unittest.cc144
-rw-r--r--chromium/ui/events/ozone/device/device_manager_manual.cc43
-rw-r--r--chromium/ui/events/ozone/device/device_manager_manual.h14
-rwxr-xr-xchromium/ui/events/ozone/evdev/capture_device_capabilities.py22
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.cc48
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info.h13
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_info_unittest.cc89
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_test_util.cc170
-rw-r--r--chromium/ui/events/ozone/evdev/event_device_test_util.h2
-rw-r--r--chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc148
-rw-r--r--chromium/ui/events/ozone/keyboard_hook_ozone.cc8
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.cc2
-rw-r--r--chromium/ui/events/platform/x11/x11_event_source.h5
-rw-r--r--chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc2
-rw-r--r--chromium/ui/events/win/events_win_utils.cc2
-rw-r--r--chromium/ui/events/win/keyboard_hook_win.h52
-rw-r--r--chromium/ui/events/win/keyboard_hook_win_base.cc81
-rw-r--r--chromium/ui/events/win/keyboard_hook_win_base.h74
-rw-r--r--chromium/ui/events/win/media_keyboard_hook_win.cc139
-rw-r--r--chromium/ui/events/win/media_keyboard_hook_win_interactive_test.cc120
-rw-r--r--chromium/ui/events/win/media_keyboard_hook_win_unittest.cc206
-rw-r--r--chromium/ui/events/win/modifier_keyboard_hook_win.cc (renamed from chromium/ui/events/win/keyboard_hook_win.cc)131
-rw-r--r--chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc (renamed from chromium/ui/events/win/keyboard_hook_win_unittest.cc)87
-rw-r--r--chromium/ui/events/x/events_x.cc4
-rw-r--r--chromium/ui/events/x/events_x_unittest.cc63
-rw-r--r--chromium/ui/events/x/events_x_utils.cc94
-rw-r--r--chromium/ui/events/x/events_x_utils.h14
-rw-r--r--chromium/ui/events/x/keyboard_hook_x11.cc8
-rw-r--r--chromium/ui/file_manager/BUILD.gn9
-rw-r--r--chromium/ui/file_manager/audio_player/elements/BUILD.gn2
-rw-r--r--chromium/ui/file_manager/audio_player/js/BUILD.gn2
-rw-r--r--chromium/ui/file_manager/base/js/BUILD.gn57
-rw-r--r--chromium/ui/file_manager/externs/BUILD.gn2
-rw-r--r--chromium/ui/file_manager/file_manager/background/js/BUILD.gn225
-rw-r--r--chromium/ui/file_manager/file_manager/common/js/BUILD.gn94
-rw-r--r--chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn50
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn132
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn43
-rw-r--r--chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn77
-rw-r--r--chromium/ui/file_manager/file_manager/test/BUILD.gn47
-rw-r--r--chromium/ui/file_manager/file_manager/test/js/BUILD.gn2
-rw-r--r--chromium/ui/file_manager/gallery/js/BUILD.gn41
-rw-r--r--chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn11
-rw-r--r--chromium/ui/file_manager/image_loader/BUILD.gn17
-rw-r--r--chromium/ui/file_manager/video_player/js/BUILD.gn3
-rw-r--r--chromium/ui/file_manager/video_player/js/cast/BUILD.gn2
-rw-r--r--chromium/ui/gfx/BUILD.gn28
-rw-r--r--chromium/ui/gfx/OWNERS7
-rw-r--r--chromium/ui/gfx/animation/animation_mac.mm4
-rw-r--r--chromium/ui/gfx/blit_unittest.cc18
-rw-r--r--chromium/ui/gfx/canvas.cc6
-rw-r--r--chromium/ui/gfx/canvas.h13
-rw-r--r--chromium/ui/gfx/canvas_skia.cc4
-rw-r--r--chromium/ui/gfx/canvas_unittest_mac.mm4
-rw-r--r--chromium/ui/gfx/client_native_pixmap_factory.cc13
-rw-r--r--chromium/ui/gfx/client_native_pixmap_factory.h13
-rw-r--r--chromium/ui/gfx/color_palette.h1
-rw-r--r--chromium/ui/gfx/color_space.cc10
-rw-r--r--chromium/ui/gfx/color_space.h3
-rw-r--r--chromium/ui/gfx/color_space_win.cc2
-rw-r--r--chromium/ui/gfx/color_transform_unittest.cc7
-rw-r--r--chromium/ui/gfx/color_utils.cc2
-rw-r--r--chromium/ui/gfx/color_utils.h2
-rw-r--r--chromium/ui/gfx/color_utils_unittest.cc4
-rw-r--r--chromium/ui/gfx/font_fallback_win.cc96
-rw-r--r--chromium/ui/gfx/font_fallback_win.h46
-rw-r--r--chromium/ui/gfx/font_fallback_win_unittest.cc60
-rw-r--r--chromium/ui/gfx/font_list_unittest.cc13
-rw-r--r--chromium/ui/gfx/font_names_testing.cc2
-rw-r--r--chromium/ui/gfx/font_render_params.h2
-rw-r--r--chromium/ui/gfx/font_render_params_fuchsia.cc4
-rw-r--r--chromium/ui/gfx/font_render_params_linux.cc4
-rw-r--r--chromium/ui/gfx/font_render_params_linux_unittest.cc18
-rw-r--r--chromium/ui/gfx/font_unittest.cc10
-rw-r--r--chromium/ui/gfx/geometry/insets.h5
-rw-r--r--chromium/ui/gfx/geometry/insets_unittest.cc24
-rw-r--r--chromium/ui/gfx/gfx_paths.cc44
-rw-r--r--chromium/ui/gfx/gfx_paths.h29
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.h4
-rw-r--r--chromium/ui/gfx/harfbuzz_font_skia.cc57
-rw-r--r--chromium/ui/gfx/icon_util_unittest.cc29
-rw-r--r--chromium/ui/gfx/image/image.cc40
-rw-r--r--chromium/ui/gfx/image/image.h23
-rw-r--r--chromium/ui/gfx/image/image_family.cc3
-rw-r--r--chromium/ui/gfx/image/image_generic.cc2
-rw-r--r--chromium/ui/gfx/image/image_ios.mm6
-rw-r--r--chromium/ui/gfx/image/image_mac.mm2
-rw-r--r--chromium/ui/gfx/image/image_mac_unittest.mm6
-rw-r--r--chromium/ui/gfx/image/image_platform.h4
-rw-r--r--chromium/ui/gfx/image/image_unittest.cc55
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.cc6
-rw-r--r--chromium/ui/gfx/ipc/gfx_param_traits_macros.h2
-rw-r--r--chromium/ui/gfx/linux/OWNERS1
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc63
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h5
-rw-r--r--chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc89
-rw-r--r--chromium/ui/gfx/linux_font_delegate.cc23
-rw-r--r--chromium/ui/gfx/mojo/BUILD.gn4
-rw-r--r--chromium/ui/gfx/mojo/OWNERS2
-rw-r--r--chromium/ui/gfx/mojo/accelerated_widget_struct_traits.h4
-rw-r--r--chromium/ui/gfx/mojo/buffer_types.mojom43
-rw-r--r--chromium/ui/gfx/mojo/buffer_types_struct_traits.cc240
-rw-r--r--chromium/ui/gfx/mojo/buffer_types_struct_traits.h77
-rw-r--r--chromium/ui/gfx/mojo/struct_traits_unittest.cc23
-rw-r--r--chromium/ui/gfx/mojo/swap_result.typemap2
-rw-r--r--chromium/ui/gfx/mojo/swap_result_mojom_traits.h (renamed from chromium/ui/gfx/mojo/swap_result_enum_traits.h)6
-rw-r--r--chromium/ui/gfx/native_widget_types.h76
-rw-r--r--chromium/ui/gfx/paint_throbber.cc48
-rw-r--r--chromium/ui/gfx/paint_throbber.h20
-rw-r--r--chromium/ui/gfx/path.cc16
-rw-r--r--chromium/ui/gfx/path.h17
-rw-r--r--chromium/ui/gfx/platform_font_fuchsia.cc26
-rw-r--r--chromium/ui/gfx/platform_font_skia.cc (renamed from chromium/ui/gfx/platform_font_linux.cc)139
-rw-r--r--chromium/ui/gfx/platform_font_skia.h (renamed from chromium/ui/gfx/platform_font_linux.h)52
-rw-r--r--chromium/ui/gfx/platform_font_skia_unittest.cc (renamed from chromium/ui/gfx/platform_font_linux_unittest.cc)73
-rw-r--r--chromium/ui/gfx/platform_font_win.cc2
-rw-r--r--chromium/ui/gfx/platform_font_win.h5
-rw-r--r--chromium/ui/gfx/render_text.cc8
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.cc159
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.h4
-rw-r--r--chromium/ui/gfx/render_text_unittest.cc756
-rw-r--r--chromium/ui/gfx/selection_model.cc7
-rw-r--r--chromium/ui/gfx/selection_model.h4
-rw-r--r--chromium/ui/gfx/skia_font_delegate.cc23
-rw-r--r--chromium/ui/gfx/skia_font_delegate.h (renamed from chromium/ui/gfx/linux_font_delegate.h)16
-rw-r--r--chromium/ui/gfx/skia_vector_animation.cc20
-rw-r--r--chromium/ui/gfx/skia_vector_animation.h11
-rw-r--r--chromium/ui/gfx/skia_vector_animation_unittest.cc10
-rw-r--r--chromium/ui/gfx/skottie_wrapper.cc36
-rw-r--r--chromium/ui/gfx/skottie_wrapper.h55
-rw-r--r--chromium/ui/gfx/switches.cc8
-rw-r--r--chromium/ui/gfx/text_elider_unittest.cc20
-rw-r--r--chromium/ui/gfx/text_utils_ios.mm4
-rw-r--r--chromium/ui/gfx/text_utils_unittest.cc8
-rw-r--r--chromium/ui/gfx/transform_unittest.cc40
-rw-r--r--chromium/ui/gfx/win/singleton_hwnd.cc12
-rw-r--r--chromium/ui/gl/BUILD.gn8
-rw-r--r--chromium/ui/gl/PRESUBMIT.py31
-rw-r--r--chromium/ui/gl/android/android_surface_composer_compat.cc253
-rw-r--r--chromium/ui/gl/android/android_surface_control_compat.cc246
-rw-r--r--chromium/ui/gl/android/android_surface_control_compat.h (renamed from chromium/ui/gl/android/android_surface_composer_compat.h)45
-rw-r--r--chromium/ui/gl/android/surface_texture.cc3
-rw-r--r--chromium/ui/gl/dc_renderer_layer_params.cc4
-rw-r--r--chromium/ui/gl/dc_renderer_layer_params.h11
-rwxr-xr-xchromium/ui/gl/generate_bindings.py23
-rw-r--r--chromium/ui/gl/gl_bindings.h9
-rw-r--r--chromium/ui/gl/gl_bindings_api_autogen_gl.h20
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.cc195
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_gl.h57
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_mock.cc53
-rw-r--r--chromium/ui/gl/gl_bindings_autogen_mock.h23
-rw-r--r--chromium/ui/gl/gl_context.cc4
-rw-r--r--chromium/ui/gl/gl_context.h5
-rw-r--r--chromium/ui/gl/gl_context_cgl.cc3
-rw-r--r--chromium/ui/gl/gl_enums_implementation_autogen.h9
-rw-r--r--chromium/ui/gl/gl_image_memory.cc31
-rw-r--r--chromium/ui/gl/gl_image_memory.h5
-rw-r--r--chromium/ui/gl/gl_image_ref_counted_memory.cc5
-rw-r--r--chromium/ui/gl/gl_image_ref_counted_memory.h2
-rw-r--r--chromium/ui/gl/gl_image_ref_counted_memory_unittest.cc3
-rw-r--r--chromium/ui/gl/gl_image_shared_memory.cc28
-rw-r--r--chromium/ui/gl/gl_image_shared_memory.h12
-rw-r--r--chromium/ui/gl/gl_image_shared_memory_unittest.cc46
-rw-r--r--chromium/ui/gl/gl_implementation.h22
-rw-r--r--chromium/ui/gl/gl_mock_autogen_gl.h24
-rw-r--r--chromium/ui/gl/gl_stub_autogen_gl.h20
-rw-r--r--chromium/ui/gl/gl_surface_egl.cc63
-rw-r--r--chromium/ui/gl/gl_surface_egl.h3
-rw-r--r--chromium/ui/gl/gl_surface_egl_surface_control.cc132
-rw-r--r--chromium/ui/gl/gl_surface_egl_surface_control.h36
-rw-r--r--chromium/ui/gl/gl_switches.cc8
-rw-r--r--chromium/ui/gl/gl_switches.h2
-rw-r--r--chromium/ui/gl/gl_version_info.h6
-rw-r--r--chromium/ui/gl/init/create_gr_gl_interface.cc5
-rw-r--r--chromium/ui/gl/trace_util.cc6
-rw-r--r--chromium/ui/gl/trace_util.h2
-rw-r--r--chromium/ui/keyboard/BUILD.gn14
-rw-r--r--chromium/ui/keyboard/OWNERS2
-rw-r--r--chromium/ui/keyboard/container_behavior.cc14
-rw-r--r--chromium/ui/keyboard/container_behavior.h43
-rw-r--r--chromium/ui/keyboard/container_floating_behavior.cc39
-rw-r--r--chromium/ui/keyboard/container_floating_behavior.h30
-rw-r--r--chromium/ui/keyboard/container_full_width_behavior.cc25
-rw-r--r--chromium/ui/keyboard/container_full_width_behavior.h15
-rw-r--r--chromium/ui/keyboard/container_fullscreen_behavior.cc11
-rw-r--r--chromium/ui/keyboard/container_fullscreen_behavior.h6
-rw-r--r--chromium/ui/keyboard/container_type.h29
-rw-r--r--chromium/ui/keyboard/keyboard_controller.cc312
-rw-r--r--chromium/ui/keyboard/keyboard_controller.h98
-rw-r--r--chromium/ui/keyboard/keyboard_controller_observer.h17
-rw-r--r--chromium/ui/keyboard/keyboard_controller_unittest.cc44
-rw-r--r--chromium/ui/keyboard/keyboard_layout_manager.cc2
-rw-r--r--chromium/ui/keyboard/keyboard_ui.cc12
-rw-r--r--chromium/ui/keyboard/keyboard_ui.h31
-rw-r--r--chromium/ui/keyboard/keyboard_util.cc173
-rw-r--r--chromium/ui/keyboard/keyboard_util.h60
-rw-r--r--chromium/ui/keyboard/keyboard_util_unittest.cc58
-rw-r--r--chromium/ui/keyboard/public/keyboard_config.mojom2
-rw-r--r--chromium/ui/keyboard/public/keyboard_controller_types.mojom51
-rw-r--r--chromium/ui/keyboard/public/keyboard_switches.cc (renamed from chromium/ui/keyboard/keyboard_switches.cc)2
-rw-r--r--chromium/ui/keyboard/public/keyboard_switches.h (renamed from chromium/ui/keyboard/keyboard_switches.h)12
-rw-r--r--chromium/ui/keyboard/queued_container_type.cc2
-rw-r--r--chromium/ui/keyboard/queued_container_type.h8
-rw-r--r--chromium/ui/keyboard/queued_display_change.h1
-rw-r--r--chromium/ui/keyboard/resources/inputview_adapter.js1
-rw-r--r--chromium/ui/keyboard/resources/keyboard_resource_util.cc (renamed from chromium/ui/keyboard/keyboard_resource_util.cc)2
-rw-r--r--chromium/ui/keyboard/resources/keyboard_resource_util.h (renamed from chromium/ui/keyboard/keyboard_resource_util.h)6
-rw-r--r--chromium/ui/latency/frame_metrics.cc48
-rw-r--r--chromium/ui/latency/frame_metrics.h2
-rw-r--r--chromium/ui/latency/ipc/latency_info_param_traits.cc5
-rw-r--r--chromium/ui/latency/ipc/latency_info_param_traits_macros.h3
-rw-r--r--chromium/ui/latency/ipc/latency_info_param_traits_unittest.cc2
-rw-r--r--chromium/ui/latency/latency_info.cc23
-rw-r--r--chromium/ui/latency/latency_info.h14
-rw-r--r--chromium/ui/latency/latency_info_unittest.cc22
-rw-r--r--chromium/ui/latency/latency_tracker.cc151
-rw-r--r--chromium/ui/latency/latency_tracker.h72
-rw-r--r--chromium/ui/latency/mojo/latency_info.mojom3
-rw-r--r--chromium/ui/latency/mojo/latency_info_struct_traits.cc51
-rw-r--r--chromium/ui/latency/mojo/latency_info_struct_traits.h3
-rw-r--r--chromium/ui/latency/mojo/struct_traits_unittest.cc2
-rw-r--r--chromium/ui/latency/skipped_frame_tracker.cc10
-rw-r--r--chromium/ui/latency/skipped_frame_tracker.h4
-rw-r--r--chromium/ui/latency/skipped_frame_tracker_unittest.cc59
-rw-r--r--chromium/ui/latency/stream_analyzer.h2
-rw-r--r--chromium/ui/latency/windowed_analyzer.h2
-rw-r--r--chromium/ui/login/account_picker/md_user_pod_template.html5
-rw-r--r--chromium/ui/login/display_manager.js31
-rw-r--r--chromium/ui/message_center/BUILD.gn30
-rw-r--r--chromium/ui/message_center/cocoa/notification_controller.h119
-rw-r--r--chromium/ui/message_center/cocoa/notification_controller.mm995
-rw-r--r--chromium/ui/message_center/cocoa/notification_controller_unittest.mm434
-rw-r--r--chromium/ui/message_center/cocoa/opaque_views.h36
-rw-r--r--chromium/ui/message_center/cocoa/opaque_views.mm63
-rw-r--r--chromium/ui/message_center/cocoa/popup_collection.h101
-rw-r--r--chromium/ui/message_center/cocoa/popup_collection.mm398
-rw-r--r--chromium/ui/message_center/cocoa/popup_collection_unittest.mm348
-rw-r--r--chromium/ui/message_center/cocoa/popup_controller.h99
-rw-r--r--chromium/ui/message_center/cocoa/popup_controller.mm296
-rw-r--r--chromium/ui/message_center/cocoa/popup_controller_unittest.mm46
-rw-r--r--chromium/ui/message_center/message_center_impl.cc3
-rw-r--r--chromium/ui/message_center/message_center_impl_unittest.cc30
-rw-r--r--chromium/ui/message_center/message_center_stats_collector.cc9
-rw-r--r--chromium/ui/message_center/message_center_stats_collector.h4
-rw-r--r--chromium/ui/message_center/notification_list_unittest.cc36
-rw-r--r--chromium/ui/message_center/popup_timers_controller.cc2
-rw-r--r--chromium/ui/message_center/public/cpp/message_center_constants.h13
-rw-r--r--chromium/ui/message_center/public/cpp/notification.cc57
-rw-r--r--chromium/ui/message_center/public/cpp/notification.h45
-rw-r--r--chromium/ui/message_center/public/cpp/notifier_id.cc11
-rw-r--r--chromium/ui/message_center/public/cpp/notifier_id.h21
-rw-r--r--chromium/ui/message_center/public/mojo/notification.mojom1
-rw-r--r--chromium/ui/message_center/public/mojo/notifier_id.mojom4
-rw-r--r--chromium/ui/message_center/public/mojo/notifier_id.typemap2
-rw-r--r--chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc2
-rw-r--r--chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h36
-rw-r--r--chromium/ui/message_center/public/mojo/struct_traits_unittest.cc4
-rw-r--r--chromium/ui/message_center/views/bounded_label.cc6
-rw-r--r--chromium/ui/message_center/views/bounded_label.h3
-rw-r--r--chromium/ui/message_center/views/bounded_label_unittest.cc18
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.cc133
-rw-r--r--chromium/ui/message_center/views/message_popup_collection.h35
-rw-r--r--chromium/ui/message_center/views/message_popup_collection_unittest.cc168
-rw-r--r--chromium/ui/message_center/views/message_popup_view.cc2
-rw-r--r--chromium/ui/message_center/views/message_popup_view_mac.mm19
-rw-r--r--chromium/ui/message_center/views/message_view.cc28
-rw-r--r--chromium/ui/message_center/views/message_view.h24
-rw-r--r--chromium/ui/message_center/views/message_view_factory.cc37
-rw-r--r--chromium/ui/message_center/views/message_view_factory.h19
-rw-r--r--chromium/ui/message_center/views/notification_header_view.cc4
-rw-r--r--chromium/ui/message_center/views/notification_header_view.h3
-rw-r--r--chromium/ui/message_center/views/notification_menu_model_unittest.cc2
-rw-r--r--chromium/ui/message_center/views/notification_view.cc49
-rw-r--r--chromium/ui/message_center/views/notification_view.h6
-rw-r--r--chromium/ui/message_center/views/notification_view_md.cc94
-rw-r--r--chromium/ui/message_center/views/notification_view_md.h18
-rw-r--r--chromium/ui/message_center/views/notification_view_md_unittest.cc259
-rw-r--r--chromium/ui/message_center/views/notification_view_unittest.cc181
-rw-r--r--chromium/ui/message_center/views/padded_button.h2
-rw-r--r--chromium/ui/message_center/views/slide_out_controller.cc51
-rw-r--r--chromium/ui/message_center/views/slide_out_controller.h32
-rw-r--r--chromium/ui/message_center/views/slide_out_controller_unittest.cc121
-rw-r--r--chromium/ui/native_theme/common_theme.cc30
-rw-r--r--chromium/ui/native_theme/native_theme.cc7
-rw-r--r--chromium/ui/native_theme/native_theme.h11
-rw-r--r--chromium/ui/native_theme/native_theme_aura.cc1
-rw-r--r--chromium/ui/native_theme/native_theme_dark_aura.cc8
-rw-r--r--chromium/ui/native_theme/native_theme_mac.h1
-rw-r--r--chromium/ui/native_theme/native_theme_mac.mm21
-rw-r--r--chromium/ui/ozone/common/gpu/ozone_gpu_message_generator.cc4
-rw-r--r--chromium/ui/ozone/common/linux/BUILD.gn15
-rw-r--r--chromium/ui/ozone/common/linux/drm_util_linux.cc26
-rw-r--r--chromium/ui/ozone/common/linux/gbm_wrapper.cc21
-rw-r--r--chromium/ui/ozone/common/stub_client_native_pixmap_factory.cc4
-rw-r--r--chromium/ui/ozone/demo/demo_window.cc19
-rw-r--r--chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc6
-rw-r--r--chromium/ui/ozone/platform/cast/ozone_platform_cast.cc5
-rw-r--r--chromium/ui/ozone/platform/drm/BUILD.gn12
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_device.cc8
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc11
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.cc6
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc9
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h3
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc5
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc13
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h2
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc48
-rw-r--r--chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h8
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_cursor.cc2
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_device_handle.cc4
-rw-r--r--chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc5
-rw-r--r--chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc28
-rw-r--r--chromium/ui/ozone/platform/scenic/BUILD.gn10
-rw-r--r--chromium/ui/ozone/platform/scenic/DEPS1
-rw-r--r--chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc55
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc101
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_host.h76
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc52
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_gpu_service.h51
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_session.cc309
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_session.h127
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc81
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_surface_factory.h12
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.cc163
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window.h49
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc86
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window_canvas.h37
-rw-r--r--chromium/ui/ozone/platform/scenic/scenic_window_manager.cc11
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc99
-rw-r--r--chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h10
-rw-r--r--chromium/ui/ozone/platform/wayland/BUILD.gn9
-rw-r--r--chromium/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc36
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc8
-rw-r--r--chromium/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc41
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc33
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_buffer_manager.h2
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_connection.cc12
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_surface_factory.cc1
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window.cc48
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window.h18
-rw-r--r--chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc48
-rw-r--r--chromium/ui/ozone/platform/x11/BUILD.gn10
-rw-r--r--chromium/ui/ozone/platform/x11/ozone_platform_x11.cc5
-rw-r--r--chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.cc91
-rw-r--r--chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.h59
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.cc94
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone.h57
-rw-r--r--chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc24
-rw-r--r--chromium/ui/ozone/public/cursor_factory_ozone.cc21
-rw-r--r--chromium/ui/ozone/public/interfaces/BUILD.gn2
-rw-r--r--chromium/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc15
-rw-r--r--chromium/ui/ozone/public/interfaces/scenic_gpu_host.mojom11
-rw-r--r--chromium/ui/ozone/public/interfaces/scenic_gpu_service.mojom19
-rw-r--r--chromium/ui/ozone/public/ozone_platform.cc26
-rw-r--r--chromium/ui/ozone/public/ozone_platform.h23
-rw-r--r--chromium/ui/ozone/public/ozone_switches.cc3
-rw-r--r--chromium/ui/ozone/public/ozone_switches.h2
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.cc5
-rw-r--r--chromium/ui/ozone/public/surface_factory_ozone.h5
-rw-r--r--chromium/ui/platform_window/BUILD.gn8
-rw-r--r--chromium/ui/platform_window/fuchsia/OWNERS1
-rw-r--r--chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.cc36
-rw-r--r--chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.h21
-rw-r--r--chromium/ui/platform_window/platform_window_handler/BUILD.gn2
-rw-r--r--chromium/ui/platform_window/platform_window_handler/wm_drag_handler.cc25
-rw-r--r--chromium/ui/platform_window/platform_window_handler/wm_drag_handler.h39
-rw-r--r--chromium/ui/platform_window/platform_window_init_properties.h5
-rw-r--r--chromium/ui/resources/default_100_percent/common/menu_hierarchy_arrow.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/menu_overflow_down.pngbin84 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/menu_overflow_up.pngbin83 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_close.pngbin139 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_close_hover.pngbin214 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_close_pressed.pngbin214 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_settings_button.pngbin186 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_settings_button_hover.pngbin191 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/common/notification_settings_button_pressed.pngbin186 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/cros/menu_droparrow.pngbin104 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/legacy/throbber.pngbin4309 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/win/notification_close.pngbin171 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/win/notification_close_hover.pngbin224 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_100_percent/win/notification_close_pressed.pngbin222 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/menu_hierarchy_arrow.pngbin141 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/menu_overflow_down.pngbin142 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/menu_overflow_up.pngbin137 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_close.pngbin205 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_close_hover.pngbin380 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_close_pressed.pngbin379 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_settings_button.pngbin336 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_settings_button_hover.pngbin331 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/common/notification_settings_button_pressed.pngbin331 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/cros/menu_droparrow.pngbin100 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/legacy/throbber.pngbin10033 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/win/notification_close.pngbin196 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/win/notification_close_hover.pngbin447 -> 0 bytes
-rw-r--r--chromium/ui/resources/default_200_percent/win/notification_close_pressed.pngbin428 -> 0 bytes
-rw-r--r--chromium/ui/resources/ui_resources.grd26
-rw-r--r--chromium/ui/shell_dialogs/BUILD.gn7
-rw-r--r--chromium/ui/shell_dialogs/OWNERS2
-rw-r--r--chromium/ui/shell_dialogs/base_shell_dialog_win.cc44
-rw-r--r--chromium/ui/shell_dialogs/base_shell_dialog_win.h37
-rw-r--r--chromium/ui/shell_dialogs/execute_select_file_win.cc407
-rw-r--r--chromium/ui/shell_dialogs/execute_select_file_win.h58
-rw-r--r--chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc54
-rw-r--r--chromium/ui/shell_dialogs/run_all_unittests.cc19
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_mac.mm5
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm4
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win.cc683
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win.h31
-rw-r--r--chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc516
-rw-r--r--chromium/ui/snapshot/screenshot_grabber.cc4
-rw-r--r--chromium/ui/snapshot/snapshot_aura_unittest.cc1
-rw-r--r--chromium/ui/snapshot/snapshot_mac.mm15
-rw-r--r--chromium/ui/strings/translations/ui_strings_am.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_ar.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_bg.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_bn.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_ca.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_cs.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_da.xtb27
-rw-r--r--chromium/ui/strings/translations/ui_strings_de.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_el.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_en-GB.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_es-419.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_es.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_et.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_fa.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_fi.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_fil.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_fr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_gu.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_hi.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_hr.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_hu.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_id.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_it.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_iw.xtb9
-rw-r--r--chromium/ui/strings/translations/ui_strings_ja.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_kn.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_ko.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_lt.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_lv.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_ml.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_mr.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ms.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_nl.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_no.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_pl.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-BR.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_pt-PT.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_ro.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_ru.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_sk.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_sl.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_sr.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_sv.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_sw.xtb7
-rw-r--r--chromium/ui/strings/translations/ui_strings_ta.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_te.xtb13
-rw-r--r--chromium/ui/strings/translations/ui_strings_th.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_tr.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_uk.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_vi.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-CN.xtb5
-rw-r--r--chromium/ui/strings/translations/ui_strings_zh-TW.xtb7
-rw-r--r--chromium/ui/strings/ui_strings.grd17
-rw-r--r--chromium/ui/surface/transport_dib_win.cc2
-rw-r--r--chromium/ui/touch_selection/touch_selection_menu_runner.h7
-rw-r--r--chromium/ui/views/BUILD.gn54
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_cache.cc2
-rw-r--r--chromium/ui/views/accessibility/ax_aura_obj_wrapper.h3
-rw-r--r--chromium/ui/views/accessibility/ax_event_manager.cc36
-rw-r--r--chromium/ui/views/accessibility/ax_event_manager.h41
-rw-r--r--chromium/ui/views/accessibility/ax_event_observer.cc13
-rw-r--r--chromium/ui/views/accessibility/ax_event_observer.h28
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.cc5
-rw-r--r--chromium/ui/views/accessibility/ax_root_obj_wrapper.h2
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.cc26
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views.h15
-rw-r--r--chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc34
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.cc32
-rw-r--r--chromium/ui/views/accessibility/ax_view_obj_wrapper.h10
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.cc281
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view.h170
-rw-r--r--chromium/ui/views/accessibility/ax_virtual_view_unittest.cc347
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc9
-rw-r--r--chromium/ui/views/accessibility/ax_widget_obj_wrapper.h2
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.cc34
-rw-r--r--chromium/ui/views/accessibility/ax_window_obj_wrapper.h3
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.cc134
-rw-r--r--chromium/ui/views/accessibility/view_accessibility.h89
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc54
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate.h32
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.h1
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm30
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc40
-rw-r--r--chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc2
-rw-r--r--chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc13
-rw-r--r--chromium/ui/views/animation/flood_fill_ink_drop_ripple.h1
-rw-r--r--chromium/ui/views/animation/ink_drop_host.h66
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.cc196
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view.h132
-rw-r--r--chromium/ui/views/animation/ink_drop_host_view_unittest.cc82
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.cc26
-rw-r--r--chromium/ui/views/animation/ink_drop_impl.h6
-rw-r--r--chromium/ui/views/animation/ink_drop_impl_unittest.cc29
-rw-r--r--chromium/ui/views/animation/ink_drop_mask.cc6
-rw-r--r--chromium/ui/views/animation/ink_drop_mask.h8
-rw-r--r--chromium/ui/views/animation/ink_drop_ripple.cc16
-rw-r--r--chromium/ui/views/animation/ink_drop_ripple.h7
-rw-r--r--chromium/ui/views/animation/ink_drop_unittest.cc2
-rw-r--r--chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc3
-rw-r--r--chromium/ui/views/bubble/bubble_border.cc7
-rw-r--r--chromium/ui/views/bubble/bubble_border_unittest.cc1
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.cc27
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view.h10
-rw-r--r--chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc19
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.cc34
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view.h3
-rw-r--r--chromium/ui/views/bubble/bubble_frame_view_unittest.cc1
-rw-r--r--chromium/ui/views/bubble/footnote_container_view.cc78
-rw-r--r--chromium/ui/views/bubble/footnote_container_view.h32
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.h41
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm119
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm4
-rw-r--r--chromium/ui/views/cocoa/bridged_native_widget_unittest.mm24
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac.h2
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac.mm8
-rw-r--r--chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm5
-rw-r--r--chromium/ui/views/controls/animated_icon_view.cc91
-rw-r--r--chromium/ui/views/controls/animated_icon_view.h71
-rw-r--r--chromium/ui/views/controls/animated_image_view.cc50
-rw-r--r--chromium/ui/views/controls/animated_image_view.h7
-rw-r--r--chromium/ui/views/controls/button/blue_button.cc78
-rw-r--r--chromium/ui/views/controls/button/blue_button.h33
-rw-r--r--chromium/ui/views/controls/button/blue_button_unittest.cc69
-rw-r--r--chromium/ui/views/controls/button/button.cc61
-rw-r--r--chromium/ui/views/controls/button/button.h32
-rw-r--r--chromium/ui/views/controls/button/button_unittest.cc35
-rw-r--r--chromium/ui/views/controls/button/checkbox.cc2
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.cc54
-rw-r--r--chromium/ui/views/controls/button/image_button_factory.h21
-rw-r--r--chromium/ui/views/controls/button/image_button_factory_unittest.cc1
-rw-r--r--chromium/ui/views/controls/button/label_button.cc23
-rw-r--r--chromium/ui/views/controls/button/label_button.h4
-rw-r--r--chromium/ui/views/controls/button/label_button_unittest.cc28
-rw-r--r--chromium/ui/views/controls/button/md_text_button.cc1
-rw-r--r--chromium/ui/views/controls/button/menu_button.cc365
-rw-r--r--chromium/ui/views/controls/button/menu_button.h135
-rw-r--r--chromium/ui/views/controls/button/menu_button_event_handler.cc384
-rw-r--r--chromium/ui/views/controls/button/menu_button_event_handler.h137
-rw-r--r--chromium/ui/views/controls/button/menu_button_unittest.cc59
-rw-r--r--chromium/ui/views/controls/button/toggle_button_unittest.cc3
-rw-r--r--chromium/ui/views/controls/combobox/combobox.cc437
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h65
-rw-r--r--chromium/ui/views/controls/combobox/combobox_listener.h11
-rw-r--r--chromium/ui/views/controls/combobox/combobox_unittest.cc199
-rw-r--r--chromium/ui/views/controls/focus_ring.cc2
-rw-r--r--chromium/ui/views/controls/image_view_base.cc19
-rw-r--r--chromium/ui/views/controls/image_view_base.h8
-rw-r--r--chromium/ui/views/controls/label_unittest.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_closure_animation_mac.mm2
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.cc60
-rw-r--r--chromium/ui/views/controls/menu/menu_controller.h9
-rw-r--r--chromium/ui/views/controls/menu/menu_controller_unittest.cc108
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.cc4
-rw-r--r--chromium/ui/views/controls/menu/menu_delegate.h5
-rw-r--r--chromium/ui/views/controls/menu/menu_host.cc2
-rw-r--r--chromium/ui/views/controls/menu/menu_image_util.cc1
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.cc107
-rw-r--r--chromium/ui/views/controls/menu/menu_item_view.h17
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter.cc3
-rw-r--r--chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc6
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_aura.cc23
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h2
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h15
-rw-r--r--chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm42
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm10
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm5
-rw-r--r--chromium/ui/views/controls/menu/menu_runner_unittest.cc8
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.cc49
-rw-r--r--chromium/ui/views/controls/menu/menu_scroll_view_container.h13
-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/menu/submenu_view_unittest.cc36
-rw-r--r--chromium/ui/views/controls/native/native_view_host.cc7
-rw-r--r--chromium/ui/views/controls/native/native_view_host.h1
-rw-r--r--chromium/ui/views/controls/native/native_view_host_aura.cc13
-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.h1
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac.mm41
-rw-r--r--chromium/ui/views/controls/native/native_view_host_mac_unittest.mm10
-rw-r--r--chromium/ui/views/controls/native/native_view_host_wrapper.h5
-rw-r--r--chromium/ui/views/controls/resize_area_unittest.cc5
-rw-r--r--chromium/ui/views/controls/scroll_view_unittest.cc10
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.cc13
-rw-r--r--chromium/ui/views/controls/scrollbar/base_scroll_bar.h2
-rw-r--r--chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc14
-rw-r--r--chromium/ui/views/controls/slider_unittest.cc82
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc2
-rw-r--r--chromium/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm3
-rw-r--r--chromium/ui/views/controls/table/table_view_unittest.cc9
-rw-r--r--chromium/ui/views/controls/textfield/textfield.h2
-rw-r--r--chromium/ui/views/controls/textfield/textfield_model.cc2
-rw-r--r--chromium/ui/views/controls/textfield/textfield_unittest.cc7
-rw-r--r--chromium/ui/views/controls/tree/tree_view.cc1
-rw-r--r--chromium/ui/views/controls/views_text_services_context_menu_mac.mm2
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc15
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.h4
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_default.cc4
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_mac.mm3
-rw-r--r--chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc3
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.cc5
-rw-r--r--chromium/ui/views/controls/webview/web_dialog_view.h2
-rw-r--r--chromium/ui/views/controls/webview/webview.cc5
-rw-r--r--chromium/ui/views/controls/webview/webview_unittest.cc2
-rw-r--r--chromium/ui/views/corewm/tooltip_controller_unittest.cc19
-rw-r--r--chromium/ui/views/corewm/tooltip_win.cc17
-rw-r--r--chromium/ui/views/event_monitor.h35
-rw-r--r--chromium/ui/views/event_monitor_aura.cc31
-rw-r--r--chromium/ui/views/event_monitor_aura.h11
-rw-r--r--chromium/ui/views/event_monitor_mac.h6
-rw-r--r--chromium/ui/views/event_monitor_mac.mm36
-rw-r--r--chromium/ui/views/event_monitor_unittest.cc110
-rw-r--r--chromium/ui/views/event_utils.cc3
-rw-r--r--chromium/ui/views/examples/BUILD.gn2
-rw-r--r--chromium/ui/views/examples/animated_image_view_example.cc4
-rw-r--r--chromium/ui/views/examples/box_layout_example.cc362
-rw-r--r--chromium/ui/views/examples/box_layout_example.h65
-rw-r--r--chromium/ui/views/examples/button_example.cc3
-rw-r--r--chromium/ui/views/examples/combobox_example.cc61
-rw-r--r--chromium/ui/views/examples/combobox_example.h16
-rw-r--r--chromium/ui/views/examples/examples_window.cc31
-rw-r--r--chromium/ui/views/examples/label_example.cc12
-rw-r--r--chromium/ui/views/examples/label_example.h3
-rw-r--r--chromium/ui/views/examples/layout_example_base.cc352
-rw-r--r--chromium/ui/views/examples/layout_example_base.h147
-rw-r--r--chromium/ui/views/examples/menu_example.cc5
-rw-r--r--chromium/ui/views/examples/text_example.cc15
-rw-r--r--chromium/ui/views/examples/text_example.h6
-rw-r--r--chromium/ui/views/examples/webview_example.cc4
-rw-r--r--chromium/ui/views/examples/webview_example.h2
-rw-r--r--chromium/ui/views/focus/focus_manager.cc5
-rw-r--r--chromium/ui/views/focus/focus_manager.h19
-rw-r--r--chromium/ui/views/focus/focus_manager_unittest.cc24
-rw-r--r--chromium/ui/views/focus/focus_search.cc17
-rw-r--r--chromium/ui/views/layout/box_layout.h10
-rw-r--r--chromium/ui/views/layout/layout_manager.cc14
-rw-r--r--chromium/ui/views/layout/layout_manager.h13
-rw-r--r--chromium/ui/views/layout/layout_provider.cc9
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.cc4
-rw-r--r--chromium/ui/views/linux_ui/linux_ui.h10
-rw-r--r--chromium/ui/views/mouse_watcher.cc29
-rw-r--r--chromium/ui/views/mus/BUILD.gn5
-rw-r--r--chromium/ui/views/mus/aura_init.cc5
-rw-r--r--chromium/ui/views/mus/ax_remote_host.cc42
-rw-r--r--chromium/ui/views/mus/ax_remote_host.h10
-rw-r--r--chromium/ui/views/mus/ax_remote_host_unittest.cc8
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.cc28
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus.h9
-rw-r--r--chromium/ui/views/mus/ax_tree_source_mus_unittest.cc15
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.cc269
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.h37
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc382
-rw-r--r--chromium/ui/views/mus/mus_client.cc28
-rw-r--r--chromium/ui/views/mus/mus_client.h29
-rw-r--r--chromium/ui/views/mus/mus_views_delegate.cc23
-rw-r--r--chromium/ui/views/mus/mus_views_delegate.h9
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router.cc175
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router.h101
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc240
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc6
-rw-r--r--chromium/ui/views/pointer_watcher.h65
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused.pngbin96 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_hover.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_pressed.pngbin95 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_hover.pngbin85 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left.pngbin103 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused.pngbin129 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_hover.pngbin142 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_pressed.pngbin126 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_hover.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_pressed.pngbin103 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_pressed.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right.pngbin89 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_hover.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_pressed.pngbin95 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_hover.pngbin89 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_pressed.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_hover.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_pressed.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_hover.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left.pngbin75 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused.pngbin84 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_hover.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_pressed.pngbin84 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_hover.pngbin77 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_pressed.pngbin75 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_pressed.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right.pngbin69 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused.pngbin69 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_hover.pngbin69 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_pressed.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_hover.pngbin69 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_pressed.pngbin68 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom.pngbin122 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused.pngbin150 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_hover.pngbin168 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_pressed.pngbin151 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_hover.pngbin128 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_pressed.pngbin120 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused.pngbin89 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_hover.pngbin93 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_pressed.pngbin88 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_hover.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_pressed.pngbin79 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top.pngbin114 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused.pngbin139 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_hover.pngbin148 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_pressed.pngbin129 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_hover.pngbin117 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_pressed.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_hover.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_pressed.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_hover.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left.pngbin97 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused.pngbin119 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_hover.pngbin122 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_pressed.pngbin109 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_hover.pngbin102 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_pressed.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_pressed.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused.pngbin97 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_hover.pngbin97 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_pressed.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_hover.pngbin86 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_pressed.pngbin82 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused.pngbin108 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_hover.pngbin107 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_pressed.pngbin103 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_hover.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left.pngbin129 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused.pngbin169 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_hover.pngbin165 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_pressed.pngbin170 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_hover.pngbin130 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_pressed.pngbin133 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_pressed.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right.pngbin100 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused.pngbin115 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_hover.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_pressed.pngbin103 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_hover.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_pressed.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_hover.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_pressed.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_hover.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left.pngbin80 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_hover.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_pressed.pngbin91 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_hover.pngbin81 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_pressed.pngbin80 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_pressed.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_hover.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_pressed.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_hover.pngbin71 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_pressed.pngbin70 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom.pngbin153 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused.pngbin204 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_hover.pngbin202 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_pressed.pngbin208 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_hover.pngbin152 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_pressed.pngbin152 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused.pngbin100 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_hover.pngbin100 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_pressed.pngbin99 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_hover.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_pressed.pngbin84 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top.pngbin134 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused.pngbin177 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_hover.pngbin176 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_pressed.pngbin167 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_hover.pngbin134 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_pressed.pngbin130 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused.pngbin99 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_hover.pngbin98 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_pressed.pngbin99 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_hover.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left.pngbin116 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused.pngbin149 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_hover.pngbin144 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_pressed.pngbin135 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_hover.pngbin115 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_pressed.pngbin112 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_pressed.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right.pngbin94 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused.pngbin107 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_hover.pngbin103 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_pressed.pngbin99 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_hover.pngbin93 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_pressed.pngbin87 -> 0 bytes
-rw-r--r--chromium/ui/views/resources/views_resources.grd79
-rw-r--r--chromium/ui/views/style/platform_style.cc3
-rw-r--r--chromium/ui/views/style/platform_style.h7
-rw-r--r--chromium/ui/views/style/platform_style_mac.mm2
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.cc82
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl.h22
-rw-r--r--chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc4
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_runner_views.cc245
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_runner_views.h21
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc11
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_views.cc185
-rw-r--r--chromium/ui/views/touchui/touch_selection_menu_views.h70
-rw-r--r--chromium/ui/views/view.cc42
-rw-r--r--chromium/ui/views/view.h42
-rw-r--r--chromium/ui/views/view_properties.cc4
-rw-r--r--chromium/ui/views/view_properties.h8
-rw-r--r--chromium/ui/views/view_unittest.cc35
-rw-r--r--chromium/ui/views/view_unittest_mac.mm5
-rw-r--r--chromium/ui/views/views_delegate.cc27
-rw-r--r--chromium/ui/views/views_delegate.h22
-rw-r--r--chromium/ui/views/views_touch_selection_controller_factory.h2
-rw-r--r--chromium/ui/views/widget/ax_native_widget_mac_unittest.mm28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc110
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h66
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc121
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc12
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h2
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc19
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h3
-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_x11.cc249
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h10
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc6
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc14
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h3
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc26
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h9
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc28
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h7
-rw-r--r--chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc92
-rw-r--r--chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc2
-rw-r--r--chromium/ui/views/widget/native_widget_aura.cc5
-rw-r--r--chromium/ui/views/widget/native_widget_mac.h21
-rw-r--r--chromium/ui/views/widget/native_widget_mac.mm120
-rw-r--r--chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm44
-rw-r--r--chromium/ui/views/widget/native_widget_mac_unittest.mm245
-rw-r--r--chromium/ui/views/widget/native_widget_unittest.cc2
-rw-r--r--chromium/ui/views/widget/root_view.cc4
-rw-r--r--chromium/ui/views/widget/widget.h10
-rw-r--r--chromium/ui/views/widget/widget_interactive_uitest.cc20
-rw-r--r--chromium/ui/views/widget/widget_unittest.cc81
-rw-r--r--chromium/ui/views/widget/widget_utils.cc23
-rw-r--r--chromium/ui/views/widget/widget_utils.h20
-rw-r--r--chromium/ui/views/widget/widget_utils_mac.mm2
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.cc70
-rw-r--r--chromium/ui/views/win/hwnd_message_handler.h25
-rw-r--r--chromium/ui/views/win/hwnd_message_handler_delegate.h9
-rw-r--r--chromium/ui/views/win/pen_event_processor.cc8
-rw-r--r--chromium/ui/views/window/dialog_client_view.cc2
-rw-r--r--chromium/ui/views/window/dialog_delegate.cc1
-rw-r--r--chromium/ui/views/window/non_client_view.cc5
-rw-r--r--chromium/ui/views/window/non_client_view.h5
-rw-r--r--chromium/ui/views_bridge_mac/bridge_factory_impl.mm41
-rw-r--r--chromium/ui/views_bridge_mac/bridged_content_view.h4
-rw-r--r--chromium/ui/views_bridge_mac/bridged_content_view.mm19
-rw-r--r--chromium/ui/views_bridge_mac/bridged_native_widget_host_helper.h7
-rw-r--r--chromium/ui/views_bridge_mac/bridged_native_widget_impl.h20
-rw-r--r--chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm88
-rw-r--r--chromium/ui/views_bridge_mac/browser_native_widget_window_mac.h13
-rw-r--r--chromium/ui/views_bridge_mac/browser_native_widget_window_mac.mm99
-rw-r--r--chromium/ui/views_bridge_mac/cocoa_window_move_loop.mm3
-rw-r--r--chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom43
-rw-r--r--chromium/ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom27
-rw-r--r--chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.h17
-rw-r--r--chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.mm30
-rw-r--r--chromium/ui/views_bridge_mac/native_widget_mac_nswindow.h7
-rw-r--r--chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm42
-rw-r--r--chromium/ui/views_bridge_mac/views_nswindow_delegate.h3
-rw-r--r--chromium/ui/views_bridge_mac/views_nswindow_delegate.mm3
-rw-r--r--chromium/ui/views_bridge_mac/views_scrollbar_bridge.h2
-rw-r--r--chromium/ui/views_bridge_mac/views_scrollbar_bridge.mm2
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts.cc6
-rw-r--r--chromium/ui/views_content_client/views_content_client_main_parts.h6
-rw-r--r--chromium/ui/webui/PLATFORM_OWNERS1
-rw-r--r--chromium/ui/webui/mojo_web_ui_controller.cc5
-rw-r--r--chromium/ui/webui/resources/PRESUBMIT.py3
-rw-r--r--chromium/ui/webui/resources/cr_components/.eslintrc.js (renamed from chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/.eslintrc.js)0
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html5
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html5
-rw-r--r--chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html3
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js34
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn32
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js38
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_choose_mobile.js10
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html139
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js441
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.js37
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html40
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.js35
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.html38
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.js19
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.html32
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.js23
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js28
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html13
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js23
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.html47
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.js96
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js34
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js45
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.js2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html22
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js36
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/OWNERS5
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html6
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js22
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.html30
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js21
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn30
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/OWNERS1
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html132
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js180
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.html2
-rw-r--r--chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.js79
-rw-r--r--chromium/ui/webui/resources/cr_components/cr_components_resources.grdp42
-rw-r--r--chromium/ui/webui/resources/cr_elements/.eslintrc.js13
-rw-r--r--chromium/ui/webui/resources/cr_elements/BUILD.gn1
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js45
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js12
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js14
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.js2
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_png_behavior.js80
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js20
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list.js6
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js10
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_types.js2
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js12
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js67
-rw-r--r--chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js124
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html5
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js57
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_container_shadow_behavior.js8
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js25
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn4
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html10
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js82
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html4
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html2
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js10
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js4
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js2
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js24
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js43
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html3
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn18
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.html30
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js250
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js42
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js8
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.html52
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js83
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html15
-rw-r--r--chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js2
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js5
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js4
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html18
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js17
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js5
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js4
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html2
-rw-r--r--chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.js9
-rw-r--r--chromium/ui/webui/resources/cr_elements/shared_style_css.html6
-rw-r--r--chromium/ui/webui/resources/cr_elements_resources.grdp8
-rw-r--r--chromium/ui/webui/resources/js/action_link.js138
-rw-r--r--chromium/ui/webui/resources/js/analytics.js13
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/command.js27
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/dialogs.js2
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/list_selection_model.js19
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu.js31
-rw-r--r--chromium/ui/webui/resources/js/cr/ui/menu_test.html67
-rw-r--r--chromium/ui/webui/resources/js/polymer_config.js1
-rw-r--r--chromium/ui/webui/resources/polymer_resources.grdp196
-rw-r--r--chromium/ui/webui/resources/webui_resources.grd1
-rw-r--r--chromium/ui/wm/core/accelerator_filter.cc21
-rw-r--r--chromium/ui/wm/core/accelerator_filter.h3
-rw-r--r--chromium/ui/wm/core/window_animations_unittest.cc2
-rw-r--r--chromium/ui/wm/core/window_modality_controller.cc42
-rw-r--r--chromium/ui/wm/core/window_modality_controller.h9
1344 files changed, 28716 insertions, 21121 deletions
diff --git a/chromium/ui/accessibility/BUILD.gn b/chromium/ui/accessibility/BUILD.gn
index 085e5d6da13..fc631e4e1fc 100644
--- a/chromium/ui/accessibility/BUILD.gn
+++ b/chromium/ui/accessibility/BUILD.gn
@@ -31,6 +31,8 @@ mojom("ax_enums_mojo") {
jumbo_component("accessibility") {
sources = [
+ "accessibility_switches.cc",
+ "accessibility_switches.h",
"ax_action_data.cc",
"ax_action_data.h",
"ax_enum_util.cc",
@@ -42,6 +44,7 @@ jumbo_component("accessibility") {
"ax_export.h",
"ax_host_delegate.cc",
"ax_host_delegate.h",
+ "ax_language_info.h",
"ax_mode.h",
"ax_mode_observer.h",
"ax_node.cc",
@@ -80,6 +83,11 @@ jumbo_component("accessibility") {
"platform/ax_android_constants.h",
"platform/ax_platform_node.cc",
"platform/ax_platform_node.h",
+ "platform/ax_platform_node_base.cc",
+ "platform/ax_platform_node_base.h",
+ "platform/ax_platform_node_delegate.h",
+ "platform/ax_platform_node_delegate_base.cc",
+ "platform/ax_platform_node_delegate_base.h",
"platform/ax_platform_node_test_helper.cc",
"platform/ax_platform_node_test_helper.h",
"platform/ax_unique_id.cc",
@@ -88,11 +96,6 @@ jumbo_component("accessibility") {
if (has_native_accessibility) {
sources += [
- "platform/ax_platform_node_base.cc",
- "platform/ax_platform_node_base.h",
- "platform/ax_platform_node_delegate.h",
- "platform/ax_platform_node_delegate_base.cc",
- "platform/ax_platform_node_delegate_base.h",
"platform/ax_platform_node_mac.h",
"platform/ax_platform_node_mac.mm",
"platform/ax_platform_node_win.cc",
@@ -145,6 +148,16 @@ jumbo_component("accessibility") {
if (use_glib) {
configs += [ "//build/config/linux:glib" ]
}
+
+ if (use_x11) {
+ sources += [ "platform/atk_util_auralinux_x11.cc" ]
+
+ configs += [ "//build/config/linux:x11" ]
+ public_deps += [
+ "//ui/events/x",
+ "//ui/gfx/x",
+ ]
+ }
}
if (use_aura) {
@@ -196,6 +209,8 @@ test("accessibility_unittests") {
sources = [
"ax_event_generator_unittest.cc",
"ax_generated_tree_unittest.cc",
+ "ax_language_info_unittest.cc",
+ "ax_node_data_unittest.cc",
"ax_node_position_unittest.cc",
"ax_table_info_unittest.cc",
"ax_text_utils_unittest.cc",
@@ -205,6 +220,7 @@ test("accessibility_unittests") {
"mojom/ax_action_data_mojom_traits_unittest.cc",
"mojom/ax_event_mojom_traits_unittest.cc",
"mojom/ax_node_data_mojom_traits_unittest.cc",
+ "mojom/ax_relative_bounds_mojom_traits_unittest.cc",
"mojom/ax_tree_data_mojom_traits_unittest.cc",
"mojom/ax_tree_id_mojom_traits_unittest.cc",
"mojom/ax_tree_update_mojom_traits_unittest.cc",
@@ -238,7 +254,10 @@ test("accessibility_unittests") {
libs = [ "oleacc.lib" ]
}
if (use_atk) {
- sources += [ "platform/ax_platform_node_auralinux_unittest.cc" ]
+ sources += [
+ "platform/atk_util_auralinux_unittest.cc",
+ "platform/ax_platform_node_auralinux_unittest.cc",
+ ]
configs += [ "//build/config/linux/atk" ]
}
}
@@ -252,3 +271,15 @@ fuzzer_test("ax_tree_fuzzer") {
":accessibility",
]
}
+
+fuzzer_test("ax_table_fuzzer") {
+ sources = [
+ "ax_table_fuzzer.cc",
+ ]
+
+ deps = [
+ ":accessibility",
+ ]
+
+ seed_corpus = "fuzz_corpus"
+}
diff --git a/chromium/ui/accessibility/accessibility_switches.cc b/chromium/ui/accessibility/accessibility_switches.cc
new file mode 100644
index 00000000000..5428cb21f43
--- /dev/null
+++ b/chromium/ui/accessibility/accessibility_switches.cc
@@ -0,0 +1,29 @@
+// 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/accessibility/accessibility_switches.h"
+
+#include "base/command_line.h"
+
+namespace switches {
+
+// Shows additional checkboxes in Settings to enable Chrome OS accessibility
+// features that haven't launched yet.
+const char kEnableExperimentalAccessibilityFeatures[] =
+ "enable-experimental-accessibility-features";
+
+// Shows additional automatic click features that haven't launched yet.
+const char kEnableExperimentalAccessibilityAutoclick[] =
+ "enable-experimental-accessibility-autoclick";
+
+// Shows setting to enable Switch Access before it has launched.
+const char kEnableExperimentalAccessibilitySwitchAccess[] =
+ "enable-experimental-accessibility-switch-access";
+
+bool AreExperimentalAccessibilityFeaturesEnabled() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ ::switches::kEnableExperimentalAccessibilityFeatures);
+}
+
+} // namespace switches
diff --git a/chromium/ui/accessibility/accessibility_switches.h b/chromium/ui/accessibility/accessibility_switches.h
new file mode 100644
index 00000000000..70588cd9501
--- /dev/null
+++ b/chromium/ui/accessibility/accessibility_switches.h
@@ -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.
+
+// Define all the command-line switches used by ui/accessibility.
+#ifndef UI_ACCESSIBILITY_ACCESSIBILITY_SWITCHES_H_
+#define UI_ACCESSIBILITY_ACCESSIBILITY_SWITCHES_H_
+
+#include "ui/accessibility/ax_export.h"
+
+namespace switches {
+
+AX_EXPORT extern const char kEnableExperimentalAccessibilityFeatures[];
+AX_EXPORT extern const char kEnableExperimentalAccessibilityAutoclick[];
+AX_EXPORT extern const char kEnableExperimentalAccessibilitySwitchAccess[];
+
+// Returns true if experimental accessibility features are enabled.
+AX_EXPORT bool AreExperimentalAccessibilityFeaturesEnabled();
+
+} // namespace switches
+
+#endif // UI_ACCESSIBILITY_ACCESSIBILITY_SWITCHES_H_
diff --git a/chromium/ui/accessibility/ax_action_data.h b/chromium/ui/accessibility/ax_action_data.h
index 543c072caa6..575db7f8782 100644
--- a/chromium/ui/accessibility/ax_action_data.h
+++ b/chromium/ui/accessibility/ax_action_data.h
@@ -54,6 +54,12 @@ struct AX_EXPORT AXActionData {
int focus_node_id = -1;
int focus_offset = -1;
+ // Start index of the text which should be queried for.
+ int32_t start_index = -1;
+
+ // End index of the text which should be queried for.
+ int32_t end_index = -1;
+
// For custom action.
int custom_action_id = -1;
diff --git a/chromium/ui/accessibility/ax_assistant_structure.cc b/chromium/ui/accessibility/ax_assistant_structure.cc
index 12924e8db38..0364e7bccb0 100644
--- a/chromium/ui/accessibility/ax_assistant_structure.cc
+++ b/chromium/ui/accessibility/ax_assistant_structure.cc
@@ -305,24 +305,16 @@ void WalkAXTreeDepthFirst(const AXNode* node,
gfx::ToEnclosingRect(tree->RelativeToTreeBounds(node, text_size_rect));
result->text_size = scaled_text_size_rect.height();
- const int32_t text_style =
- node->data().GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
result->color =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kColor);
result->bgcolor =
node->data().GetIntAttribute(ax::mojom::IntAttribute::kBackgroundColor);
- result->bold =
- (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleBold)) != 0;
- result->italic =
- (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleItalic)) != 0;
+ result->bold = node->data().HasTextStyle(ax::mojom::TextStyle::kBold);
+ result->italic = node->data().HasTextStyle(ax::mojom::TextStyle::kItalic);
result->line_through =
- (text_style & static_cast<int32_t>(
- ax::mojom::TextStyle::kTextStyleLineThrough)) != 0;
+ node->data().HasTextStyle(ax::mojom::TextStyle::kLineThrough);
result->underline =
- (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleUnderline)) != 0;
+ node->data().HasTextStyle(ax::mojom::TextStyle::kUnderline);
}
const gfx::Rect& absolute_rect =
diff --git a/chromium/ui/accessibility/ax_enum_util.cc b/chromium/ui/accessibility/ax_enum_util.cc
index 654deaf19b9..cb523c47c62 100644
--- a/chromium/ui/accessibility/ax_enum_util.cc
+++ b/chromium/ui/accessibility/ax_enum_util.cc
@@ -110,6 +110,10 @@ const char* ToString(ax::mojom::Event event) {
return "textChanged";
case ax::mojom::Event::kTextSelectionChanged:
return "textSelectionChanged";
+ case ax::mojom::Event::kWindowActivated:
+ return "windowActivated";
+ case ax::mojom::Event::kWindowDeactivated:
+ return "windowDeactivated";
case ax::mojom::Event::kTreeChanged:
return "treeChanged";
case ax::mojom::Event::kValueChanged:
@@ -218,6 +222,10 @@ ax::mojom::Event ParseEvent(const char* event) {
return ax::mojom::Event::kTextChanged;
if (0 == strcmp(event, "textSelectionChanged"))
return ax::mojom::Event::kTextSelectionChanged;
+ if (0 == strcmp(event, "windowActivated"))
+ return ax::mojom::Event::kWindowActivated;
+ if (0 == strcmp(event, "windowDeactivated"))
+ return ax::mojom::Event::kWindowDeactivated;
if (0 == strcmp(event, "treeChanged"))
return ax::mojom::Event::kTreeChanged;
if (0 == strcmp(event, "valueChanged"))
@@ -989,6 +997,8 @@ const char* ToString(ax::mojom::Action action) {
return "setValue";
case ax::mojom::Action::kShowContextMenu:
return "showContextMenu";
+ case ax::mojom::Action::kGetTextLocation:
+ return "getTextLocation";
}
return "";
@@ -1541,6 +1551,8 @@ const char* ToString(ax::mojom::BoolAttribute bool_attribute) {
return "clipsChildren";
case ax::mojom::BoolAttribute::kSelected:
return "selected";
+ case ax::mojom::BoolAttribute::kSupportsTextLocation:
+ return "supportsTextLocation";
}
return "";
@@ -1573,6 +1585,8 @@ ax::mojom::BoolAttribute ParseBoolAttribute(const char* bool_attribute) {
return ax::mojom::BoolAttribute::kClipsChildren;
if (0 == strcmp(bool_attribute, "selected"))
return ax::mojom::BoolAttribute::kSelected;
+ if (0 == strcmp(bool_attribute, "supportsTextLocation"))
+ return ax::mojom::BoolAttribute::kSupportsTextLocation;
return ax::mojom::BoolAttribute::kNone;
}
@@ -1866,79 +1880,19 @@ ax::mojom::TextPosition ParseTextPosition(const char* text_position) {
const char* ToString(ax::mojom::TextStyle text_style) {
switch (text_style) {
- case ax::mojom::TextStyle::kNone:
- return "none";
- case ax::mojom::TextStyle::kTextStyleBold:
- return "textStyleBold";
- case ax::mojom::TextStyle::kTextStyleItalic:
- return "textStyleItalic";
- case ax::mojom::TextStyle::kTextStyleBoldItalic:
- return "textStyleBoldItalic";
- case ax::mojom::TextStyle::kTextStyleUnderline:
- return "textStyleUnderline";
- case ax::mojom::TextStyle::kTextStyleBoldUnderline:
- return "textStyleBoldUnderline";
- case ax::mojom::TextStyle::kTextStyleItalicUnderline:
- return "textStyleItalicUnderline";
- case ax::mojom::TextStyle::kTextStyleBoldItalicUnderline:
- return "textStyleBoldItalicUnderline";
- case ax::mojom::TextStyle::kTextStyleLineThrough:
- return "textStyleLineThrough";
- case ax::mojom::TextStyle::kTextStyleBoldLineThrough:
- return "textStyleBoldLineThrough";
- case ax::mojom::TextStyle::kTextStyleItalicLineThrough:
- return "textStyleItalicLineThrough";
- case ax::mojom::TextStyle::kTextStyleBoldItalicLineThrough:
- return "textStyleBoldItalicLineThrough";
- case ax::mojom::TextStyle::kTextStyleUnderlineLineThrough:
- return "textStyleUnderlineLineThrough";
- case ax::mojom::TextStyle::kTextStyleBoldUnderlineLineThrough:
- return "textStyleBoldUnderlineLineThrough";
- case ax::mojom::TextStyle::kTextStyleItalicUnderlineLineThrough:
- return "textStyleItalicUnderlineLineThrough";
- case ax::mojom::TextStyle::kTextStyleBoldItalicUnderlineLineThrough:
- return "textStyleBoldItalicUnderlineLineThrough";
+ case ax::mojom::TextStyle::kBold:
+ return "bold";
+ case ax::mojom::TextStyle::kItalic:
+ return "italic";
+ case ax::mojom::TextStyle::kUnderline:
+ return "underline";
+ case ax::mojom::TextStyle::kLineThrough:
+ return "lineThrough";
}
return "";
}
-ax::mojom::TextStyle ParseTextStyle(const char* text_style) {
- if (0 == strcmp(text_style, "none"))
- return ax::mojom::TextStyle::kNone;
- if (0 == strcmp(text_style, "textStyleBold"))
- return ax::mojom::TextStyle::kTextStyleBold;
- if (0 == strcmp(text_style, "textStyleItalic"))
- return ax::mojom::TextStyle::kTextStyleItalic;
- if (0 == strcmp(text_style, "textStyleBoldItalic"))
- return ax::mojom::TextStyle::kTextStyleBoldItalic;
- if (0 == strcmp(text_style, "textStyleUnderline"))
- return ax::mojom::TextStyle::kTextStyleUnderline;
- if (0 == strcmp(text_style, "textStyleBoldUnderline"))
- return ax::mojom::TextStyle::kTextStyleBoldUnderline;
- if (0 == strcmp(text_style, "textStyleItalicUnderline"))
- return ax::mojom::TextStyle::kTextStyleItalicUnderline;
- if (0 == strcmp(text_style, "textStyleBoldItalicUnderline"))
- return ax::mojom::TextStyle::kTextStyleBoldItalicUnderline;
- if (0 == strcmp(text_style, "textStyleLineThrough"))
- return ax::mojom::TextStyle::kTextStyleLineThrough;
- if (0 == strcmp(text_style, "textStyleBoldLineThrough"))
- return ax::mojom::TextStyle::kTextStyleBoldLineThrough;
- if (0 == strcmp(text_style, "textStyleItalicLineThrough"))
- return ax::mojom::TextStyle::kTextStyleItalicLineThrough;
- if (0 == strcmp(text_style, "textStyleBoldItalicLineThrough"))
- return ax::mojom::TextStyle::kTextStyleBoldItalicLineThrough;
- if (0 == strcmp(text_style, "textStyleUnderlineLineThrough"))
- return ax::mojom::TextStyle::kTextStyleUnderlineLineThrough;
- if (0 == strcmp(text_style, "textStyleBoldUnderlineLineThrough"))
- return ax::mojom::TextStyle::kTextStyleBoldUnderlineLineThrough;
- if (0 == strcmp(text_style, "textStyleItalicUnderlineLineThrough"))
- return ax::mojom::TextStyle::kTextStyleItalicUnderlineLineThrough;
- if (0 == strcmp(text_style, "textStyleBoldItalicUnderlineLineThrough"))
- return ax::mojom::TextStyle::kTextStyleBoldItalicUnderlineLineThrough;
- return ax::mojom::TextStyle::kNone;
-}
-
const char* ToString(ax::mojom::AriaCurrentState aria_current_state) {
switch (aria_current_state) {
case ax::mojom::AriaCurrentState::kNone:
diff --git a/chromium/ui/accessibility/ax_enums.mojom b/chromium/ui/accessibility/ax_enums.mojom
index 2c35cf14722..905352e5a03 100644
--- a/chromium/ui/accessibility/ax_enums.mojom
+++ b/chromium/ui/accessibility/ax_enums.mojom
@@ -76,6 +76,8 @@ enum Event {
kShow, // Remove: http://crbug.com/392502
kStateChanged, // Native / Automation
kTextChanged,
+ kWindowActivated, // Native
+ kWindowDeactivated, // Native
kTextSelectionChanged,
kTreeChanged, // Accessibility tree changed. Don't
// explicitly fire an accessibility event,
@@ -379,6 +381,7 @@ enum Action {
kSetValue,
kShowContextMenu,
+ kGetTextLocation,
};
enum ActionFlags {
@@ -613,6 +616,9 @@ enum BoolAttribute {
// Indicates whether this node is selected or unselected.
kSelected,
+
+ // Indicates whether this node supports text location.
+ kSupportsTextLocation,
};
enum IntListAttribute {
@@ -728,23 +734,10 @@ enum TextPosition {
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.accessibility
enum TextStyle {
- kNone,
- // Assignments are ignored by the parser, but are kept here for clarity.
- kTextStyleBold = 1,
- kTextStyleItalic = 2,
- kTextStyleBoldItalic = 3,
- kTextStyleUnderline = 4,
- kTextStyleBoldUnderline = 5,
- kTextStyleItalicUnderline = 6,
- kTextStyleBoldItalicUnderline = 7,
- kTextStyleLineThrough = 8,
- kTextStyleBoldLineThrough = 9,
- kTextStyleItalicLineThrough = 10,
- kTextStyleBoldItalicLineThrough = 11,
- kTextStyleUnderlineLineThrough = 12,
- kTextStyleBoldUnderlineLineThrough = 13,
- kTextStyleItalicUnderlineLineThrough = 14,
- kTextStyleBoldItalicUnderlineLineThrough = 15,
+ kBold,
+ kItalic,
+ kUnderline,
+ kLineThrough,
};
enum AriaCurrentState {
diff --git a/chromium/ui/accessibility/ax_event_generator.cc b/chromium/ui/accessibility/ax_event_generator.cc
index ed747ec39cc..d96824cbfe7 100644
--- a/chromium/ui/accessibility/ax_event_generator.cc
+++ b/chromium/ui/accessibility/ax_event_generator.cc
@@ -270,7 +270,7 @@ void AXEventGenerator::OnBoolAttributeChanged(AXTree* tree,
AddEvent(node, Event::SELECTED_CHANGED);
ui::AXNode* container = node;
while (container &&
- !ui::IsContainerWithSelectableChildrenRole(container->data().role))
+ !ui::IsContainerWithSelectableChildren(container->data().role))
container = container->parent();
if (container)
AddEvent(container, Event::SELECTED_CHILDREN_CHANGED);
@@ -461,7 +461,8 @@ void AXEventGenerator::FireRelationSourceEvents(AXTree* tree,
// interested in under any circumstances, such as pages which have no size.
bool AXEventGenerator::ShouldFireLoadEvents(AXNode* node) {
const AXNodeData& data = node->data();
- return data.location.width() || data.location.height();
+ return data.relative_bounds.bounds.width() ||
+ data.relative_bounds.bounds.height();
}
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_event_generator_unittest.cc b/chromium/ui/accessibility/ax_event_generator_unittest.cc
index 99db15e9015..923b163f935 100644
--- a/chromium/ui/accessibility/ax_event_generator_unittest.cc
+++ b/chromium/ui/accessibility/ax_event_generator_unittest.cc
@@ -121,7 +121,7 @@ TEST(AXEventGeneratorTest, LoadCompleteSameTree) {
initial_state.root_id = 1;
initial_state.nodes.resize(1);
initial_state.nodes[0].id = 1;
- initial_state.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ initial_state.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
initial_state.has_tree_data = true;
AXTree tree(initial_state);
@@ -146,7 +146,8 @@ TEST(AXEventGeneratorTest, LoadCompleteNewTree) {
load_complete_update.root_id = 2;
load_complete_update.nodes.resize(1);
load_complete_update.nodes[0].id = 2;
- load_complete_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ load_complete_update.nodes[0].relative_bounds.bounds =
+ gfx::RectF(0, 0, 800, 600);
load_complete_update.has_tree_data = true;
load_complete_update.tree_data.loaded = true;
EXPECT_TRUE(tree.Unserialize(load_complete_update));
@@ -156,7 +157,7 @@ TEST(AXEventGeneratorTest, LoadCompleteNewTree) {
load_complete_update.root_id = 3;
load_complete_update.nodes.resize(1);
load_complete_update.nodes[0].id = 3;
- load_complete_update.nodes[0].location = gfx::RectF(0, 0, 0, 0);
+ load_complete_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 0, 0);
load_complete_update.has_tree_data = true;
load_complete_update.tree_data.loaded = true;
EXPECT_TRUE(tree.Unserialize(load_complete_update));
@@ -167,7 +168,8 @@ TEST(AXEventGeneratorTest, LoadCompleteNewTree) {
load_complete_update.root_id = 4;
load_complete_update.nodes.resize(1);
load_complete_update.nodes[0].id = 4;
- load_complete_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ load_complete_update.nodes[0].relative_bounds.bounds =
+ gfx::RectF(0, 0, 800, 600);
load_complete_update.nodes[0].AddStringAttribute(
ax::mojom::StringAttribute::kUrl, "chrome-search://foo");
load_complete_update.has_tree_data = true;
@@ -181,7 +183,7 @@ TEST(AXEventGeneratorTest, LoadStart) {
initial_state.root_id = 1;
initial_state.nodes.resize(1);
initial_state.nodes[0].id = 1;
- initial_state.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ initial_state.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
initial_state.has_tree_data = true;
AXTree tree(initial_state);
@@ -190,7 +192,8 @@ TEST(AXEventGeneratorTest, LoadStart) {
load_start_update.root_id = 2;
load_start_update.nodes.resize(1);
load_start_update.nodes[0].id = 2;
- load_start_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ load_start_update.nodes[0].relative_bounds.bounds =
+ gfx::RectF(0, 0, 800, 600);
load_start_update.has_tree_data = true;
load_start_update.tree_data.loaded = false;
EXPECT_TRUE(tree.Unserialize(load_start_update));
diff --git a/chromium/ui/accessibility/ax_language_info.h b/chromium/ui/accessibility/ax_language_info.h
new file mode 100644
index 00000000000..01b016ab48e
--- /dev/null
+++ b/chromium/ui/accessibility/ax_language_info.h
@@ -0,0 +1,49 @@
+// 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_ACCESSIBILITY_AX_LANGUAGE_INFO_H_
+#define UI_ACCESSIBILITY_AX_LANGUAGE_INFO_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+class AXNode;
+
+// An instance of LanguageInfo is used to record any specified language
+// attributes and will eventually be extended to include required information
+// for language detection.
+class AX_EXPORT AXLanguageInfo {
+ public:
+ AXLanguageInfo(const AXNode* node, std::string lang)
+ : node_(node), language_(lang) {}
+
+ AXLanguageInfo(const AXLanguageInfo& info, const AXNode* node)
+ : node_(node), language_(info.language_) {}
+
+ AXLanguageInfo(const AXLanguageInfo* info, const AXNode* node)
+ : node_(node), language_(info->language_) {}
+
+ ~AXLanguageInfo() {}
+
+ const AXNode* node() const { return node_; }
+
+ // Get language code in BCP 47.
+ const std::string& language() const { return language_; }
+
+ private:
+ const AXNode* const node_;
+ // Language code in BCP 47.
+ const std::string language_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AXLanguageInfo);
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_LANGUAGE_INFO
diff --git a/chromium/ui/accessibility/ax_language_info_unittest.cc b/chromium/ui/accessibility/ax_language_info_unittest.cc
new file mode 100644
index 00000000000..1b01ce047f0
--- /dev/null
+++ b/chromium/ui/accessibility/ax_language_info_unittest.cc
@@ -0,0 +1,70 @@
+// 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/accessibility/ax_language_info.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_tree.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+
+// Tests that AXNode::GetLanguage() terminates when there is no lang attribute.
+TEST(AXLanguageInfoTest, TestGetLanguageNoLangAttr) {
+ /* build tree including parenting, this is to exercise the code paths within
+ * AXNode::GetLanguage() which scan up the tree to handle lang inheritance.
+ * 1
+ * 2 3
+ * 4
+ */
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(4);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].child_ids.resize(2);
+ initial_state.nodes[0].child_ids[0] = 2;
+ initial_state.nodes[0].child_ids[1] = 3;
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].child_ids.resize(1);
+ initial_state.nodes[1].child_ids[0] = 4;
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[3].id = 4;
+ AXTree tree(initial_state);
+
+ // Check that tree parenting conforms to expected shape.
+ AXNode* item1 = tree.GetFromId(1);
+ EXPECT_EQ(item1->parent(), nullptr);
+
+ AXNode* item2 = tree.GetFromId(2);
+ EXPECT_EQ(item2->parent(), item1);
+ EXPECT_EQ(item2->parent()->parent(), nullptr);
+
+ AXNode* item3 = tree.GetFromId(3);
+ EXPECT_EQ(item3->parent(), item1);
+ EXPECT_EQ(item3->parent()->parent(), nullptr);
+
+ AXNode* item4 = tree.GetFromId(4);
+ EXPECT_EQ(item4->parent(), item2);
+ EXPECT_EQ(item4->parent()->parent(), item1);
+ EXPECT_EQ(item4->parent()->parent()->parent(), nullptr);
+
+ std::string item1_lang = item1->GetLanguage();
+ EXPECT_EQ(item1_lang, "");
+
+ std::string item2_lang = item2->GetLanguage();
+ EXPECT_EQ(item2_lang, "");
+
+ std::string item3_lang = item3->GetLanguage();
+ EXPECT_EQ(item3_lang, "");
+
+ std::string item4_lang = item4->GetLanguage();
+ EXPECT_EQ(item4_lang, "");
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node.cc b/chromium/ui/accessibility/ax_node.cc
index 8bb169cc990..c245a1b42ba 100644
--- a/chromium/ui/accessibility/ax_node.cc
+++ b/chromium/ui/accessibility/ax_node.cc
@@ -9,16 +9,29 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_language_info.h"
+#include "ui/accessibility/ax_role_properties.h"
+#include "ui/accessibility/ax_table_info.h"
+#include "ui/accessibility/ax_tree.h"
#include "ui/gfx/transform.h"
namespace ui {
-AXNode::AXNode(AXNode* parent, int32_t id, int32_t index_in_parent)
- : index_in_parent_(index_in_parent), parent_(parent) {
+AXNode::AXNode(AXNode::OwnerTree* tree,
+ AXNode* parent,
+ int32_t id,
+ int32_t index_in_parent)
+ : tree_(tree),
+ index_in_parent_(index_in_parent),
+ parent_(parent),
+ language_info_(nullptr) {
data_.id = id;
}
-AXNode::~AXNode() {}
+AXNode::~AXNode() {
+ if (language_info_)
+ delete language_info_;
+}
int AXNode::GetUnignoredChildCount() const {
int count = 0;
@@ -85,12 +98,12 @@ void AXNode::SetData(const AXNodeData& src) {
void AXNode::SetLocation(int32_t offset_container_id,
const gfx::RectF& location,
gfx::Transform* transform) {
- data_.offset_container_id = offset_container_id;
- data_.location = location;
+ data_.relative_bounds.offset_container_id = offset_container_id;
+ data_.relative_bounds.bounds = location;
if (transform)
- data_.transform.reset(new gfx::Transform(*transform));
+ data_.relative_bounds.transform.reset(new gfx::Transform(*transform));
else
- data_.transform.reset(nullptr);
+ data_.relative_bounds.transform.reset(nullptr);
}
void AXNode::SetIndexInParent(int index_in_parent) {
@@ -169,8 +182,551 @@ base::string16 AXNode::GetInheritedString16Attribute(
return base::UTF8ToUTF16(GetInheritedStringAttribute(attribute));
}
+const AXLanguageInfo* AXNode::GetLanguageInfo() {
+ if (language_info_)
+ return language_info_;
+
+ const auto& lang_attr =
+ GetStringAttribute(ax::mojom::StringAttribute::kLanguage);
+
+ // Promote language attribute to LanguageInfo.
+ if (!lang_attr.empty()) {
+ language_info_ = new AXLanguageInfo(this, lang_attr);
+ return language_info_;
+ }
+
+ // Try search for language through parent instead.
+ if (!parent())
+ return nullptr;
+
+ const AXLanguageInfo* parent_lang_info = parent()->GetLanguageInfo();
+ if (!parent_lang_info)
+ return nullptr;
+
+ // Cache the results on this node.
+ language_info_ = new AXLanguageInfo(parent_lang_info, this);
+ return language_info_;
+}
+
+std::string AXNode::GetLanguage() {
+ const AXLanguageInfo* lang_info = GetLanguageInfo();
+
+ if (lang_info)
+ return lang_info->language();
+
+ return "";
+}
+
std::ostream& operator<<(std::ostream& stream, const AXNode& node) {
return stream << node.data().ToString();
}
+bool AXNode::IsTable() const {
+ return IsTableLike(data().role);
+}
+
+int32_t AXNode::GetTableColCount() const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return 0;
+
+ return table_info->col_count;
+}
+
+int32_t AXNode::GetTableRowCount() const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return 0;
+
+ return table_info->row_count;
+}
+
+int32_t AXNode::GetTableAriaColCount() const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return 0;
+
+ return table_info->aria_col_count;
+}
+
+int32_t AXNode::GetTableAriaRowCount() const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return 0;
+
+ return table_info->aria_row_count;
+}
+
+int32_t AXNode::GetTableCellCount() const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return 0;
+
+ return static_cast<int32_t>(table_info->unique_cell_ids.size());
+}
+
+AXNode* AXNode::GetTableCellFromIndex(int32_t index) const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return nullptr;
+
+ if (index < 0 ||
+ index >= static_cast<int32_t>(table_info->unique_cell_ids.size()))
+ return nullptr;
+
+ return tree_->GetFromId(table_info->unique_cell_ids[index]);
+}
+
+AXNode* AXNode::GetTableCellFromCoords(int32_t row_index,
+ int32_t col_index) const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return nullptr;
+
+ if (row_index < 0 || row_index >= table_info->row_count || col_index < 0 ||
+ col_index >= table_info->col_count)
+ return nullptr;
+
+ return tree_->GetFromId(table_info->cell_ids[row_index][col_index]);
+}
+
+void AXNode::GetTableColHeaderNodeIds(
+ int32_t col_index,
+ std::vector<int32_t>* col_header_ids) const {
+ DCHECK(col_header_ids);
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return;
+
+ if (col_index < 0 || col_index >= table_info->col_count)
+ return;
+
+ for (size_t i = 0; i < table_info->col_headers[col_index].size(); i++)
+ col_header_ids->push_back(table_info->col_headers[col_index][i]);
+}
+
+void AXNode::GetTableRowHeaderNodeIds(
+ int32_t row_index,
+ std::vector<int32_t>* row_header_ids) const {
+ DCHECK(row_header_ids);
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return;
+
+ if (row_index < 0 || row_index >= table_info->row_count)
+ return;
+
+ for (size_t i = 0; i < table_info->row_headers[row_index].size(); i++)
+ row_header_ids->push_back(table_info->row_headers[row_index][i]);
+}
+
+void AXNode::GetTableUniqueCellIds(std::vector<int32_t>* cell_ids) const {
+ DCHECK(cell_ids);
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return;
+
+ cell_ids->assign(table_info->unique_cell_ids.begin(),
+ table_info->unique_cell_ids.end());
+}
+
+std::vector<AXNode*>* AXNode::GetExtraMacNodes() const {
+ AXTableInfo* table_info = tree_->GetTableInfo(this);
+ if (!table_info)
+ return nullptr;
+
+ return &table_info->extra_mac_nodes;
+}
+
+//
+// Table row-like nodes.
+//
+
+bool AXNode::IsTableRow() const {
+ return data().role == ax::mojom::Role::kRow;
+}
+
+int32_t AXNode::GetTableRowRowIndex() const {
+ // TODO(dmazzoni): Compute from AXTableInfo. http://crbug.com/832289
+ int32_t row_index = 0;
+ GetIntAttribute(ax::mojom::IntAttribute::kTableRowIndex, &row_index);
+ return row_index;
+}
+
+//
+// Table cell-like nodes.
+//
+
+bool AXNode::IsTableCellOrHeader() const {
+ return IsCellOrTableHeader(data().role);
+}
+
+int32_t AXNode::GetTableCellIndex() const {
+ if (!IsTableCellOrHeader())
+ return -1;
+
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return -1;
+
+ const auto& iter = table_info->cell_id_to_index.find(id());
+ if (iter != table_info->cell_id_to_index.end())
+ return iter->second;
+
+ return -1;
+}
+
+int32_t AXNode::GetTableCellColIndex() const {
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return 0;
+
+ int32_t index = GetTableCellIndex();
+ if (index == -1)
+ return 0;
+
+ return table_info->cell_data_vector[index].col_index;
+}
+
+int32_t AXNode::GetTableCellRowIndex() const {
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return 0;
+
+ int32_t index = GetTableCellIndex();
+ if (index == -1)
+ return 0;
+
+ return table_info->cell_data_vector[index].row_index;
+}
+
+int32_t AXNode::GetTableCellColSpan() const {
+ // If it's not a table cell, don't return a col span.
+ if (!IsTableCellOrHeader())
+ return 0;
+
+ // Otherwise, try to return a colspan, with 1 as the default if it's not
+ // specified.
+ int32_t col_span = 1;
+ if (GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnSpan, &col_span))
+ return col_span;
+
+ return 1;
+}
+
+int32_t AXNode::GetTableCellRowSpan() const {
+ // If it's not a table cell, don't return a row span.
+ if (!IsTableCellOrHeader())
+ return 0;
+
+ // Otherwise, try to return a row span, with 1 as the default if it's not
+ // specified.
+ int32_t row_span = 1;
+ if (GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowSpan, &row_span))
+ return row_span;
+ return 1;
+}
+
+int32_t AXNode::GetTableCellAriaColIndex() const {
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return -0;
+
+ int32_t index = GetTableCellIndex();
+ if (index == -1)
+ return 0;
+
+ return table_info->cell_data_vector[index].aria_col_index;
+}
+
+int32_t AXNode::GetTableCellAriaRowIndex() const {
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return -0;
+
+ int32_t index = GetTableCellIndex();
+ if (index == -1)
+ return 0;
+
+ return table_info->cell_data_vector[index].aria_row_index;
+}
+
+void AXNode::GetTableCellColHeaderNodeIds(
+ std::vector<int32_t>* col_header_ids) const {
+ DCHECK(col_header_ids);
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return;
+
+ int32_t col_index = GetTableCellColIndex();
+ if (col_index < 0 || col_index >= table_info->col_count)
+ return;
+
+ for (size_t i = 0; i < table_info->col_headers[col_index].size(); i++)
+ col_header_ids->push_back(table_info->col_headers[col_index][i]);
+}
+
+void AXNode::GetTableCellColHeaders(std::vector<AXNode*>* col_headers) const {
+ DCHECK(col_headers);
+
+ std::vector<int32_t> col_header_ids;
+ GetTableCellColHeaderNodeIds(&col_header_ids);
+ IdVectorToNodeVector(col_header_ids, col_headers);
+}
+
+void AXNode::GetTableCellRowHeaderNodeIds(
+ std::vector<int32_t>* row_header_ids) const {
+ DCHECK(row_header_ids);
+ AXTableInfo* table_info = GetAncestorTableInfo();
+ if (!table_info)
+ return;
+
+ int32_t row_index = GetTableCellRowIndex();
+ if (row_index < 0 || row_index >= table_info->row_count)
+ return;
+
+ for (size_t i = 0; i < table_info->row_headers[row_index].size(); i++)
+ row_header_ids->push_back(table_info->row_headers[row_index][i]);
+}
+
+void AXNode::GetTableCellRowHeaders(std::vector<AXNode*>* row_headers) const {
+ DCHECK(row_headers);
+
+ std::vector<int32_t> row_header_ids;
+ GetTableCellRowHeaderNodeIds(&row_header_ids);
+ IdVectorToNodeVector(row_header_ids, row_headers);
+}
+
+AXTableInfo* AXNode::GetAncestorTableInfo() const {
+ const AXNode* node = this;
+ while (node && !node->IsTable())
+ node = node->parent();
+ if (node)
+ return tree_->GetTableInfo(node);
+ return nullptr;
+}
+
+void AXNode::IdVectorToNodeVector(std::vector<int32_t>& ids,
+ std::vector<AXNode*>* nodes) const {
+ for (int32_t id : ids) {
+ AXNode* node = tree_->GetFromId(id);
+ if (node)
+ nodes->push_back(node);
+ }
+}
+
+// Returns true if the node's role uses PosInSet and SetSize
+// Returns false otherwise.
+bool AXNode::IsSetSizePosInSetUsedInRole() const {
+ switch (data().role) {
+ case ax::mojom::Role::kArticle:
+ case ax::mojom::Role::kListItem:
+ case ax::mojom::Role::kMenuItem:
+ case ax::mojom::Role::kMenuItemRadio:
+ case ax::mojom::Role::kTab:
+ case ax::mojom::Role::kMenuItemCheckBox:
+ case ax::mojom::Role::kTreeItem:
+ case ax::mojom::Role::kListBoxOption:
+ case ax::mojom::Role::kRadioButton:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// Returns true if a node's role matches with the role of its container.
+// Returns false otherwise.
+bool AXNode::ContainerRoleMatches(AXNode* container) const {
+ ax::mojom::Role container_role = container->data().role;
+ switch (data().role) {
+ case ax::mojom::Role::kArticle:
+ return container_role == ax::mojom::Role::kFeed;
+
+ case ax::mojom::Role::kListItem:
+ return container_role == ax::mojom::Role::kList ||
+ container_role == ax::mojom::Role::kGroup;
+
+ case ax::mojom::Role::kMenuItem:
+ return container_role == ax::mojom::Role::kMenu ||
+ container_role == ax::mojom::Role::kGroup ||
+ container_role == ax::mojom::Role::kMenuBar;
+
+ case ax::mojom::Role::kMenuItemRadio:
+ return container_role == ax::mojom::Role::kGroup ||
+ container_role == ax::mojom::Role::kMenu ||
+ container_role == ax::mojom::Role::kMenuBar;
+
+ case ax::mojom::Role::kTab:
+ return container_role == ax::mojom::Role::kTabList;
+
+ case ax::mojom::Role::kMenuItemCheckBox:
+ return container_role == ax::mojom::Role::kMenu ||
+ container_role == ax::mojom::Role::kMenuBar;
+
+ case ax::mojom::Role::kTreeItem:
+ return container_role == ax::mojom::Role::kTree ||
+ container_role == ax::mojom::Role::kGroup;
+
+ case ax::mojom::Role::kListBoxOption:
+ return container_role == ax::mojom::Role::kListBox;
+
+ case ax::mojom::Role::kRadioButton:
+ return container_role == ax::mojom::Role::kRadioGroup;
+
+ default:
+ return false;
+ }
+}
+
+int32_t AXNode::GetPosInSet() {
+ int32_t pos = -1;
+ int32_t size = -1;
+ ComputeSetSizePosInSet(&pos, &size);
+ return pos;
+}
+int32_t AXNode::GetSetSize() {
+ int32_t pos = -1;
+ int32_t size = -1;
+ ComputeSetSizePosInSet(&pos, &size);
+ return size;
+}
+
+// Finds and returns a pointer to node's container.
+// Is not required to have a role that matches node's role.
+// Returns nullptr if node is not contained within container.
+AXNode* AXNode::GetContainer() const {
+ AXNode* result = parent();
+ // Continue walking up while parent is invalid, ignored, or is a generic
+ // container.
+ while ((result && result->data().HasState(ax::mojom::State::kIgnored)) ||
+ result->data().role == ax::mojom::Role::kGenericContainer ||
+ result->data().role == ax::mojom::Role::kIgnored) {
+ result = result->parent();
+ }
+ return result;
+}
+
+// Populates items vector with all nodes within container whose roles match.
+void AXNode::PopulateContainerItems(AXNode* container,
+ AXNode* local_parent,
+ std::vector<AXNode*>& items) const {
+ // Stop searching current path if roles of local_parent and container match.
+ // Don't compare the container to itself.
+ if (!(container == local_parent))
+ if (local_parent->data().role == container->data().role)
+ return;
+
+ for (int i = 0; i < local_parent->child_count(); ++i) {
+ AXNode* child = local_parent->children_[i];
+ // Add child to items if role matches with root container's role.
+ if (child->ContainerRoleMatches(container))
+ items.push_back(child);
+ // Recurse if there is a generic container or is ignored.
+ if (child->data().role == ax::mojom::Role::kGenericContainer ||
+ child->data().role == ax::mojom::Role::kIgnored) {
+ PopulateContainerItems(container, child, items);
+ }
+ }
+}
+
+// Computes pos_in_set and set_size values for this node.
+void AXNode::ComputeSetSizePosInSet(int32_t* out_pos_in_set,
+ int32_t* out_set_size) {
+ // Error checks
+ AXNode* container = GetContainer();
+ if (!(container && IsSetSizePosInSetUsedInRole() &&
+ ContainerRoleMatches(container))) {
+ *out_pos_in_set = 0;
+ *out_set_size = 0;
+ return;
+ }
+
+ // Find all items within parent container and add to vector.
+ std::vector<AXNode*> items;
+ PopulateContainerItems(container, container, items);
+
+ // Necessary for calculating set_size. Keeps track of largest assigned
+ // kSetSize for each role.
+ std::unordered_map<ax::mojom::Role, int> largest_assigned_set_size;
+
+ // Iterate over vector of items and calculate pos_in_set and set_size for
+ // each. Items is not guaranteed to be populated with items of the same role.
+ // Use dictionary that maps role to frequency to calculate pos_in_set.
+ std::unordered_map<ax::mojom::Role, int> role_counts;
+ AXNode* node;
+ ax::mojom::Role node_role;
+
+ // Compute pos_in_set values.
+ for (unsigned int i = 0; i < items.size(); ++i) {
+ node = items[i];
+ node_role = node->data().role;
+ int32_t pos_in_set_value = 0;
+
+ if (role_counts.find(node_role) == role_counts.end())
+ // This is the first node with its role.
+ pos_in_set_value = 1;
+ else {
+ // This is the next node with its role.
+ pos_in_set_value = role_counts[node_role] + 1;
+ }
+
+ // Check if node has kPosInSet assigned. This assignment takes precedence
+ // over previous assignment.
+ if (node->HasIntAttribute(ax::mojom::IntAttribute::kPosInSet)) {
+ pos_in_set_value =
+ node->GetIntAttribute(ax::mojom::IntAttribute::kPosInSet);
+ // If invalid assignment (decrease or duplicate), adjust value.
+ if (pos_in_set_value <= role_counts[node_role]) {
+ pos_in_set_value = role_counts[node_role] + 1;
+ }
+ }
+
+ // Assign pos_in_set and update role counts.
+ if (node == this) {
+ *out_pos_in_set = pos_in_set_value;
+ }
+ role_counts[node_role] = pos_in_set_value;
+
+ // Check if kSetSize is assigned and update if it's the largest assigned
+ // kSetSize.
+ if (node->HasIntAttribute(ax::mojom::IntAttribute::kSetSize))
+ largest_assigned_set_size[node_role] =
+ std::max(largest_assigned_set_size[node_role],
+ node->GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+ }
+
+ // Compute set_size values.
+ for (unsigned int j = 0; j < items.size(); ++j) {
+ node = items[j];
+ node_role = node->data().role;
+
+ // TODO (akihiroota): List objects should report SetSize
+
+ // The SetSize of a node is the maximum of the following candidate values:
+ // 1. The PosInSet of the last value in the container (with same role as
+ // node's)
+ // 2. The Largest assigned SetSize in the container
+ // 3. The SetSize assigned within the node's container
+ int32_t pos_candidate = role_counts[node_role];
+ int32_t largest_set_size_candidate = 0;
+ if (largest_assigned_set_size.find(node_role) !=
+ largest_assigned_set_size.end()) {
+ largest_set_size_candidate = largest_assigned_set_size[node_role];
+ }
+ int32_t container_candidate = 0;
+ if (container->HasIntAttribute(ax::mojom::IntAttribute::kSetSize)) {
+ container_candidate =
+ container->GetIntAttribute(ax::mojom::IntAttribute::kSetSize);
+ }
+
+ // Assign set_size
+ if (node == this) {
+ *out_set_size =
+ std::max(std::max(pos_candidate, largest_set_size_candidate),
+ container_candidate);
+ }
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node.h b/chromium/ui/accessibility/ax_node.h
index d28e09f30c4..8b9c5ca4dda 100644
--- a/chromium/ui/accessibility/ax_node.h
+++ b/chromium/ui/accessibility/ax_node.h
@@ -15,16 +15,32 @@
namespace ui {
+class AXTableInfo;
+class AXLanguageInfo;
+
// One node in an AXTree.
class AX_EXPORT AXNode final {
public:
+ // Interface to the tree class that owns an AXNode. We use this instead
+ // of letting AXNode have a pointer to its AXTree directly so that we're
+ // forced to think twice before calling an AXTree interface that might not
+ // be necessary.
+ class OwnerTree {
+ public:
+ // See AXTree.
+ virtual AXTableInfo* GetTableInfo(const AXNode* table_node) const = 0;
+ // See AXTree.
+ virtual AXNode* GetFromId(int32_t id) const = 0;
+ };
+
// The constructor requires a parent, id, and index in parent, but
// the data is not required. After initialization, only index_in_parent
// is allowed to change, the others are guaranteed to never change.
- AXNode(AXNode* parent, int32_t id, int32_t index_in_parent);
+ AXNode(OwnerTree* tree, AXNode* parent, int32_t id, int32_t index_in_parent);
virtual ~AXNode();
// Accessors.
+ OwnerTree* tree() const { return tree_; }
int32_t id() const { return data_.id; }
AXNode* parent() const { return parent_; }
int child_count() const { return static_cast<int>(children_.size()); }
@@ -166,21 +182,117 @@ class AX_EXPORT AXNode final {
return data().GetHtmlAttribute(attribute, value);
}
+ // PosInSet and SetSize public methods
+ int32_t GetPosInSet();
+ int32_t GetSetSize();
+
const std::string& GetInheritedStringAttribute(
ax::mojom::StringAttribute attribute) const;
base::string16 GetInheritedString16Attribute(
ax::mojom::StringAttribute attribute) const;
+ // Return a pointer to a string for the language code.
+ // This will consider the language declared in the DOM, and may eventually
+ // attempt to automatically detect the language from the text.
+ //
+ // This language code will be BCP 47.
+ //
+ // Returns empty string if no appropriate language was found.
+ std::string GetLanguage();
+
+ //
+ // Helper functions for tables, table rows, and table cells.
+ // Most of these functions construct and cache an AXTableInfo behind
+ // the scenes to infer many properties of tables.
+ //
+ // These interfaces use attributes provided by the source of the
+ // AX tree where possible, but fills in missing details and ignores
+ // specified attributes when they're bad or inconsistent. That way
+ // you're guaranteed to get a valid, consistent table when using these
+ // interfaces.
+ //
+
+ // Table-like nodes (including grids). All indices are 0-based except
+ // ARIA indices are all 1-based. In other words, the top-left corner
+ // of the table is row 0, column 0, cell index 0 - but that same cell
+ // has a minimum ARIA row index of 1 and column index of 1.
+ bool IsTable() const;
+ int32_t GetTableColCount() const;
+ int32_t GetTableRowCount() const;
+ int32_t GetTableAriaColCount() const;
+ int32_t GetTableAriaRowCount() const;
+ int32_t GetTableCellCount() const;
+ AXNode* GetTableCellFromIndex(int32_t index) const;
+ AXNode* GetTableCellFromCoords(int32_t row_index, int32_t col_index) const;
+ void GetTableColHeaderNodeIds(int32_t col_index,
+ std::vector<int32_t>* col_header_ids) const;
+ void GetTableRowHeaderNodeIds(int32_t row_index,
+ std::vector<int32_t>* row_header_ids) const;
+ void GetTableUniqueCellIds(std::vector<int32_t>* row_header_ids) const;
+ // Extra computed nodes for the accessibility tree for macOS:
+ // one column node for each table column, followed by one
+ // table header container node, or nullptr if not applicable.
+ std::vector<AXNode*>* GetExtraMacNodes() const;
+
+ // Table row-like nodes.
+ bool IsTableRow() const;
+ int32_t GetTableRowRowIndex() const;
+
+ // Table cell-like nodes.
+ bool IsTableCellOrHeader() const;
+ int32_t GetTableCellIndex() const;
+ int32_t GetTableCellColIndex() const;
+ int32_t GetTableCellRowIndex() const;
+ int32_t GetTableCellColSpan() const;
+ int32_t GetTableCellRowSpan() const;
+ int32_t GetTableCellAriaColIndex() const;
+ int32_t GetTableCellAriaRowIndex() const;
+ void GetTableCellColHeaderNodeIds(std::vector<int32_t>* col_header_ids) const;
+ void GetTableCellRowHeaderNodeIds(std::vector<int32_t>* row_header_ids) const;
+ void GetTableCellColHeaders(std::vector<AXNode*>* col_headers) const;
+ void GetTableCellRowHeaders(std::vector<AXNode*>* row_headers) const;
+
private:
// Computes the text offset where each line starts by traversing all child
// leaf nodes.
void ComputeLineStartOffsets(std::vector<int>* line_offsets,
int* start_offset) const;
-
+ AXTableInfo* GetAncestorTableInfo() const;
+ void IdVectorToNodeVector(std::vector<int32_t>& ids,
+ std::vector<AXNode*>* nodes) const;
+
+ // Helpers for GetPosInSet and GetSetSize.
+ // Returns true if the role of parent container matches the role of node.
+ // Returns false otherwise.
+ bool ContainerRoleMatches(AXNode* parent) const;
+ // Returns true if the node's role uses PosInSet and SetSize
+ // Returns false otherwise.
+ bool IsSetSizePosInSetUsedInRole() const;
+ // Finds and returns a pointer to node's container.
+ AXNode* GetContainer() const;
+ // Populates items vector with all nodes within container whose roles match.
+ void PopulateContainerItems(AXNode* container,
+ AXNode* local_parent,
+ std::vector<AXNode*>& items) const;
+ // Computes pos_in_set and set_size values for this node.
+ void ComputeSetSizePosInSet(int32_t* out_pos_in_set, int32_t* out_set_size);
+
+ OwnerTree* tree_; // Owns this.
int index_in_parent_;
AXNode* parent_;
std::vector<AXNode*> children_;
AXNodeData data_;
+
+ AXLanguageInfo* language_info_;
+
+ // Return an object containing information about the languages used.
+ // Will walk up tree if needed to determine language.
+ //
+ // Clients should not retain this pointer, instead they should request it
+ // every time it is needed.
+ //
+ // Returns nullptr if the node has no detectable language.
+ const AXLanguageInfo* GetLanguageInfo();
};
AX_EXPORT std::ostream& operator<<(std::ostream& stream, const AXNode& node);
diff --git a/chromium/ui/accessibility/ax_node_data.cc b/chromium/ui/accessibility/ax_node_data.cc
index 9f72d3026df..7dfeb25678c 100644
--- a/chromium/ui/accessibility/ax_node_data.cc
+++ b/chromium/ui/accessibility/ax_node_data.cc
@@ -10,6 +10,7 @@
#include <set>
#include "base/no_destructor.h"
+#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -23,18 +24,18 @@ namespace ui {
namespace {
bool IsFlagSet(uint32_t bitfield, uint32_t flag) {
- return 0 != (bitfield & (1 << flag));
+ return (bitfield & (1 << flag)) != 0;
}
uint32_t ModifyFlag(uint32_t bitfield, uint32_t flag, bool set) {
return set ? (bitfield |= (1 << flag)) : (bitfield &= ~(1 << flag));
}
-std::string StateBitfieldToString(uint32_t state) {
+std::string StateBitfieldToString(uint32_t state_enum) {
std::string str;
for (uint32_t i = static_cast<uint32_t>(ax::mojom::State::kNone) + 1;
i <= static_cast<uint32_t>(ax::mojom::State::kMaxValue); ++i) {
- if (IsFlagSet(state, i))
+ if (IsFlagSet(state_enum, i))
str += " " +
base::ToUpperASCII(ui::ToString(static_cast<ax::mojom::State>(i)));
}
@@ -205,10 +206,7 @@ AXNodeData::AXNodeData(const AXNodeData& other) {
stringlist_attributes = other.stringlist_attributes;
html_attributes = other.html_attributes;
child_ids = other.child_ids;
- location = other.location;
- offset_container_id = other.offset_container_id;
- if (other.transform)
- transform.reset(new gfx::Transform(*other.transform));
+ relative_bounds = other.relative_bounds;
}
AXNodeData& AXNodeData::operator=(AXNodeData other) {
@@ -224,12 +222,7 @@ AXNodeData& AXNodeData::operator=(AXNodeData other) {
stringlist_attributes = other.stringlist_attributes;
html_attributes = other.html_attributes;
child_ids = other.child_ids;
- location = other.location;
- offset_container_id = other.offset_container_id;
- if (other.transform)
- transform.reset(new gfx::Transform(*other.transform));
- else
- transform.reset(nullptr);
+ relative_bounds = other.relative_bounds;
return *this;
}
@@ -310,9 +303,8 @@ bool AXNodeData::HasStringAttribute(
const std::string& AXNodeData::GetStringAttribute(
ax::mojom::StringAttribute attribute) const {
- static base::NoDestructor<std::string> empty_string;
auto iter = FindInVectorOfPairs(attribute, string_attributes);
- return iter != string_attributes.end() ? iter->second : *empty_string;
+ return iter != string_attributes.end() ? iter->second : base::EmptyString();
}
bool AXNodeData::GetStringAttribute(ax::mojom::StringAttribute attribute,
@@ -351,7 +343,7 @@ bool AXNodeData::HasIntListAttribute(
const std::vector<int32_t>& AXNodeData::GetIntListAttribute(
ax::mojom::IntListAttribute attribute) const {
- static base::NoDestructor<std::vector<int32_t>> empty_vector;
+ static const base::NoDestructor<std::vector<int32_t>> empty_vector;
auto iter = FindInVectorOfPairs(attribute, intlist_attributes);
if (iter != intlist_attributes.end())
return iter->second;
@@ -377,7 +369,7 @@ bool AXNodeData::HasStringListAttribute(
const std::vector<std::string>& AXNodeData::GetStringListAttribute(
ax::mojom::StringListAttribute attribute) const {
- static base::NoDestructor<std::vector<std::string>> empty_vector;
+ static const base::NoDestructor<std::vector<std::string>> empty_vector;
auto iter = FindInVectorOfPairs(attribute, stringlist_attributes);
if (iter != stringlist_attributes.end())
return iter->second;
@@ -428,6 +420,13 @@ void AXNodeData::AddIntAttribute(ax::mojom::IntAttribute attribute, int value) {
int_attributes.push_back(std::make_pair(attribute, value));
}
+void AXNodeData::RemoveIntAttribute(ax::mojom::IntAttribute attribute) {
+ DCHECK_GE(static_cast<int>(attribute), 0);
+ base::EraseIf(int_attributes, [attribute](const auto& int_attribute) {
+ return int_attribute.first == attribute;
+ });
+}
+
void AXNodeData::AddFloatAttribute(ax::mojom::FloatAttribute attribute,
float value) {
float_attributes.push_back(std::make_pair(attribute, value));
@@ -511,16 +510,34 @@ bool AXNodeData::HasState(ax::mojom::State state_enum) const {
return IsFlagSet(state, static_cast<uint32_t>(state_enum));
}
-bool AXNodeData::HasAction(ax::mojom::Action action_enum) const {
- return IsFlagSet(actions, static_cast<uint32_t>(action_enum));
+bool AXNodeData::HasAction(ax::mojom::Action action) const {
+ return IsFlagSet(actions, static_cast<uint32_t>(action));
+}
+
+bool AXNodeData::HasTextStyle(ax::mojom::TextStyle text_style_enum) const {
+ int32_t style = GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
+ return IsFlagSet(style, static_cast<uint32_t>(text_style_enum));
}
-void AXNodeData::AddState(ax::mojom::State state_enum) {
- DCHECK_NE(state_enum, ax::mojom::State::kNone);
+ax::mojom::State AXNodeData::AddState(ax::mojom::State state_enum) {
+ DCHECK_GT(static_cast<int>(state_enum),
+ static_cast<int>(ax::mojom::State::kNone));
+ DCHECK_LE(static_cast<int>(state_enum),
+ static_cast<int>(ax::mojom::State::kMaxValue));
state = ModifyFlag(state, static_cast<uint32_t>(state_enum), true);
+ return static_cast<ax::mojom::State>(state);
+}
+
+ax::mojom::State AXNodeData::RemoveState(ax::mojom::State state_enum) {
+ DCHECK_GT(static_cast<int>(state_enum),
+ static_cast<int>(ax::mojom::State::kNone));
+ DCHECK_LE(static_cast<int>(state_enum),
+ static_cast<int>(ax::mojom::State::kMaxValue));
+ state = ModifyFlag(state, static_cast<uint32_t>(state_enum), false);
+ return static_cast<ax::mojom::State>(state);
}
-void AXNodeData::AddAction(ax::mojom::Action action_enum) {
+ax::mojom::Action AXNodeData::AddAction(ax::mojom::Action action_enum) {
switch (action_enum) {
case ax::mojom::Action::kNone:
NOTREACHED();
@@ -560,15 +577,136 @@ void AXNodeData::AddAction(ax::mojom::Action action_enum) {
case ax::mojom::Action::kScrollDown:
case ax::mojom::Action::kScrollLeft:
case ax::mojom::Action::kScrollRight:
+ case ax::mojom::Action::kGetTextLocation:
break;
}
actions = ModifyFlag(actions, static_cast<uint32_t>(action_enum), true);
+ return static_cast<ax::mojom::Action>(actions);
}
-void AXNodeData::RemoveState(ax::mojom::State state_enum) {
- DCHECK_NE(state_enum, ax::mojom::State::kNone);
- state = ModifyFlag(state, static_cast<uint32_t>(state_enum), false);
+void AXNodeData::AddTextStyle(ax::mojom::TextStyle text_style_enum) {
+ DCHECK_GE(static_cast<int>(text_style_enum),
+ static_cast<int>(ax::mojom::TextStyle::kMinValue));
+ DCHECK_LE(static_cast<int>(text_style_enum),
+ static_cast<int>(ax::mojom::TextStyle::kMaxValue));
+ int32_t style = GetIntAttribute(ax::mojom::IntAttribute::kTextStyle);
+ style = ModifyFlag(style, static_cast<uint32_t>(text_style_enum), true);
+ RemoveIntAttribute(ax::mojom::IntAttribute::kTextStyle);
+ AddIntAttribute(ax::mojom::IntAttribute::kTextStyle, style);
+}
+
+ax::mojom::CheckedState AXNodeData::GetCheckedState() const {
+ return static_cast<ax::mojom::CheckedState>(
+ GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
+}
+
+void AXNodeData::SetCheckedState(ax::mojom::CheckedState checked_state) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kCheckedState);
+ if (checked_state != ax::mojom::CheckedState::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kCheckedState,
+ static_cast<int32_t>(checked_state));
+ }
+}
+
+ax::mojom::DefaultActionVerb AXNodeData::GetDefaultActionVerb() const {
+ return static_cast<ax::mojom::DefaultActionVerb>(
+ GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb));
+}
+
+void AXNodeData::SetDefaultActionVerb(
+ ax::mojom::DefaultActionVerb default_action_verb) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb);
+ if (default_action_verb != ax::mojom::DefaultActionVerb::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb,
+ static_cast<int32_t>(default_action_verb));
+ }
+}
+
+ax::mojom::HasPopup AXNodeData::GetHasPopup() const {
+ return static_cast<ax::mojom::HasPopup>(
+ GetIntAttribute(ax::mojom::IntAttribute::kHasPopup));
+}
+
+void AXNodeData::SetHasPopup(ax::mojom::HasPopup has_popup) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kHasPopup))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kHasPopup);
+ if (has_popup != ax::mojom::HasPopup::kFalse) {
+ AddIntAttribute(ax::mojom::IntAttribute::kHasPopup,
+ static_cast<int32_t>(has_popup));
+ }
+}
+
+ax::mojom::InvalidState AXNodeData::GetInvalidState() const {
+ return static_cast<ax::mojom::InvalidState>(
+ GetIntAttribute(ax::mojom::IntAttribute::kInvalidState));
+}
+
+void AXNodeData::SetInvalidState(ax::mojom::InvalidState invalid_state) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kInvalidState))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kInvalidState);
+ if (invalid_state != ax::mojom::InvalidState::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kInvalidState,
+ static_cast<int32_t>(invalid_state));
+ }
+}
+
+ax::mojom::NameFrom AXNodeData::GetNameFrom() const {
+ return static_cast<ax::mojom::NameFrom>(
+ GetIntAttribute(ax::mojom::IntAttribute::kNameFrom));
+}
+
+void AXNodeData::SetNameFrom(ax::mojom::NameFrom name_from) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kNameFrom))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kNameFrom);
+ if (name_from != ax::mojom::NameFrom::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
+ static_cast<int32_t>(name_from));
+ }
+}
+
+ax::mojom::TextPosition AXNodeData::GetTextPosition() const {
+ return static_cast<ax::mojom::TextPosition>(
+ GetIntAttribute(ax::mojom::IntAttribute::kTextPosition));
+}
+
+void AXNodeData::SetTextPosition(ax::mojom::TextPosition text_position) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kTextPosition))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kTextPosition);
+ if (text_position != ax::mojom::TextPosition::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kTextPosition,
+ static_cast<int32_t>(text_position));
+ }
+}
+
+ax::mojom::Restriction AXNodeData::GetRestriction() const {
+ return static_cast<ax::mojom::Restriction>(
+ GetIntAttribute(ax::mojom::IntAttribute::kRestriction));
+}
+
+void AXNodeData::SetRestriction(ax::mojom::Restriction restriction) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kRestriction))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kRestriction);
+ if (restriction != ax::mojom::Restriction::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kRestriction,
+ static_cast<int32_t>(restriction));
+ }
+}
+
+ax::mojom::TextDirection AXNodeData::GetTextDirection() const {
+ return static_cast<ax::mojom::TextDirection>(
+ GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
+}
+
+void AXNodeData::SetTextDirection(ax::mojom::TextDirection text_direction) {
+ if (HasIntAttribute(ax::mojom::IntAttribute::kTextDirection))
+ RemoveIntAttribute(ax::mojom::IntAttribute::kTextDirection);
+ if (text_direction != ax::mojom::TextDirection::kNone) {
+ AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
+ static_cast<int32_t>(text_direction));
+ }
}
std::string AXNodeData::ToString() const {
@@ -580,17 +718,17 @@ std::string AXNodeData::ToString() const {
result += StateBitfieldToString(state);
- result += " (" + base::NumberToString(location.x()) + ", " +
- base::NumberToString(location.y()) + ")-(" +
- base::NumberToString(location.width()) + ", " +
- base::NumberToString(location.height()) + ")";
+ result += " (" + base::NumberToString(relative_bounds.bounds.x()) + ", " +
+ base::NumberToString(relative_bounds.bounds.y()) + ")-(" +
+ base::NumberToString(relative_bounds.bounds.width()) + ", " +
+ base::NumberToString(relative_bounds.bounds.height()) + ")";
- if (offset_container_id != -1)
- result +=
- " offset_container_id=" + base::NumberToString(offset_container_id);
+ if (relative_bounds.offset_container_id != -1)
+ result += " offset_container_id=" +
+ base::NumberToString(relative_bounds.offset_container_id);
- if (transform && !transform->IsIdentity())
- result += " transform=" + transform->ToString();
+ if (relative_bounds.transform && !relative_bounds.transform->IsIdentity())
+ result += " transform=" + relative_bounds.transform->ToString();
for (const std::pair<ax::mojom::IntAttribute, int32_t>& int_attribute :
int_attributes) {
@@ -794,21 +932,14 @@ std::string AXNodeData::ToString() const {
}
break;
case ax::mojom::IntAttribute::kTextStyle: {
- int32_t text_style = int_attribute.second;
- if (text_style == static_cast<int32_t>(ax::mojom::TextStyle::kNone))
- break;
- std::string text_style_value(" text_style=");
- if (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleBold))
+ std::string text_style_value;
+ if (HasTextStyle(ax::mojom::TextStyle::kBold))
text_style_value += "bold,";
- if (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleItalic))
+ if (HasTextStyle(ax::mojom::TextStyle::kItalic))
text_style_value += "italic,";
- if (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleUnderline))
+ if (HasTextStyle(ax::mojom::TextStyle::kUnderline))
text_style_value += "underline,";
- if (text_style &
- static_cast<int32_t>(ax::mojom::TextStyle::kTextStyleLineThrough))
+ if (HasTextStyle(ax::mojom::TextStyle::kLineThrough))
text_style_value += "line-through,";
result += text_style_value.substr(0, text_style_value.size() - 1);
break;
@@ -1047,6 +1178,9 @@ std::string AXNodeData::ToString() const {
case ax::mojom::BoolAttribute::kSelected:
result += " selected=" + value;
break;
+ case ax::mojom::BoolAttribute::kSupportsTextLocation:
+ result += " supports_text_location=" + value;
+ break;
case ax::mojom::BoolAttribute::kNone:
break;
}
diff --git a/chromium/ui/accessibility/ax_node_data.h b/chromium/ui/accessibility/ax_node_data.h
index c7d3320e7aa..232d56208f0 100644
--- a/chromium/ui/accessibility/ax_node_data.h
+++ b/chromium/ui/accessibility/ax_node_data.h
@@ -16,12 +16,9 @@
#include "base/strings/string_split.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_relative_bounds.h"
#include "ui/gfx/geometry/rect_f.h"
-namespace gfx {
-class Transform;
-};
-
namespace ui {
// Return true if |attr| should be interpreted as the id of another node
@@ -100,6 +97,7 @@ struct AX_EXPORT AXNodeData {
void AddStringAttribute(ax::mojom::StringAttribute attribute,
const std::string& value);
void AddIntAttribute(ax::mojom::IntAttribute attribute, int32_t value);
+ void RemoveIntAttribute(ax::mojom::IntAttribute attribute);
void AddFloatAttribute(ax::mojom::FloatAttribute attribute, float value);
void AddBoolAttribute(ax::mojom::BoolAttribute attribute, bool value);
void AddIntListAttribute(ax::mojom::IntListAttribute attribute,
@@ -127,88 +125,36 @@ struct AX_EXPORT AXNodeData {
void SetValue(const base::string16& value);
// Returns true if the given enum bit is 1.
- bool HasState(ax::mojom::State state_enum) const;
- bool HasAction(ax::mojom::Action state_enum) const;
-
- // Set bits in the given enum's corresponding bitfield.
- void AddState(ax::mojom::State state_enum);
- void AddAction(ax::mojom::Action action_enum);
-
- // Remove bits in the given enum's corresponding bitfield.
- void RemoveState(ax::mojom::State state_enum);
-
- // Helper functions to get some common int attributes with some specific
- // enum types:
- ax::mojom::CheckedState GetCheckedState() const {
- return static_cast<ax::mojom::CheckedState>(
- GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
- }
-
- ax::mojom::HasPopup GetHasPopup() const {
- return static_cast<ax::mojom::HasPopup>(
- GetIntAttribute(ax::mojom::IntAttribute::kHasPopup));
- }
-
- ax::mojom::DefaultActionVerb GetDefaultActionVerb() const {
- return static_cast<ax::mojom::DefaultActionVerb>(
- GetIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb));
- }
- ax::mojom::InvalidState GetInvalidState() const {
- return static_cast<ax::mojom::InvalidState>(
- GetIntAttribute(ax::mojom::IntAttribute::kInvalidState));
- }
- ax::mojom::NameFrom GetNameFrom() const {
- return static_cast<ax::mojom::NameFrom>(
- GetIntAttribute(ax::mojom::IntAttribute::kNameFrom));
- }
- ax::mojom::Restriction GetRestriction() const {
- return static_cast<ax::mojom::Restriction>(
- GetIntAttribute(ax::mojom::IntAttribute::kRestriction));
- }
- ax::mojom::TextDirection GetTextDirection() const {
- return static_cast<ax::mojom::TextDirection>(
- GetIntAttribute(ax::mojom::IntAttribute::kTextDirection));
- }
-
- ax::mojom::TextPosition GetTextPosition() const {
- return static_cast<ax::mojom::TextPosition>(
- GetIntAttribute(ax::mojom::IntAttribute::kTextPosition));
- }
-
- // Helper functions to set some common int attributes.
- void SetCheckedState(ax::mojom::CheckedState checked_state) {
- AddIntAttribute(ax::mojom::IntAttribute::kCheckedState,
- static_cast<int32_t>(checked_state));
- }
- void SetHasPopup(ax::mojom::HasPopup has_popup) {
- AddIntAttribute(ax::mojom::IntAttribute::kHasPopup,
- static_cast<int32_t>(has_popup));
- }
- void SetDefaultActionVerb(ax::mojom::DefaultActionVerb default_action_verb) {
- AddIntAttribute(ax::mojom::IntAttribute::kDefaultActionVerb,
- static_cast<int32_t>(default_action_verb));
- }
- void SetInvalidState(ax::mojom::InvalidState invalid_state) {
- AddIntAttribute(ax::mojom::IntAttribute::kInvalidState,
- static_cast<int32_t>(invalid_state));
- }
- void SetNameFrom(ax::mojom::NameFrom name_from) {
- AddIntAttribute(ax::mojom::IntAttribute::kNameFrom,
- static_cast<int32_t>(name_from));
- }
- void SetRestriction(ax::mojom::Restriction restriction) {
- AddIntAttribute(ax::mojom::IntAttribute::kRestriction,
- static_cast<int32_t>(restriction));
- }
- void SetTextDirection(ax::mojom::TextDirection text_direction) {
- AddIntAttribute(ax::mojom::IntAttribute::kTextDirection,
- static_cast<int32_t>(text_direction));
- }
-
- void SetTextPosition(ax::mojom::TextPosition text_position) {
- AddIntAttribute(ax::mojom::IntAttribute::kTextPosition,
- static_cast<int32_t>(text_position));
- }
+ bool HasState(ax::mojom::State state) const;
+ bool HasAction(ax::mojom::Action action) const;
+ bool HasTextStyle(ax::mojom::TextStyle text_style) const;
+
+ // Set or remove bits in the given enum's corresponding bitfield.
+ ax::mojom::State AddState(ax::mojom::State state);
+ ax::mojom::State RemoveState(ax::mojom::State state);
+ ax::mojom::Action AddAction(ax::mojom::Action action);
+ void AddTextStyle(ax::mojom::TextStyle text_style);
+
+ // Helper functions to get or set some common int attributes with some
+ // specific enum types. To remove an attribute, set it to None.
+ //
+ // Please keep in alphabetic order.
+ ax::mojom::CheckedState GetCheckedState() const;
+ void SetCheckedState(ax::mojom::CheckedState checked_state);
+ ax::mojom::DefaultActionVerb GetDefaultActionVerb() const;
+ void SetDefaultActionVerb(ax::mojom::DefaultActionVerb default_action_verb);
+ ax::mojom::HasPopup GetHasPopup() const;
+ void SetHasPopup(ax::mojom::HasPopup has_popup);
+ ax::mojom::InvalidState GetInvalidState() const;
+ void SetInvalidState(ax::mojom::InvalidState invalid_state);
+ ax::mojom::NameFrom GetNameFrom() const;
+ void SetNameFrom(ax::mojom::NameFrom name_from);
+ ax::mojom::TextPosition GetTextPosition() const;
+ void SetTextPosition(ax::mojom::TextPosition text_position);
+ ax::mojom::Restriction GetRestriction() const;
+ void SetRestriction(ax::mojom::Restriction restriction);
+ ax::mojom::TextDirection GetTextDirection() const;
+ void SetTextDirection(ax::mojom::TextDirection text_direction);
// Return a string representation of this data, for debugging.
virtual std::string ToString() const;
@@ -232,22 +178,7 @@ struct AX_EXPORT AXNodeData {
base::StringPairs html_attributes;
std::vector<int32_t> child_ids;
- // TODO(dmazzoni): replace the following three members with a single
- // instance of AXRelativeBounds.
-
- // The id of an ancestor node in the same AXTree that this object's
- // bounding box is relative to, or -1 if there's no offset container.
- int32_t offset_container_id = -1;
-
- // The relative bounding box of this node.
- gfx::RectF location;
-
- // An additional transform to apply to position this object and its subtree.
- // NOTE: this member is a std::unique_ptr because it's rare and gfx::Transform
- // takes up a fair amount of space. The assignment operator and copy
- // constructor both make a duplicate of the owned pointer, so it acts more
- // like a member than a pointer.
- std::unique_ptr<gfx::Transform> transform;
+ AXRelativeBounds relative_bounds;
};
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node_data_unittest.cc b/chromium/ui/accessibility/ax_node_data_unittest.cc
new file mode 100644
index 00000000000..13e51dc4861
--- /dev/null
+++ b/chromium/ui/accessibility/ax_node_data_unittest.cc
@@ -0,0 +1,30 @@
+// 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/accessibility/ax_node_data.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+
+namespace ui {
+
+TEST(AXNodeDataTest, GetAndSetCheckedState) {
+ AXNodeData root;
+ EXPECT_EQ(ax::mojom::CheckedState::kNone, root.GetCheckedState());
+ EXPECT_FALSE(root.HasIntAttribute(ax::mojom::IntAttribute::kCheckedState));
+
+ root.SetCheckedState(ax::mojom::CheckedState::kMixed);
+ EXPECT_EQ(ax::mojom::CheckedState::kMixed, root.GetCheckedState());
+ EXPECT_TRUE(root.HasIntAttribute(ax::mojom::IntAttribute::kCheckedState));
+
+ root.SetCheckedState(ax::mojom::CheckedState::kFalse);
+ EXPECT_EQ(ax::mojom::CheckedState::kFalse, root.GetCheckedState());
+ EXPECT_TRUE(root.HasIntAttribute(ax::mojom::IntAttribute::kCheckedState));
+
+ root.SetCheckedState(ax::mojom::CheckedState::kNone);
+ EXPECT_EQ(ax::mojom::CheckedState::kNone, root.GetCheckedState());
+ EXPECT_FALSE(root.HasIntAttribute(ax::mojom::IntAttribute::kCheckedState));
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/ax_node_position_unittest.cc b/chromium/ui/accessibility/ax_node_position_unittest.cc
index 55c0753aaa6..5aeeff01fa3 100644
--- a/chromium/ui/accessibility/ax_node_position_unittest.cc
+++ b/chromium/ui/accessibility/ax_node_position_unittest.cc
@@ -118,12 +118,12 @@ void AXPositionTest::SetUp() {
root_.role = ax::mojom::Role::kDialog;
root_.AddState(ax::mojom::State::kFocusable);
root_.SetName(std::string("ButtonCheck box") + TEXT_VALUE);
- root_.location = gfx::RectF(0, 0, 800, 600);
+ root_.relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
button_.role = ax::mojom::Role::kButton;
button_.SetHasPopup(ax::mojom::HasPopup::kMenu);
button_.SetName("Button");
- button_.location = gfx::RectF(20, 20, 200, 30);
+ button_.relative_bounds.bounds = gfx::RectF(20, 20, 200, 30);
button_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
std::vector<int32_t>{0});
button_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
@@ -135,7 +135,7 @@ void AXPositionTest::SetUp() {
check_box_.role = ax::mojom::Role::kCheckBox;
check_box_.SetCheckedState(ax::mojom::CheckedState::kTrue);
check_box_.SetName("Check box");
- check_box_.location = gfx::RectF(20, 50, 200, 30);
+ check_box_.relative_bounds.bounds = gfx::RectF(20, 50, 200, 30);
check_box_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
std::vector<int32_t>{0, 6});
check_box_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
diff --git a/chromium/ui/accessibility/ax_relative_bounds.cc b/chromium/ui/accessibility/ax_relative_bounds.cc
index 87c3d5811ca..7e4170a3796 100644
--- a/chromium/ui/accessibility/ax_relative_bounds.cc
+++ b/chromium/ui/accessibility/ax_relative_bounds.cc
@@ -5,6 +5,7 @@
#include "ui/accessibility/ax_relative_bounds.h"
#include "base/strings/string_number_conversions.h"
+#include "ui/accessibility/ax_enum_util.h"
#include "ui/gfx/transform.h"
using base::IntToString;
@@ -30,6 +31,8 @@ AXRelativeBounds& AXRelativeBounds::operator=(AXRelativeBounds other) {
bounds = other.bounds;
if (other.transform)
transform.reset(new gfx::Transform(*other.transform));
+ else
+ transform.reset(nullptr);
return *this;
}
diff --git a/chromium/ui/accessibility/ax_relative_bounds.h b/chromium/ui/accessibility/ax_relative_bounds.h
index 18e92b2d2a1..5126f74006a 100644
--- a/chromium/ui/accessibility/ax_relative_bounds.h
+++ b/chromium/ui/accessibility/ax_relative_bounds.h
@@ -10,12 +10,10 @@
#include <memory>
#include <ostream>
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_export.h"
#include "ui/gfx/geometry/rect_f.h"
-
-namespace gfx {
-class Transform;
-};
+#include "ui/gfx/transform.h"
namespace ui {
diff --git a/chromium/ui/accessibility/ax_role_properties.cc b/chromium/ui/accessibility/ax_role_properties.cc
index 487ba26d71a..0c851bb60d4 100644
--- a/chromium/ui/accessibility/ax_role_properties.cc
+++ b/chromium/ui/accessibility/ax_role_properties.cc
@@ -3,19 +3,22 @@
// found in the LICENSE file.
#include "ui/accessibility/ax_role_properties.h"
+
#include "build/build_config.h"
namespace ui {
namespace {
+
#if defined(OS_WIN) || defined(OS_CHROMEOS)
-static bool kExposeLayoutTableAsDataTable = true;
+constexpr bool kExposeLayoutTableAsDataTable = true;
#else
-static bool kExposeLayoutTableAsDataTable = false;
-#endif
+constexpr bool kExposeLayoutTableAsDataTable = false;
+#endif // defined(OS_WIN)
+
} // namespace
-bool IsRoleClickable(ax::mojom::Role role) {
+bool IsClickable(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kButton:
case ax::mojom::Role::kCheckBox:
@@ -44,47 +47,73 @@ bool IsRoleClickable(ax::mojom::Role role) {
}
}
-bool IsLink(ax::mojom::Role role) {
+bool IsCellOrTableHeader(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kDocBackLink:
- case ax::mojom::Role::kDocBiblioRef:
- case ax::mojom::Role::kDocGlossRef:
- case ax::mojom::Role::kDocNoteRef:
- case ax::mojom::Role::kLink:
+ case ax::mojom::Role::kCell:
+ case ax::mojom::Role::kColumnHeader:
+ case ax::mojom::Role::kRowHeader:
return true;
+ case ax::mojom::Role::kLayoutTableCell:
+ return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsList(ax::mojom::Role role) {
+bool IsContainerWithSelectableChildren(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kDirectory:
- case ax::mojom::Role::kDocBibliography:
- case ax::mojom::Role::kList:
+ case ax::mojom::Role::kComboBoxGrouping:
+ case ax::mojom::Role::kComboBoxMenuButton:
+ case ax::mojom::Role::kGrid:
case ax::mojom::Role::kListBox:
- case ax::mojom::Role::kDescriptionList:
+ case ax::mojom::Role::kMenu:
+ case ax::mojom::Role::kMenuBar:
+ case ax::mojom::Role::kRadioGroup:
+ case ax::mojom::Role::kTabList:
+ case ax::mojom::Role::kToolbar:
+ case ax::mojom::Role::kTree:
+ case ax::mojom::Role::kTreeGrid:
return true;
default:
return false;
}
}
-bool IsListItem(ax::mojom::Role role) {
+bool IsControl(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kDescriptionListTerm:
- case ax::mojom::Role::kDocBiblioEntry:
- case ax::mojom::Role::kDocEndnote:
- case ax::mojom::Role::kListBoxOption:
- case ax::mojom::Role::kListItem:
- case ax::mojom::Role::kTerm:
+ case ax::mojom::Role::kButton:
+ case ax::mojom::Role::kCheckBox:
+ case ax::mojom::Role::kColorWell:
+ case ax::mojom::Role::kComboBoxMenuButton:
+ case ax::mojom::Role::kDisclosureTriangle:
+ case ax::mojom::Role::kListBox:
+ case ax::mojom::Role::kMenu:
+ case ax::mojom::Role::kMenuBar:
+ case ax::mojom::Role::kMenuButton:
+ case ax::mojom::Role::kMenuItem:
+ case ax::mojom::Role::kMenuItemCheckBox:
+ case ax::mojom::Role::kMenuItemRadio:
+ case ax::mojom::Role::kMenuListOption:
+ case ax::mojom::Role::kMenuListPopup:
+ case ax::mojom::Role::kPopUpButton:
+ case ax::mojom::Role::kRadioButton:
+ case ax::mojom::Role::kScrollBar:
+ case ax::mojom::Role::kSearchBox:
+ case ax::mojom::Role::kSlider:
+ case ax::mojom::Role::kSpinButton:
+ case ax::mojom::Role::kSwitch:
+ case ax::mojom::Role::kTab:
+ case ax::mojom::Role::kTextField:
+ case ax::mojom::Role::kTextFieldWithComboBox:
+ case ax::mojom::Role::kToggleButton:
+ case ax::mojom::Role::kTree:
return true;
default:
return false;
}
}
-bool IsDocument(ax::mojom::Role role) {
+bool IsDocument(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kRootWebArea:
case ax::mojom::Role::kWebArea:
@@ -94,105 +123,96 @@ bool IsDocument(ax::mojom::Role role) {
}
}
-bool IsCellOrTableHeaderRole(ax::mojom::Role role) {
+bool IsHeading(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kCell:
- case ax::mojom::Role::kColumnHeader:
- case ax::mojom::Role::kRowHeader:
+ case ax::mojom::Role::kHeading:
+ case ax::mojom::Role::kDocSubtitle:
return true;
- case ax::mojom::Role::kLayoutTableCell:
- return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsTableLikeRole(ax::mojom::Role role) {
+bool IsHeadingOrTableHeader(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kTable:
- case ax::mojom::Role::kGrid:
- case ax::mojom::Role::kTreeGrid:
+ case ax::mojom::Role::kColumnHeader:
+ case ax::mojom::Role::kDocSubtitle:
+ case ax::mojom::Role::kHeading:
+ case ax::mojom::Role::kRowHeader:
return true;
- case ax::mojom::Role::kLayoutTable:
- return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsTableHeaderRole(ax::mojom::Role role) {
+bool IsImage(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kColumnHeader:
- case ax::mojom::Role::kRowHeader:
+ case ax::mojom::Role::kCanvas:
+ case ax::mojom::Role::kDocCover:
+ case ax::mojom::Role::kGraphicsSymbol:
+ case ax::mojom::Role::kImage:
+ case ax::mojom::Role::kImageMap:
+ case ax::mojom::Role::kSvgRoot:
+ case ax::mojom::Role::kVideo:
return true;
default:
return false;
}
}
-bool IsTableRowRole(ax::mojom::Role role) {
+bool IsLink(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kRow:
+ case ax::mojom::Role::kDocBackLink:
+ case ax::mojom::Role::kDocBiblioRef:
+ case ax::mojom::Role::kDocGlossRef:
+ case ax::mojom::Role::kDocNoteRef:
+ case ax::mojom::Role::kLink:
return true;
- case ax::mojom::Role::kLayoutTableRow:
- return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsContainerWithSelectableChildrenRole(ax::mojom::Role role) {
+bool IsList(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kComboBoxGrouping:
- case ax::mojom::Role::kComboBoxMenuButton:
- case ax::mojom::Role::kGrid:
+ case ax::mojom::Role::kDescriptionList:
+ case ax::mojom::Role::kDirectory:
+ case ax::mojom::Role::kDocBibliography:
+ case ax::mojom::Role::kList:
case ax::mojom::Role::kListBox:
- case ax::mojom::Role::kMenu:
- case ax::mojom::Role::kMenuBar:
- case ax::mojom::Role::kRadioGroup:
- case ax::mojom::Role::kTabList:
- case ax::mojom::Role::kToolbar:
- case ax::mojom::Role::kTree:
- case ax::mojom::Role::kTreeGrid:
return true;
default:
return false;
}
}
-bool IsUIASelectable(ax::mojom::Role role) {
+bool IsListItem(const ax::mojom::Role role) {
switch (role) {
+ case ax::mojom::Role::kDescriptionListTerm:
+ case ax::mojom::Role::kDocBiblioEntry:
+ case ax::mojom::Role::kDocEndnote:
case ax::mojom::Role::kListBoxOption:
- case ax::mojom::Role::kMenuListOption:
- case ax::mojom::Role::kRadioButton:
- case ax::mojom::Role::kTab:
- case ax::mojom::Role::kTreeItem:
+ case ax::mojom::Role::kListItem:
+ case ax::mojom::Role::kTerm:
return true;
default:
return false;
}
}
-bool IsRowContainer(ax::mojom::Role role) {
+bool IsMenuItem(ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kTree:
- case ax::mojom::Role::kTreeGrid:
- case ax::mojom::Role::kGrid:
- case ax::mojom::Role::kTable:
+ case ax::mojom::Role::kMenuItem:
+ case ax::mojom::Role::kMenuItemCheckBox:
+ case ax::mojom::Role::kMenuItemRadio:
return true;
default:
return false;
}
}
-bool IsControl(ax::mojom::Role role) {
+bool IsMenuRelated(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kButton:
- case ax::mojom::Role::kCheckBox:
- case ax::mojom::Role::kColorWell:
- case ax::mojom::Role::kComboBoxMenuButton:
- case ax::mojom::Role::kDisclosureTriangle:
- case ax::mojom::Role::kListBox:
case ax::mojom::Role::kMenu:
case ax::mojom::Role::kMenuBar:
case ax::mojom::Role::kMenuButton:
@@ -201,89 +221,73 @@ bool IsControl(ax::mojom::Role role) {
case ax::mojom::Role::kMenuItemRadio:
case ax::mojom::Role::kMenuListOption:
case ax::mojom::Role::kMenuListPopup:
- case ax::mojom::Role::kPopUpButton:
- case ax::mojom::Role::kRadioButton:
- case ax::mojom::Role::kScrollBar:
- case ax::mojom::Role::kSearchBox:
- case ax::mojom::Role::kSlider:
- case ax::mojom::Role::kSpinButton:
- case ax::mojom::Role::kSwitch:
- case ax::mojom::Role::kTab:
- case ax::mojom::Role::kTextField:
- case ax::mojom::Role::kTextFieldWithComboBox:
- case ax::mojom::Role::kToggleButton:
- case ax::mojom::Role::kTree:
return true;
default:
return false;
}
}
-bool IsMenuRelated(ax::mojom::Role role) {
+bool IsRowContainer(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kMenu:
- case ax::mojom::Role::kMenuBar:
- case ax::mojom::Role::kMenuButton:
- case ax::mojom::Role::kMenuItem:
- case ax::mojom::Role::kMenuItemCheckBox:
- case ax::mojom::Role::kMenuItemRadio:
- case ax::mojom::Role::kMenuListOption:
- case ax::mojom::Role::kMenuListPopup:
+ case ax::mojom::Role::kGrid:
+ case ax::mojom::Role::kTable:
+ case ax::mojom::Role::kTree:
+ case ax::mojom::Role::kTreeGrid:
return true;
+ case ax::mojom::Role::kLayoutTable:
+ return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsMenuItem(ax::mojom::Role role) {
+bool IsTableHeader(ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kMenuItem:
- case ax::mojom::Role::kMenuItemCheckBox:
- case ax::mojom::Role::kMenuItemRadio:
+ case ax::mojom::Role::kColumnHeader:
+ case ax::mojom::Role::kRowHeader:
return true;
default:
return false;
}
}
-bool IsImage(ax::mojom::Role role) {
+bool IsTableLike(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kCanvas:
- case ax::mojom::Role::kDocCover:
- case ax::mojom::Role::kGraphicsSymbol:
- case ax::mojom::Role::kImageMap:
- case ax::mojom::Role::kImage:
- case ax::mojom::Role::kSvgRoot:
- case ax::mojom::Role::kVideo:
+ case ax::mojom::Role::kGrid:
+ case ax::mojom::Role::kTable:
+ case ax::mojom::Role::kTreeGrid:
return true;
+ case ax::mojom::Role::kLayoutTable:
+ return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsHeading(ax::mojom::Role role) {
+bool IsTableRow(ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kHeading:
- case ax::mojom::Role::kDocSubtitle:
+ case ax::mojom::Role::kRow:
return true;
+ case ax::mojom::Role::kLayoutTableRow:
+ return kExposeLayoutTableAsDataTable;
default:
return false;
}
}
-bool IsHeadingOrTableHeader(ax::mojom::Role role) {
+bool SupportsExpandCollapse(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kColumnHeader:
- case ax::mojom::Role::kHeading:
- case ax::mojom::Role::kRowHeader:
- case ax::mojom::Role::kDocSubtitle:
+ case ax::mojom::Role::kComboBoxGrouping:
+ case ax::mojom::Role::kComboBoxMenuButton:
+ case ax::mojom::Role::kDisclosureTriangle:
+ case ax::mojom::Role::kTextFieldWithComboBox:
return true;
default:
return false;
}
}
-bool SupportsOrientation(ax::mojom::Role role) {
+bool SupportsOrientation(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kComboBoxGrouping:
case ax::mojom::Role::kComboBoxMenuButton:
@@ -304,7 +308,7 @@ bool SupportsOrientation(ax::mojom::Role role) {
}
}
-bool SupportsToggle(ax::mojom::Role role) {
+bool SupportsToggle(const ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kCheckBox:
case ax::mojom::Role::kMenuItemCheckBox:
@@ -316,15 +320,27 @@ bool SupportsToggle(ax::mojom::Role role) {
}
}
-bool SupportsExpandCollapse(ax::mojom::Role role) {
+bool IsUIASelectable(const ax::mojom::Role role) {
switch (role) {
- case ax::mojom::Role::kComboBoxGrouping:
- case ax::mojom::Role::kComboBoxMenuButton:
- case ax::mojom::Role::kDisclosureTriangle:
- case ax::mojom::Role::kTextFieldWithComboBox:
+ case ax::mojom::Role::kListBoxOption:
+ case ax::mojom::Role::kMenuListOption:
+ case ax::mojom::Role::kRadioButton:
+ case ax::mojom::Role::kTab:
+ case ax::mojom::Role::kTreeItem:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IsStaticList(const ax::mojom::Role role) {
+ switch (role) {
+ case ax::mojom::Role::kList:
+ case ax::mojom::Role::kDescriptionList:
return true;
default:
return false;
}
}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_role_properties.h b/chromium/ui/accessibility/ax_role_properties.h
index bfb756f9800..c6a80263e06 100644
--- a/chromium/ui/accessibility/ax_role_properties.h
+++ b/chromium/ui/accessibility/ax_role_properties.h
@@ -10,71 +10,81 @@
namespace ui {
+// This file contains various helper functions that determine whether a specific
+// accessibility role meets certain criteria.
+//
+// Please keep these functions in alphabetic order.
+
// Checks if the given role should belong to a control that can respond to
// clicks.
-AX_EXPORT bool IsRoleClickable(ax::mojom::Role role);
+AX_EXPORT bool IsClickable(const ax::mojom::Role role);
-// Returns true if this node is a link.
-AX_EXPORT bool IsLink(ax::mojom::Role role);
+// Returns true if the provided role belongs to a cell or a table header.
+AX_EXPORT bool IsCellOrTableHeader(const ax::mojom::Role role);
-// Returns true if this node is a list.
-AX_EXPORT bool IsList(ax::mojom::Role role);
+// Returns true if the provided role belongs to a container with selectable
+// children.
+AX_EXPORT bool IsContainerWithSelectableChildren(const ax::mojom::Role role);
-// Returns true if this node is a list item.
-AX_EXPORT bool IsListItem(ax::mojom::Role role);
+// Returns true if the provided role is a control.
+AX_EXPORT bool IsControl(const ax::mojom::Role role);
-// Returns true if this node is a document.
-AX_EXPORT bool IsDocument(ax::mojom::Role role);
+// Returns true if the provided role belongs to a document.
+AX_EXPORT bool IsDocument(const ax::mojom::Role role);
-// Returns true if this node is a cell or a table header.
-AX_EXPORT bool IsCellOrTableHeaderRole(ax::mojom::Role role);
+// Returns true if the provided role belongs to a heading.
+AX_EXPORT bool IsHeading(const ax::mojom::Role role);
-// Returns true if this node is a table, a grid or a treegrid.
-AX_EXPORT bool IsTableLikeRole(ax::mojom::Role role);
+// Returns true if the provided role belongs to a heading or a table header.
+AX_EXPORT bool IsHeadingOrTableHeader(const ax::mojom::Role role);
-// Returns true if this node is a table header.
-AX_EXPORT bool IsTableHeaderRole(ax::mojom::Role role);
+// Returns true if the provided role belongs to an image, graphic, canvas, etc.
+AX_EXPORT bool IsImage(const ax::mojom::Role role);
-// Returns true if this node is a row.
-AX_EXPORT bool IsTableRowRole(ax::mojom::Role role);
+// Returns true if the provided role belongs to a link.
+AX_EXPORT bool IsLink(const ax::mojom::Role role);
-// Returns true if the provided role is selectable from the standpoint of UI
-// automation.
-AX_EXPORT bool IsUIASelectable(ax::mojom::Role role);
+// Returns true if the provided role belongs to a list.
+AX_EXPORT bool IsList(const ax::mojom::Role role);
-// Returns true if this node is a container with selectable children.
-AX_EXPORT bool IsContainerWithSelectableChildrenRole(ax::mojom::Role role);
+// Returns true if the provided role belongs to a list item.
+AX_EXPORT bool IsListItem(const ax::mojom::Role role);
-// Returns true if this node is a row container.
-AX_EXPORT bool IsRowContainer(ax::mojom::Role role);
+// Returns true if the provided role belongs to a menu item, including menu item
+// checkbox and menu item radio buttons.
+AX_EXPORT bool IsMenuItem(ax::mojom::Role role);
-// Returns true if this node is a control.
-AX_EXPORT bool IsControl(ax::mojom::Role role);
+// Returns true if the provided role belongs to a menu or related control.
+AX_EXPORT bool IsMenuRelated(const ax::mojom::Role role);
-// Returns true if this node is a menu or related role.
-AX_EXPORT bool IsMenuRelated(ax::mojom::Role role);
+// Returns true if the provided role belongs to a widget that can contain a
+// table or grid row.
+AX_EXPORT bool IsRowContainer(const ax::mojom::Role role);
-// Returns true if the role is a menu item, including menu item
-// check box and menu item radio buttons.
-AX_EXPORT bool IsMenuItem(ax::mojom::Role role);
+// Returns true if the provided role belongs to a table header.
+AX_EXPORT bool IsTableHeader(ax::mojom::Role role);
-// Returns true if it's an image, graphic, canvas, etc.
-AX_EXPORT bool IsImage(ax::mojom::Role role);
+// Returns true if the provided role belongs to a table, a grid or a treegrid.
+AX_EXPORT bool IsTableLike(const ax::mojom::Role role);
-// Returns true if it's a heading.
-AX_EXPORT bool IsHeading(ax::mojom::Role role);
+// Returns true if the provided role belongs to a table or grid row.
+AX_EXPORT bool IsTableRow(ax::mojom::Role role);
-// Returns true if it's a heading.
-AX_EXPORT bool IsHeadingOrTableHeader(ax::mojom::Role role);
+// Returns true if the provided role supports expand/collapse.
+AX_EXPORT bool SupportsExpandCollapse(const ax::mojom::Role role);
// Returns true if the provided role can have an orientation.
-AX_EXPORT bool SupportsOrientation(ax::mojom::Role role);
+AX_EXPORT bool SupportsOrientation(const ax::mojom::Role role);
// Returns true if the provided role supports toggle.
-AX_EXPORT bool SupportsToggle(ax::mojom::Role role);
+AX_EXPORT bool SupportsToggle(const ax::mojom::Role role);
+
+// Returns true if the provided role is selectable from the standpoint of UI
+// Automation.
+AX_EXPORT bool IsUIASelectable(const ax::mojom::Role role);
+
+AX_EXPORT bool IsStaticList(const ax::mojom::Role role);
-// Returns true if the provided role supports expand/collapse.
-AX_EXPORT bool SupportsExpandCollapse(ax::mojom::Role role);
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_ROLE_PROPERTIES_H_
diff --git a/chromium/ui/accessibility/ax_table_fuzzer.cc b/chromium/ui/accessibility/ax_table_fuzzer.cc
new file mode 100644
index 00000000000..107d0ca8c07
--- /dev/null
+++ b/chromium/ui/accessibility/ax_table_fuzzer.cc
@@ -0,0 +1,183 @@
+// 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 "base/macros.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_tree.h"
+
+// The purpose of this script is to fuzz code that parses
+// table-like structures. As a result, we want to generate
+// accessibility trees that contain lots of table-related
+// roles.
+//
+// We also bias towards cells and rows so that we end up
+// with more of those overall.
+ax::mojom::Role GetInterestingTableRole(unsigned char byte) {
+ switch (byte % 16) {
+ default:
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ return ax::mojom::Role::kCell;
+ case 4:
+ case 5:
+ return ax::mojom::Role::kRow;
+ case 6:
+ return ax::mojom::Role::kTable;
+ case 7:
+ return ax::mojom::Role::kGrid;
+ case 8:
+ return ax::mojom::Role::kColumnHeader;
+ case 9:
+ return ax::mojom::Role::kRowHeader;
+ case 10:
+ return ax::mojom::Role::kGenericContainer;
+ case 11:
+ return ax::mojom::Role::kIgnored;
+ case 12:
+ return ax::mojom::Role::kLayoutTable;
+ case 13:
+ return ax::mojom::Role::kLayoutTableCell;
+ case 14:
+ return ax::mojom::Role::kLayoutTableRow;
+ case 15:
+ return ax::mojom::Role::kMain;
+ }
+}
+
+// We want some of the nodes in the accessibility tree to have
+// table-related attributes.
+ax::mojom::IntAttribute GetInterestingTableAttribute(unsigned char byte) {
+ switch (byte % 10) {
+ case 0:
+ default:
+ return ax::mojom::IntAttribute::kTableCellRowIndex;
+ case 1:
+ return ax::mojom::IntAttribute::kTableCellColumnIndex;
+ case 2:
+ return ax::mojom::IntAttribute::kTableRowCount;
+ case 3:
+ return ax::mojom::IntAttribute::kTableColumnCount;
+ case 4:
+ return ax::mojom::IntAttribute::kAriaRowCount;
+ case 5:
+ return ax::mojom::IntAttribute::kAriaColumnCount;
+ case 6:
+ return ax::mojom::IntAttribute::kTableCellRowSpan;
+ case 7:
+ return ax::mojom::IntAttribute::kTableCellColumnSpan;
+ case 8:
+ return ax::mojom::IntAttribute::kAriaCellRowIndex;
+ case 9:
+ return ax::mojom::IntAttribute::kAriaCellColumnIndex;
+ }
+}
+
+// Call all of the table-related APIs on an accessibility node.
+// These will be no-ops if the node is not part of a complete
+// table. We don't care about any of the results, we just want
+// to make sure none of these crash or hang.
+void TestTableAPIs(ui::AXNode* node) {
+ ignore_result(node->IsTable());
+ ignore_result(node->GetTableColCount());
+ ignore_result(node->GetTableRowCount());
+ ignore_result(node->GetTableAriaColCount());
+ ignore_result(node->GetTableAriaRowCount());
+ ignore_result(node->GetTableCellCount());
+ for (int i = 0; i < 8; i++)
+ ignore_result(node->GetTableCellFromIndex(i));
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ ignore_result(node->GetTableCellFromCoords(i, j));
+ // Note: some of the APIs return IDs - we don't care what's
+ // returned, we just want to make sure these APIs don't
+ // crash. Normally |ids| is an out argument only, but
+ // there's no reason we shouldn't be able to pass a vector
+ // that was previously used by another call.
+ std::vector<int32_t> ids;
+ for (int i = 0; i < 3; i++) {
+ node->GetTableColHeaderNodeIds(i, &ids);
+ node->GetTableRowHeaderNodeIds(i, &ids);
+ }
+ node->GetTableUniqueCellIds(&ids);
+ ignore_result(node->IsTableRow());
+ ignore_result(node->GetTableRowRowIndex());
+
+ ignore_result(node->IsTableCellOrHeader());
+ ignore_result(node->GetTableCellIndex());
+ ignore_result(node->GetTableCellColIndex());
+ ignore_result(node->GetTableCellRowIndex());
+ ignore_result(node->GetTableCellColSpan());
+ ignore_result(node->GetTableCellRowSpan());
+ ignore_result(node->GetTableCellAriaColIndex());
+ ignore_result(node->GetTableCellAriaRowIndex());
+ node->GetTableCellColHeaderNodeIds(&ids);
+ node->GetTableCellRowHeaderNodeIds(&ids);
+ std::vector<ui::AXNode*> headers;
+ node->GetTableCellColHeaders(&headers);
+ node->GetTableCellRowHeaders(&headers);
+
+ for (int i = 0; i < node->child_count(); i++)
+ TestTableAPIs(node->children()[i]);
+}
+
+// Entry point for LibFuzzer.
+extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
+ ui::AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ size_t i = 0;
+
+ // The root of the accessibility tree.
+ ui::AXNodeData root;
+ root.id = 1;
+ if (i < size)
+ root.role = GetInterestingTableRole(data[i++]);
+ root.child_ids.push_back(2);
+ initial_state.nodes.push_back(root);
+
+ // Force the next node of the accessibility tree to be a table,
+ // and give it no attributes but a few children.
+ ui::AXNodeData table;
+ table.id = 2;
+ table.role = ax::mojom::Role::kTable;
+ if (i < size) {
+ size_t child_count = data[i++] % 8;
+ for (size_t j = 0; j < child_count && i < size; j++)
+ table.child_ids.push_back(3 + data[i++] % 32);
+ }
+ initial_state.nodes.push_back(table);
+
+ // Create more accessibility nodes that might result in a table.
+ int next_id = 3;
+ while (i < size) {
+ ui::AXNodeData node;
+ node.id = next_id++;
+ if (i < size)
+ node.role = GetInterestingTableRole(data[i++]);
+ if (i < size) {
+ int attr_count = data[i++] % 6;
+ for (int j = 0; j < attr_count && i + 1 < size; j++) {
+ unsigned char attr = data[i++];
+ int32_t value = static_cast<int32_t>(data[i++]) - 2;
+ node.AddIntAttribute(GetInterestingTableAttribute(attr), value);
+ }
+ }
+ if (i < size) {
+ size_t child_count = data[i++] % 8;
+ for (size_t j = 0; j < child_count && i < size; j++)
+ node.child_ids.push_back(4 + data[i++] % 32);
+ }
+ initial_state.nodes.push_back(node);
+ }
+
+ // Run with --v=1 to aid in debugging a specific crash.
+ VLOG(1) << "Input accessibility tree:\n" << initial_state.ToString();
+
+ ui::AXTree tree;
+ if (tree.Unserialize(initial_state))
+ TestTableAPIs(tree.root());
+
+ return 0;
+}
diff --git a/chromium/ui/accessibility/ax_table_info.cc b/chromium/ui/accessibility/ax_table_info.cc
index 72cfaa240c2..b3f79cc65ee 100644
--- a/chromium/ui/accessibility/ax_table_info.cc
+++ b/chromium/ui/accessibility/ax_table_info.cc
@@ -9,27 +9,50 @@
#include "ui/accessibility/ax_tree.h"
#include "ui/gfx/geometry/rect_f.h"
+using ax::mojom::IntAttribute;
+
namespace ui {
namespace {
-void FindCells(AXNode* node, std::vector<AXNode*>* cells) {
+// Given a node representing a table row, search its children
+// recursively to find any cells or table headers, and append
+// them to |cells|.
+//
+// We recursively check generic containers like <div> and any
+// nodes that are ignored, but we don't search any other roles
+// in-between a table row and its cells.
+void FindCellsInRow(AXNode* node, std::vector<AXNode*>* cell_nodes) {
for (AXNode* child : node->children()) {
if (child->data().HasState(ax::mojom::State::kIgnored) ||
child->data().role == ax::mojom::Role::kGenericContainer)
- FindCells(child, cells);
- else if (IsCellOrTableHeaderRole(child->data().role))
- cells->push_back(child);
+ FindCellsInRow(child, cell_nodes);
+ else if (IsCellOrTableHeader(child->data().role))
+ cell_nodes->push_back(child);
}
}
-void FindRowsAndThenCells(AXNode* node, std::vector<AXNode*>* cells) {
+// Given a node representing a table/grid, search its children
+// recursively to find any rows and append them to |row_nodes|, then
+// for each row find its cells and add them to |cell_nodes_per_row| as a
+// 2-dimensional array.
+//
+// We recursively check generic containers like <div> and any
+// nodes that are ignored, but we don't search any other roles
+// in-between a table and its rows.
+void FindRowsAndThenCells(
+ AXNode* node,
+ std::vector<AXNode*>* row_nodes,
+ std::vector<std::vector<AXNode*>>* cell_nodes_per_row) {
for (AXNode* child : node->children()) {
if (child->data().HasState(ax::mojom::State::kIgnored) ||
- child->data().role == ax::mojom::Role::kGenericContainer)
- FindRowsAndThenCells(child, cells);
- else if (child->data().role == ax::mojom::Role::kRow)
- FindCells(child, cells);
+ child->data().role == ax::mojom::Role::kGenericContainer) {
+ FindRowsAndThenCells(child, row_nodes, cell_nodes_per_row);
+ } else if (child->data().role == ax::mojom::Role::kRow) {
+ row_nodes->push_back(child);
+ cell_nodes_per_row->push_back(std::vector<AXNode*>());
+ FindCellsInRow(child, &cell_nodes_per_row->back());
+ }
}
}
@@ -48,7 +71,7 @@ AXTableInfo* AXTableInfo::Create(AXTree* tree, AXNode* table_node) {
DCHECK(node == tree->root());
#endif
- if (!IsTableLikeRole(table_node->data().role))
+ if (!IsTableLike(table_node->data().role))
return nullptr;
AXTableInfo* info = new AXTableInfo(tree, table_node);
@@ -59,38 +82,176 @@ AXTableInfo* AXTableInfo::Create(AXTree* tree, AXNode* table_node) {
}
bool AXTableInfo::Update() {
- if (!IsTableLikeRole(table_node_->data().role))
+ const AXNodeData& node_data = table_node_->data();
+ if (!IsTableLike(node_data.role))
return false;
+ ClearVectors();
+
+ std::vector<AXNode*> row_nodes;
+ std::vector<std::vector<AXNode*>> cell_nodes_per_row;
+ FindRowsAndThenCells(table_node_, &row_nodes, &cell_nodes_per_row);
+ DCHECK_EQ(cell_nodes_per_row.size(), row_nodes.size());
+
+ // Get the optional row and column count from the table. If we encounter
+ // a cell with an index or span larger than this, we'll update the
+ // table row and column count to be large enough to fit all cells.
+ row_count =
+ std::max(0, node_data.GetIntAttribute(IntAttribute::kTableRowCount));
+ col_count =
+ std::max(0, node_data.GetIntAttribute(IntAttribute::kTableColumnCount));
+ aria_row_count =
+ std::max(0, node_data.GetIntAttribute(IntAttribute::kAriaRowCount));
+ aria_col_count =
+ std::max(0, node_data.GetIntAttribute(IntAttribute::kAriaColumnCount));
+
+ // Iterate over the cells and build up an array of CellData
+ // entries, one for each cell. Compute the actual row and column
+ BuildCellDataVectorFromRowAndCellNodes(row_nodes, cell_nodes_per_row);
+
+ // At this point we have computed valid row and column indices for
+ // every cell in the table, and an accurate row and column count for the
+ // whole table that fits every cell and its spans. The final step is to
+ // fill in a 2-dimensional array that lets us look up an individual cell
+ // by its (row, column) coordinates, plus arrays to hold row and column
+ // headers.
+ BuildCellAndHeaderVectorsFromCellData();
+
+ // On Mac, we add a few extra nodes to the table - see comment
+ // at the top of UpdateExtraMacNodes for details.
+ if (tree_->enable_extra_mac_nodes())
+ UpdateExtraMacNodes();
+
+ // The table metadata is now valid, any table queries will now be
+ // fast. Any time a node in the table is updated, we'll have to
+ // recompute all of this.
+ valid_ = true;
+ return true;
+}
+
+void AXTableInfo::Invalidate() {
+ valid_ = false;
+}
+
+void AXTableInfo::ClearVectors() {
col_headers.clear();
row_headers.clear();
all_headers.clear();
cell_ids.clear();
unique_cell_ids.clear();
+ cell_data_vector.clear();
+}
+
+void AXTableInfo::BuildCellDataVectorFromRowAndCellNodes(
+ const std::vector<AXNode*>& row_nodes,
+ const std::vector<std::vector<AXNode*>>& cell_nodes_per_row) {
+ // Iterate over the cells and build up an array of CellData
+ // entries, one for each cell. Compute the actual row and column
+ // indices for each cell by taking the specified row and column
+ // index in the accessibility tree if legal, but replacing it with
+ // valid table coordinates otherwise.
+ int32_t cell_index = 0;
+ int32_t current_row_index = 0;
+ int32_t current_aria_row_index = 1;
+ for (size_t i = 0; i < cell_nodes_per_row.size(); i++) {
+ auto& cell_nodes_in_this_row = cell_nodes_per_row[i];
+ AXNode* row_node = row_nodes[i];
+ bool is_first_cell_in_row = true;
+ int32_t current_col_index = 0;
+ int32_t current_aria_col_index = 1;
+ for (AXNode* cell : cell_nodes_in_this_row) {
+ // Fill in basic info in CellData.
+ CellData cell_data;
+ unique_cell_ids.push_back(cell->id());
+ cell_id_to_index[cell->id()] = cell_index++;
+ cell_data.cell = cell;
+
+ // Get table cell accessibility attributes - note that these may
+ // be missing or invalid, we'll correct them next.
+ const AXNodeData& node_data = cell->data();
+ cell_data.row_index =
+ node_data.GetIntAttribute(IntAttribute::kTableCellRowIndex);
+ cell_data.row_span =
+ node_data.GetIntAttribute(IntAttribute::kTableCellRowSpan);
+ cell_data.aria_row_index =
+ node_data.GetIntAttribute(IntAttribute::kAriaCellRowIndex);
+ cell_data.col_index =
+ node_data.GetIntAttribute(IntAttribute::kTableCellColumnIndex);
+ cell_data.aria_col_index =
+ node_data.GetIntAttribute(IntAttribute::kAriaCellColumnIndex);
+ cell_data.col_span =
+ node_data.GetIntAttribute(IntAttribute::kTableCellColumnSpan);
+
+ // The col span and row span must be at least 1.
+ cell_data.row_span = std::max(1, cell_data.row_span);
+ cell_data.col_span = std::max(1, cell_data.col_span);
+
+ // Ensure the column index must always be incrementing.
+ cell_data.col_index = std::max(cell_data.col_index, current_col_index);
+
+ if (is_first_cell_in_row) {
+ is_first_cell_in_row = false;
+
+ // If it's the first cell in the row, ensure the row index is
+ // incrementing. The rest of the cells in this row will be force to
+ // have the same row index.
+ cell_data.row_index = std::max(cell_data.row_index, current_row_index);
+ current_row_index = cell_data.row_index;
+
+ // The starting ARIA row and column index might be specified in
+ // the row node, we should check there.
+ if (!cell_data.aria_row_index) {
+ cell_data.aria_row_index =
+ row_node->data().GetIntAttribute(IntAttribute::kAriaCellRowIndex);
+ }
+ if (!cell_data.aria_col_index) {
+ cell_data.aria_col_index = row_node->data().GetIntAttribute(
+ IntAttribute::kAriaCellColumnIndex);
+ }
+ cell_data.aria_row_index =
+ std::max(cell_data.aria_row_index, current_aria_row_index);
+ current_aria_row_index = cell_data.aria_row_index;
+ } else {
+ // Don't allow the row index to change after the beginning
+ // of a row.
+ cell_data.row_index = current_row_index;
+ cell_data.aria_row_index = current_aria_row_index;
+ }
- std::vector<AXNode*> cells;
- FindRowsAndThenCells(table_node_, &cells);
-
- // Compute the actual row and column count, and the set of all unique cell ids
- // in the table.
- row_count = table_node_->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableRowCount);
- col_count = table_node_->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableColumnCount);
- for (AXNode* cell : cells) {
- int row_index = cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellRowIndex);
- int row_span = std::max(1, cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellRowSpan));
- row_count = std::max(row_count, row_index + row_span);
- int col_index = cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellColumnIndex);
- int col_span =
- std::max(1, cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellColumnSpan));
- col_count = std::max(col_count, col_index + col_span);
+ // Ensure the ARIA col index is incrementing.
+ cell_data.aria_col_index =
+ std::max(cell_data.aria_col_index, current_aria_col_index);
+
+ // Update the row count and col count for the whole table to make
+ // sure they're large enough to fit this cell, including its spans.
+ // The -1 in the ARIA calcluations is because ARIA indices are 1-based,
+ // whereas all other indices are zero-based.
+ row_count = std::max(row_count, cell_data.row_index + cell_data.row_span);
+ col_count = std::max(col_count, cell_data.col_index + cell_data.col_span);
+ aria_row_count = std::max(
+ aria_row_count, current_aria_row_index + cell_data.row_span - 1);
+ aria_col_count = std::max(
+ aria_col_count, current_aria_col_index + cell_data.col_span - 1);
+
+ // Update |current_col_index| to reflect the next available index after
+ // this cell including its colspan. The next column index in this row
+ // must be at least this large. Same for the current ARIA col index.
+ current_col_index = cell_data.col_index + cell_data.col_span;
+ current_aria_col_index = cell_data.aria_col_index + cell_data.col_span;
+
+ // Add this cell to our vector.
+ cell_data_vector.push_back(cell_data);
+ }
+
+ // At the end of each row, increment |current_row_index| to reflect the next
+ // available index after this row. The next row index must be at least this
+ // large. Same for the current ARIA row index.
+ current_row_index++;
+ current_aria_row_index++;
}
+}
+void AXTableInfo::BuildCellAndHeaderVectorsFromCellData() {
// Allocate space for the 2-D array of cell IDs and 1-D
// arrays of row headers and column headers.
row_headers.resize(row_count);
@@ -99,31 +260,24 @@ bool AXTableInfo::Update() {
for (auto& row : cell_ids)
row.resize(col_count);
- // Now iterate over the cells and fill in the cell IDs, row headers,
- // and column headers based on the index and span of each cell.
- int32_t cell_index = 0;
- for (AXNode* cell : cells) {
- unique_cell_ids.push_back(cell->id());
- cell_id_to_index[cell->id()] = cell_index++;
- int row_index = cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellRowIndex);
- int row_span = std::max(1, cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellRowSpan));
- int col_index = cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellColumnIndex);
- int col_span =
- std::max(1, cell->data().GetIntAttribute(
- ax::mojom::IntAttribute::kTableCellColumnSpan));
-
- // Cells must contain a 0-based row index and col index.
- if (row_index < 0 || col_index < 0)
- continue;
-
- for (int r = row_index; r < row_index + row_span; r++) {
+ // Fill in the arrays.
+ //
+ // At this point we have computed valid row and column indices for
+ // every cell in the table, and an accurate row and column count for the
+ // whole table that fits every cell and its spans. The final step is to
+ // fill in a 2-dimensional array that lets us look up an individual cell
+ // by its (row, column) coordinates, plus arrays to hold row and column
+ // headers.
+ for (auto& cell_data : cell_data_vector) {
+ for (int r = cell_data.row_index;
+ r < cell_data.row_index + cell_data.row_span; r++) {
DCHECK_LT(r, row_count);
- for (int c = col_index; c < col_index + col_span; c++) {
+ for (int c = cell_data.col_index;
+ c < cell_data.col_index + cell_data.col_span; c++) {
DCHECK_LT(c, col_count);
+ AXNode* cell = cell_data.cell;
cell_ids[r][c] = cell->id();
+
if (cell->data().role == ax::mojom::Role::kColumnHeader) {
col_headers[c].push_back(cell->id());
all_headers.push_back(cell->id());
@@ -134,16 +288,6 @@ bool AXTableInfo::Update() {
}
}
}
-
- if (tree_->enable_extra_mac_nodes())
- UpdateExtraMacNodes();
-
- valid_ = true;
- return true;
-}
-
-void AXTableInfo::Invalidate() {
- valid_ = false;
}
void AXTableInfo::UpdateExtraMacNodes() {
@@ -199,7 +343,7 @@ void AXTableInfo::UpdateExtraMacNodes() {
AXNode* AXTableInfo::CreateExtraMacColumnNode(int col_index) {
int32_t id = tree_->GetNextNegativeInternalNodeId();
int32_t index_in_parent = col_index + table_node_->child_count();
- AXNode* node = new AXNode(table_node_, id, index_in_parent);
+ AXNode* node = new AXNode(tree_, table_node_, id, index_in_parent);
AXNodeData data;
data.id = id;
data.role = ax::mojom::Role::kColumn;
@@ -212,7 +356,7 @@ AXNode* AXTableInfo::CreateExtraMacColumnNode(int col_index) {
AXNode* AXTableInfo::CreateExtraMacTableHeaderNode() {
int32_t id = tree_->GetNextNegativeInternalNodeId();
int32_t index_in_parent = col_count + table_node_->child_count();
- AXNode* node = new AXNode(table_node_, id, index_in_parent);
+ AXNode* node = new AXNode(tree_, table_node_, id, index_in_parent);
AXNodeData data;
data.id = id;
data.role = ax::mojom::Role::kTableHeaderContainer;
@@ -228,11 +372,11 @@ void AXTableInfo::UpdateExtraMacColumnNodeAttributes(int col_index) {
data.int_attributes.clear();
// Update the column index.
- data.AddIntAttribute(ax::mojom::IntAttribute::kTableColumnIndex, col_index);
+ data.AddIntAttribute(IntAttribute::kTableColumnIndex, col_index);
// Update the column header.
if (!col_headers[col_index].empty()) {
- data.AddIntAttribute(ax::mojom::IntAttribute::kTableColumnHeaderId,
+ data.AddIntAttribute(IntAttribute::kTableColumnHeaderId,
col_headers[col_index][0]);
}
diff --git a/chromium/ui/accessibility/ax_table_info.h b/chromium/ui/accessibility/ax_table_info.h
index a2fe6857b5e..39c912c680c 100644
--- a/chromium/ui/accessibility/ax_table_info.h
+++ b/chromium/ui/accessibility/ax_table_info.h
@@ -19,6 +19,17 @@ class AXNode;
// This helper class computes info about tables and grids in AXTrees.
class AX_EXPORT AXTableInfo {
public:
+ struct CellData {
+ AXNode* cell;
+ int32_t cell_id;
+ int32_t col_index;
+ int32_t row_index;
+ int32_t col_span;
+ int32_t row_span;
+ int32_t aria_col_index;
+ int32_t aria_row_index;
+ };
+
// Returns nullptr if the node is not a valid table or grid node.
static AXTableInfo* Create(AXTree* tree, AXNode* table_node);
@@ -36,11 +47,11 @@ class AX_EXPORT AXTableInfo {
// The real row count, guaranteed to be at least as large as the
// maximum row index of any cell.
- int row_count = 0;
+ int32_t row_count = 0;
// The real column count, guaranteed to be at least as large as the
// maximum column index of any cell.
- int col_count = 0;
+ int32_t col_count = 0;
// List of column header nodes IDs for each column index.
std::vector<std::vector<int32_t>> col_headers;
@@ -57,6 +68,9 @@ class AX_EXPORT AXTableInfo {
// really is missing from the table.
std::vector<std::vector<int32_t>> cell_ids;
+ // Array of cell data for every unique cell in the table.
+ std::vector<CellData> cell_data_vector;
+
// Set of all unique cell node IDs in the table.
std::vector<int32_t> unique_cell_ids;
@@ -68,9 +82,19 @@ class AX_EXPORT AXTableInfo {
// Map from each cell's node ID to its index in unique_cell_ids.
base::hash_map<int32_t, int32_t> cell_id_to_index;
+ // The ARIA row count and column count, if any ARIA table or grid
+ // attributes are used in the table at all.
+ int32_t aria_row_count = 0;
+ int32_t aria_col_count = 0;
+
private:
AXTableInfo(AXTree* tree, AXNode* table_node);
+ void ClearVectors();
+ void BuildCellDataVectorFromRowAndCellNodes(
+ const std::vector<AXNode*>& row_nodes,
+ const std::vector<std::vector<AXNode*>>& cell_nodes_per_row);
+ void BuildCellAndHeaderVectorsFromCellData();
void UpdateExtraMacNodes();
void ClearExtraMacNodes();
AXNode* CreateExtraMacColumnNode(int col_index);
diff --git a/chromium/ui/accessibility/ax_table_info_unittest.cc b/chromium/ui/accessibility/ax_table_info_unittest.cc
index 48b26c6caa6..33d4ee47732 100644
--- a/chromium/ui/accessibility/ax_table_info_unittest.cc
+++ b/chromium/ui/accessibility/ax_table_info_unittest.cc
@@ -20,9 +20,10 @@ void MakeTable(AXNodeData* table, int id, int row_count, int col_count) {
table->AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount, col_count);
}
-void MakeRow(AXNodeData* row, int id) {
+void MakeRow(AXNodeData* row, int id, int row_index) {
row->id = id;
row->role = ax::mojom::Role::kRow;
+ row->AddIntAttribute(ax::mojom::IntAttribute::kTableRowIndex, row_index);
}
void MakeCell(AXNodeData* cell,
@@ -65,7 +66,21 @@ void MakeRowHeader(AXNodeData* cell,
} // namespace
-TEST(AXTableInfoTest, SimpleTable) {
+class AXTableInfoTest : public testing::Test {
+ public:
+ AXTableInfoTest() {}
+ ~AXTableInfoTest() override {}
+
+ protected:
+ AXTableInfo* GetTableInfo(AXTree* tree, AXNode* node) {
+ return tree->GetTableInfo(node);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AXTableInfoTest);
+};
+
+TEST_F(AXTableInfoTest, SimpleTable) {
// Simple 2 x 2 table with 2 column headers in first row, 2 cells in second
// row.
AXTreeUpdate initial_state;
@@ -73,9 +88,9 @@ TEST(AXTableInfoTest, SimpleTable) {
initial_state.nodes.resize(7);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2, 3};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {4, 5};
- MakeRow(&initial_state.nodes[2], 3);
+ MakeRow(&initial_state.nodes[2], 3, 1);
initial_state.nodes[2].child_ids = {6, 7};
MakeColumnHeader(&initial_state.nodes[3], 4, 0, 0);
MakeColumnHeader(&initial_state.nodes[4], 5, 0, 1);
@@ -83,10 +98,14 @@ TEST(AXTableInfoTest, SimpleTable) {
MakeCell(&initial_state.nodes[6], 7, 1, 1);
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root()->children()[0]);
+ //
+ // Low-level: test the AXTableInfo directly.
+ //
+
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root()->children()[0]);
EXPECT_FALSE(table_info);
- table_info = tree.GetTableInfo(tree.root());
+ table_info = GetTableInfo(&tree, tree.root());
EXPECT_TRUE(table_info);
EXPECT_EQ(2, table_info->row_count);
@@ -119,9 +138,75 @@ TEST(AXTableInfoTest, SimpleTable) {
EXPECT_EQ(3, table_info->cell_id_to_index[7]);
EXPECT_EQ(0U, table_info->extra_mac_nodes.size());
+
+ //
+ // High-level: Test the helper functions on AXNode.
+ //
+
+ AXNode* table = tree.root();
+ EXPECT_TRUE(table->IsTable());
+ EXPECT_FALSE(table->IsTableRow());
+ EXPECT_FALSE(table->IsTableCellOrHeader());
+ EXPECT_EQ(2, table->GetTableColCount());
+ EXPECT_EQ(2, table->GetTableRowCount());
+
+ EXPECT_EQ(4, table->GetTableCellFromCoords(0, 0)->id());
+ EXPECT_EQ(5, table->GetTableCellFromCoords(0, 1)->id());
+ EXPECT_EQ(6, table->GetTableCellFromCoords(1, 0)->id());
+ EXPECT_EQ(7, table->GetTableCellFromCoords(1, 1)->id());
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(2, 1));
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(1, -1));
+
+ EXPECT_EQ(4, table->GetTableCellFromIndex(0)->id());
+ EXPECT_EQ(5, table->GetTableCellFromIndex(1)->id());
+ EXPECT_EQ(6, table->GetTableCellFromIndex(2)->id());
+ EXPECT_EQ(7, table->GetTableCellFromIndex(3)->id());
+ EXPECT_EQ(nullptr, table->GetTableCellFromIndex(-1));
+ EXPECT_EQ(nullptr, table->GetTableCellFromIndex(4));
+
+ AXNode* row_0 = tree.GetFromId(2);
+ EXPECT_FALSE(row_0->IsTable());
+ EXPECT_TRUE(row_0->IsTableRow());
+ EXPECT_FALSE(row_0->IsTableCellOrHeader());
+ EXPECT_EQ(0, row_0->GetTableRowRowIndex());
+
+ AXNode* row_1 = tree.GetFromId(3);
+ EXPECT_FALSE(row_1->IsTable());
+ EXPECT_TRUE(row_1->IsTableRow());
+ EXPECT_FALSE(row_1->IsTableCellOrHeader());
+ EXPECT_EQ(1, row_1->GetTableRowRowIndex());
+
+ AXNode* cell_0_0 = tree.GetFromId(4);
+ EXPECT_FALSE(cell_0_0->IsTable());
+ EXPECT_FALSE(cell_0_0->IsTableRow());
+ EXPECT_TRUE(cell_0_0->IsTableCellOrHeader());
+ EXPECT_EQ(0, cell_0_0->GetTableCellIndex());
+ EXPECT_EQ(0, cell_0_0->GetTableCellColIndex());
+ EXPECT_EQ(0, cell_0_0->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_0_0->GetTableCellColSpan());
+ EXPECT_EQ(1, cell_0_0->GetTableCellRowSpan());
+
+ AXNode* cell_1_1 = tree.GetFromId(7);
+ EXPECT_FALSE(cell_1_1->IsTable());
+ EXPECT_FALSE(cell_1_1->IsTableRow());
+ EXPECT_TRUE(cell_1_1->IsTableCellOrHeader());
+ EXPECT_EQ(3, cell_1_1->GetTableCellIndex());
+ EXPECT_EQ(1, cell_1_1->GetTableCellColIndex());
+ EXPECT_EQ(1, cell_1_1->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_1_1->GetTableCellColSpan());
+ EXPECT_EQ(1, cell_1_1->GetTableCellRowSpan());
+
+ std::vector<AXNode*> col_headers;
+ cell_1_1->GetTableCellColHeaders(&col_headers);
+ EXPECT_EQ(1U, col_headers.size());
+ EXPECT_EQ(5, col_headers[0]->id());
+
+ std::vector<AXNode*> row_headers;
+ cell_1_1->GetTableCellRowHeaders(&row_headers);
+ EXPECT_EQ(0U, row_headers.size());
}
-TEST(AXTableInfoTest, ComputedTableSizeIncludesSpans) {
+TEST_F(AXTableInfoTest, ComputedTableSizeIncludesSpans) {
// Simple 2 x 2 table with 2 column headers in first row, 2 cells in second
// row, but two cells have spans, affecting the computed row and column count.
AXTreeUpdate initial_state;
@@ -129,9 +214,9 @@ TEST(AXTableInfoTest, ComputedTableSizeIncludesSpans) {
initial_state.nodes.resize(7);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2, 3};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {4, 5};
- MakeRow(&initial_state.nodes[2], 3);
+ MakeRow(&initial_state.nodes[2], 3, 1);
initial_state.nodes[2].child_ids = {6, 7};
MakeCell(&initial_state.nodes[3], 4, 0, 0);
MakeCell(&initial_state.nodes[4], 5, 0, 1, 1, 5); // Column span of 5
@@ -139,12 +224,12 @@ TEST(AXTableInfoTest, ComputedTableSizeIncludesSpans) {
MakeCell(&initial_state.nodes[6], 7, 1, 1, 3, 1); // Row span of 3
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root());
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root());
EXPECT_EQ(4, table_info->row_count);
EXPECT_EQ(6, table_info->col_count);
}
-TEST(AXTableInfoTest, AuthorRowAndColumnCountsAreRespected) {
+TEST_F(AXTableInfoTest, AuthorRowAndColumnCountsAreRespected) {
// Simple 1 x 1 table, but the table's authored row and column
// counts imply a larger table (with missing cells).
AXTreeUpdate initial_state;
@@ -152,34 +237,34 @@ TEST(AXTableInfoTest, AuthorRowAndColumnCountsAreRespected) {
initial_state.nodes.resize(3);
MakeTable(&initial_state.nodes[0], 1, 8, 9);
initial_state.nodes[0].child_ids = {2};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {3};
MakeCell(&initial_state.nodes[2], 2, 0, 1);
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root());
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root());
EXPECT_EQ(8, table_info->row_count);
EXPECT_EQ(9, table_info->col_count);
}
-TEST(AXTableInfoTest, TableInfoRecomputedOnlyWhenTableChanges) {
+TEST_F(AXTableInfoTest, TableInfoRecomputedOnlyWhenTableChanges) {
// Simple 1 x 1 table.
AXTreeUpdate initial_state;
initial_state.root_id = 1;
initial_state.nodes.resize(3);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {3};
MakeCell(&initial_state.nodes[2], 3, 0, 0);
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root());
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root());
EXPECT_EQ(1, table_info->row_count);
EXPECT_EQ(1, table_info->col_count);
// Table info is cached.
- AXTableInfo* table_info_2 = tree.GetTableInfo(tree.root());
+ AXTableInfo* table_info_2 = GetTableInfo(&tree, tree.root());
EXPECT_EQ(table_info, table_info_2);
// Update the table so that the cell has a span.
@@ -187,12 +272,12 @@ TEST(AXTableInfoTest, TableInfoRecomputedOnlyWhenTableChanges) {
MakeCell(&update.nodes[2], 3, 0, 0, 1, 2);
EXPECT_TRUE(tree.Unserialize(update));
- AXTableInfo* table_info_3 = tree.GetTableInfo(tree.root());
+ AXTableInfo* table_info_3 = GetTableInfo(&tree, tree.root());
EXPECT_EQ(1, table_info_3->row_count);
EXPECT_EQ(2, table_info_3->col_count);
}
-TEST(AXTableInfoTest, CellIdsHandlesSpansAndMissingCells) {
+TEST_F(AXTableInfoTest, CellIdsHandlesSpansAndMissingCells) {
// 3 column x 2 row table with spans and missing cells:
//
// +---+---+---+
@@ -205,16 +290,16 @@ TEST(AXTableInfoTest, CellIdsHandlesSpansAndMissingCells) {
initial_state.nodes.resize(6);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2, 3};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {4, 5};
- MakeRow(&initial_state.nodes[2], 3);
+ MakeRow(&initial_state.nodes[2], 3, 1);
initial_state.nodes[2].child_ids = {6};
MakeCell(&initial_state.nodes[3], 4, 0, 0, 2, 1); // Row span of 2
MakeCell(&initial_state.nodes[4], 5, 0, 1, 1, 5); // Column span of 2
MakeCell(&initial_state.nodes[5], 6, 1, 1);
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root());
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root());
EXPECT_EQ(4, table_info->cell_ids[0][0]);
EXPECT_EQ(5, table_info->cell_ids[0][1]);
EXPECT_EQ(5, table_info->cell_ids[0][1]);
@@ -232,7 +317,7 @@ TEST(AXTableInfoTest, CellIdsHandlesSpansAndMissingCells) {
EXPECT_EQ(2, table_info->cell_id_to_index[6]);
}
-TEST(AXTableInfoTest, SkipsGenericAndIgnoredNodes) {
+TEST_F(AXTableInfoTest, SkipsGenericAndIgnoredNodes) {
// Simple 2 x 2 table with 2 cells in the first row, 2 cells in the second
// row, but with extra divs and ignored nodes in the tree.
//
@@ -252,7 +337,7 @@ TEST(AXTableInfoTest, SkipsGenericAndIgnoredNodes) {
initial_state.nodes.resize(10);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2, 7};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {3};
initial_state.nodes[2].id = 3;
initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
@@ -265,16 +350,16 @@ TEST(AXTableInfoTest, SkipsGenericAndIgnoredNodes) {
initial_state.nodes[6].id = 7;
initial_state.nodes[6].AddState(ax::mojom::State::kIgnored);
initial_state.nodes[6].child_ids = {8};
- MakeRow(&initial_state.nodes[7], 8);
+ MakeRow(&initial_state.nodes[7], 8, 1);
initial_state.nodes[7].child_ids = {9, 10};
MakeCell(&initial_state.nodes[8], 9, 1, 0);
MakeCell(&initial_state.nodes[9], 10, 1, 1);
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root()->children()[0]);
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root()->children()[0]);
EXPECT_FALSE(table_info);
- table_info = tree.GetTableInfo(tree.root());
+ table_info = GetTableInfo(&tree, tree.root());
EXPECT_TRUE(table_info);
EXPECT_EQ(2, table_info->row_count);
@@ -286,7 +371,7 @@ TEST(AXTableInfoTest, SkipsGenericAndIgnoredNodes) {
EXPECT_EQ(10, table_info->cell_ids[1][1]);
}
-TEST(AXTableInfoTest, HeadersWithSpans) {
+TEST_F(AXTableInfoTest, HeadersWithSpans) {
// Row and column headers spanning multiple cells.
// In the figure below, 5 and 6 are headers.
//
@@ -302,11 +387,11 @@ TEST(AXTableInfoTest, HeadersWithSpans) {
initial_state.nodes.resize(8);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2, 3, 4};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {5};
- MakeRow(&initial_state.nodes[2], 3);
+ MakeRow(&initial_state.nodes[2], 3, 1);
initial_state.nodes[2].child_ids = {6, 7};
- MakeRow(&initial_state.nodes[3], 4);
+ MakeRow(&initial_state.nodes[3], 4, 2);
initial_state.nodes[3].child_ids = {8};
MakeColumnHeader(&initial_state.nodes[4], 5, 0, 1, 1, 2);
MakeRowHeader(&initial_state.nodes[5], 6, 1, 0, 2, 1);
@@ -314,10 +399,10 @@ TEST(AXTableInfoTest, HeadersWithSpans) {
MakeCell(&initial_state.nodes[7], 8, 2, 2);
AXTree tree(initial_state);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root()->children()[0]);
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root()->children()[0]);
EXPECT_FALSE(table_info);
- table_info = tree.GetTableInfo(tree.root());
+ table_info = GetTableInfo(&tree, tree.root());
EXPECT_TRUE(table_info);
EXPECT_EQ(3U, table_info->row_headers.size());
@@ -345,7 +430,7 @@ TEST(AXTableInfoTest, HeadersWithSpans) {
EXPECT_EQ(8, table_info->cell_ids[2][2]);
}
-TEST(AXTableInfoTest, ExtraMacNodes) {
+TEST_F(AXTableInfoTest, ExtraMacNodes) {
// Simple 2 x 2 table with 2 column headers in first row, 2 cells in second
// row.
AXTreeUpdate initial_state;
@@ -353,9 +438,9 @@ TEST(AXTableInfoTest, ExtraMacNodes) {
initial_state.nodes.resize(7);
MakeTable(&initial_state.nodes[0], 1, 0, 0);
initial_state.nodes[0].child_ids = {2, 3};
- MakeRow(&initial_state.nodes[1], 2);
+ MakeRow(&initial_state.nodes[1], 2, 0);
initial_state.nodes[1].child_ids = {4, 5};
- MakeRow(&initial_state.nodes[2], 3);
+ MakeRow(&initial_state.nodes[2], 3, 1);
initial_state.nodes[2].child_ids = {6, 7};
MakeColumnHeader(&initial_state.nodes[3], 4, 0, 0);
MakeColumnHeader(&initial_state.nodes[4], 5, 0, 1);
@@ -364,10 +449,10 @@ TEST(AXTableInfoTest, ExtraMacNodes) {
AXTree tree(initial_state);
tree.SetEnableExtraMacNodes(true);
- AXTableInfo* table_info = tree.GetTableInfo(tree.root()->children()[0]);
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root()->children()[0]);
EXPECT_FALSE(table_info);
- table_info = tree.GetTableInfo(tree.root());
+ table_info = GetTableInfo(&tree, tree.root());
EXPECT_TRUE(table_info);
// We expect 3 extra Mac nodes: two column nodes, and one header node.
@@ -417,4 +502,350 @@ TEST(AXTableInfoTest, ExtraMacNodes) {
EXPECT_EQ(5, indirect_child_ids[1]);
}
+TEST_F(AXTableInfoTest, TableWithNoIndices) {
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(7);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kTable;
+ initial_state.nodes[0].child_ids = {2, 3};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kRow;
+ initial_state.nodes[1].child_ids = {4, 5};
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kRow;
+ initial_state.nodes[2].child_ids = {6, 7};
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].role = ax::mojom::Role::kColumnHeader;
+ initial_state.nodes[4].id = 5;
+ initial_state.nodes[4].role = ax::mojom::Role::kColumnHeader;
+ initial_state.nodes[5].id = 6;
+ initial_state.nodes[5].role = ax::mojom::Role::kCell;
+ initial_state.nodes[6].id = 7;
+ initial_state.nodes[6].role = ax::mojom::Role::kCell;
+
+ AXTree tree(initial_state);
+ AXNode* table = tree.root();
+
+ EXPECT_TRUE(table->IsTable());
+ EXPECT_FALSE(table->IsTableRow());
+ EXPECT_FALSE(table->IsTableCellOrHeader());
+ EXPECT_EQ(2, table->GetTableColCount());
+ EXPECT_EQ(2, table->GetTableRowCount());
+
+ EXPECT_EQ(4, table->GetTableCellFromCoords(0, 0)->id());
+ EXPECT_EQ(5, table->GetTableCellFromCoords(0, 1)->id());
+ EXPECT_EQ(6, table->GetTableCellFromCoords(1, 0)->id());
+ EXPECT_EQ(7, table->GetTableCellFromCoords(1, 1)->id());
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(2, 1));
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(1, -1));
+
+ EXPECT_EQ(4, table->GetTableCellFromIndex(0)->id());
+ EXPECT_EQ(5, table->GetTableCellFromIndex(1)->id());
+ EXPECT_EQ(6, table->GetTableCellFromIndex(2)->id());
+ EXPECT_EQ(7, table->GetTableCellFromIndex(3)->id());
+ EXPECT_EQ(nullptr, table->GetTableCellFromIndex(-1));
+ EXPECT_EQ(nullptr, table->GetTableCellFromIndex(4));
+
+ AXNode* cell_0_0 = tree.GetFromId(4);
+ EXPECT_EQ(0, cell_0_0->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_0_0->GetTableCellColIndex());
+ AXNode* cell_0_1 = tree.GetFromId(5);
+ EXPECT_EQ(0, cell_0_1->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_0_1->GetTableCellColIndex());
+ AXNode* cell_1_0 = tree.GetFromId(6);
+ EXPECT_EQ(1, cell_1_0->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_1_0->GetTableCellColIndex());
+ AXNode* cell_1_1 = tree.GetFromId(7);
+ EXPECT_EQ(1, cell_1_1->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_1_1->GetTableCellColIndex());
+}
+
+TEST_F(AXTableInfoTest, TableWithPartialIndices) {
+ // Start with a table with no indices.
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(7);
+ initial_state.nodes[0].id = 1;
+ initial_state.nodes[0].role = ax::mojom::Role::kTable;
+ initial_state.nodes[0].child_ids = {2, 3};
+ initial_state.nodes[1].id = 2;
+ initial_state.nodes[1].role = ax::mojom::Role::kRow;
+ initial_state.nodes[1].child_ids = {4, 5};
+ initial_state.nodes[2].id = 3;
+ initial_state.nodes[2].role = ax::mojom::Role::kRow;
+ initial_state.nodes[2].child_ids = {6, 7};
+ initial_state.nodes[3].id = 4;
+ initial_state.nodes[3].role = ax::mojom::Role::kColumnHeader;
+ initial_state.nodes[4].id = 5;
+ initial_state.nodes[4].role = ax::mojom::Role::kColumnHeader;
+ initial_state.nodes[5].id = 6;
+ initial_state.nodes[5].role = ax::mojom::Role::kCell;
+ initial_state.nodes[6].id = 7;
+ initial_state.nodes[6].role = ax::mojom::Role::kCell;
+
+ AXTree tree(initial_state);
+ AXNode* table = tree.root();
+
+ EXPECT_EQ(2, table->GetTableColCount());
+ EXPECT_EQ(2, table->GetTableRowCount());
+
+ AXNode* cell_0_0 = tree.GetFromId(4);
+ EXPECT_EQ(0, cell_0_0->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_0_0->GetTableCellColIndex());
+ AXNode* cell_0_1 = tree.GetFromId(5);
+ EXPECT_EQ(0, cell_0_1->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_0_1->GetTableCellColIndex());
+ AXNode* cell_1_0 = tree.GetFromId(6);
+ EXPECT_EQ(1, cell_1_0->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_1_0->GetTableCellColIndex());
+ AXNode* cell_1_1 = tree.GetFromId(7);
+ EXPECT_EQ(1, cell_1_1->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_1_1->GetTableCellColIndex());
+
+ AXTreeUpdate update = initial_state;
+ update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableColumnCount,
+ 5);
+ update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kTableRowCount, 2);
+ update.nodes[5].AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex,
+ 2);
+ update.nodes[5].AddIntAttribute(
+ ax::mojom::IntAttribute::kTableCellColumnIndex, 0);
+ update.nodes[6].AddIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex,
+ 2);
+ update.nodes[6].AddIntAttribute(
+ ax::mojom::IntAttribute::kTableCellColumnIndex, 2);
+ EXPECT_TRUE(tree.Unserialize(update));
+
+ // The largest column index in the table is 2, but the
+ // table claims it has a column count of 5. That's allowed.
+ EXPECT_EQ(5, table->GetTableColCount());
+
+ // While the table claims it has a row count of 2, the
+ // last row has an index of 2, so the correct row count is 3.
+ EXPECT_EQ(3, table->GetTableRowCount());
+
+ // All of the specified row and cell indices are legal
+ // so they're respected.
+ EXPECT_EQ(0, cell_0_0->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_0_0->GetTableCellColIndex());
+ EXPECT_EQ(0, cell_0_1->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_0_1->GetTableCellColIndex());
+ EXPECT_EQ(2, cell_1_0->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_1_0->GetTableCellColIndex());
+ EXPECT_EQ(2, cell_1_1->GetTableCellRowIndex());
+ EXPECT_EQ(2, cell_1_1->GetTableCellColIndex());
+
+ // Fetching cells by coordinates works.
+ EXPECT_EQ(4, table->GetTableCellFromCoords(0, 0)->id());
+ EXPECT_EQ(5, table->GetTableCellFromCoords(0, 1)->id());
+ EXPECT_EQ(6, table->GetTableCellFromCoords(2, 0)->id());
+ EXPECT_EQ(7, table->GetTableCellFromCoords(2, 2)->id());
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(0, 2));
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(1, 0));
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(1, 1));
+ EXPECT_EQ(nullptr, table->GetTableCellFromCoords(2, 1));
+}
+
+TEST_F(AXTableInfoTest, BadRowIndicesIgnored) {
+ // The table claims it has two rows and two columns, but
+ // the cell indices for both the first and second rows
+ // are for row 2 (zero-based).
+ //
+ // The cell indexes for the first row should be
+ // respected, and for the second row it will get the
+ // next row index.
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(7);
+ MakeTable(&initial_state.nodes[0], 1, 2, 2);
+ initial_state.nodes[0].child_ids = {2, 3};
+ MakeRow(&initial_state.nodes[1], 2, 0);
+ initial_state.nodes[1].child_ids = {4, 5};
+ MakeRow(&initial_state.nodes[2], 3, 0);
+ initial_state.nodes[2].child_ids = {6, 7};
+ MakeCell(&initial_state.nodes[3], 4, 2, 0);
+ MakeCell(&initial_state.nodes[4], 5, 2, 1);
+ MakeCell(&initial_state.nodes[5], 6, 2, 0);
+ MakeCell(&initial_state.nodes[6], 7, 2, 1);
+ AXTree tree(initial_state);
+ AXNode* table = tree.root();
+
+ EXPECT_EQ(2, table->GetTableColCount());
+ EXPECT_EQ(4, table->GetTableRowCount());
+
+ AXNode* cell_id_4 = tree.GetFromId(4);
+ EXPECT_EQ(2, cell_id_4->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_id_4->GetTableCellColIndex());
+ AXNode* cell_id_5 = tree.GetFromId(5);
+ EXPECT_EQ(2, cell_id_5->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_id_5->GetTableCellColIndex());
+ AXNode* cell_id_6 = tree.GetFromId(6);
+ EXPECT_EQ(3, cell_id_6->GetTableCellRowIndex());
+ EXPECT_EQ(0, cell_id_6->GetTableCellColIndex());
+ AXNode* cell_id_7 = tree.GetFromId(7);
+ EXPECT_EQ(3, cell_id_7->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_id_7->GetTableCellColIndex());
+}
+
+TEST_F(AXTableInfoTest, BadColIndicesIgnored) {
+ // The table claims it has two rows and two columns, but
+ // the cell indices for the columns either repeat or
+ // go backwards.
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(7);
+ MakeTable(&initial_state.nodes[0], 1, 2, 2);
+ initial_state.nodes[0].child_ids = {2, 3};
+ MakeRow(&initial_state.nodes[1], 2, 0);
+ initial_state.nodes[1].child_ids = {4, 5};
+ MakeRow(&initial_state.nodes[2], 3, 0);
+ initial_state.nodes[2].child_ids = {6, 7};
+ MakeCell(&initial_state.nodes[3], 4, 0, 1);
+ MakeCell(&initial_state.nodes[4], 5, 0, 1);
+ MakeCell(&initial_state.nodes[5], 6, 1, 2);
+ MakeCell(&initial_state.nodes[6], 7, 1, 1);
+ AXTree tree(initial_state);
+ AXNode* table = tree.root();
+
+ EXPECT_EQ(4, table->GetTableColCount());
+ EXPECT_EQ(2, table->GetTableRowCount());
+
+ AXNode* cell_id_4 = tree.GetFromId(4);
+ EXPECT_EQ(0, cell_id_4->GetTableCellRowIndex());
+ EXPECT_EQ(1, cell_id_4->GetTableCellColIndex());
+ AXNode* cell_id_5 = tree.GetFromId(5);
+ EXPECT_EQ(0, cell_id_5->GetTableCellRowIndex());
+ EXPECT_EQ(2, cell_id_5->GetTableCellColIndex());
+ AXNode* cell_id_6 = tree.GetFromId(6);
+ EXPECT_EQ(1, cell_id_6->GetTableCellRowIndex());
+ EXPECT_EQ(2, cell_id_6->GetTableCellColIndex());
+ AXNode* cell_id_7 = tree.GetFromId(7);
+ EXPECT_EQ(1, cell_id_7->GetTableCellRowIndex());
+ EXPECT_EQ(3, cell_id_7->GetTableCellColIndex());
+}
+
+TEST_F(AXTableInfoTest, AriaIndicesinferred) {
+ // Note that ARIA indices are 1-based, whereas the rest of
+ // the table indices are zero-based.
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(13);
+ MakeTable(&initial_state.nodes[0], 1, 3, 3);
+ initial_state.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kAriaRowCount,
+ 5);
+ initial_state.nodes[0].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaColumnCount, 5);
+ initial_state.nodes[0].child_ids = {2, 3, 4};
+ MakeRow(&initial_state.nodes[1], 2, 0);
+ initial_state.nodes[1].child_ids = {5, 6, 7};
+ MakeRow(&initial_state.nodes[2], 3, 1);
+ initial_state.nodes[2].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellRowIndex, 4);
+ initial_state.nodes[2].child_ids = {8, 9, 10};
+ MakeRow(&initial_state.nodes[3], 4, 2);
+ initial_state.nodes[3].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellRowIndex, 4);
+ initial_state.nodes[3].child_ids = {11, 12, 13};
+ MakeCell(&initial_state.nodes[4], 5, 0, 0);
+ initial_state.nodes[4].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellRowIndex, 2);
+ initial_state.nodes[4].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellColumnIndex, 2);
+ MakeCell(&initial_state.nodes[5], 6, 0, 1);
+ MakeCell(&initial_state.nodes[6], 7, 0, 2);
+ MakeCell(&initial_state.nodes[7], 8, 1, 0);
+ MakeCell(&initial_state.nodes[8], 9, 1, 1);
+ MakeCell(&initial_state.nodes[9], 10, 1, 2);
+ MakeCell(&initial_state.nodes[10], 11, 2, 0);
+ initial_state.nodes[10].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellColumnIndex, 3);
+ MakeCell(&initial_state.nodes[11], 12, 2, 1);
+ initial_state.nodes[11].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellColumnIndex, 2);
+ MakeCell(&initial_state.nodes[12], 13, 2, 2);
+ initial_state.nodes[12].AddIntAttribute(
+ ax::mojom::IntAttribute::kAriaCellColumnIndex, 1);
+ AXTree tree(initial_state);
+ AXNode* table = tree.root();
+
+ EXPECT_EQ(5, table->GetTableAriaColCount());
+ EXPECT_EQ(5, table->GetTableAriaRowCount());
+
+ // The first row has the first cell ARIA row and column index
+ // specified as (2, 2). The rest of the row is inferred.
+
+ AXNode* cell_0_0 = tree.GetFromId(5);
+ EXPECT_EQ(2, cell_0_0->GetTableCellAriaRowIndex());
+ EXPECT_EQ(2, cell_0_0->GetTableCellAriaColIndex());
+
+ AXNode* cell_0_1 = tree.GetFromId(6);
+ EXPECT_EQ(2, cell_0_1->GetTableCellAriaRowIndex());
+ EXPECT_EQ(3, cell_0_1->GetTableCellAriaColIndex());
+
+ AXNode* cell_0_2 = tree.GetFromId(7);
+ EXPECT_EQ(2, cell_0_2->GetTableCellAriaRowIndex());
+ EXPECT_EQ(4, cell_0_2->GetTableCellAriaColIndex());
+
+ // The next row has the ARIA row index set to 4 on the row
+ // element. The rest is inferred.
+
+ AXNode* cell_1_0 = tree.GetFromId(8);
+ EXPECT_EQ(4, cell_1_0->GetTableCellAriaRowIndex());
+ EXPECT_EQ(1, cell_1_0->GetTableCellAriaColIndex());
+
+ AXNode* cell_1_1 = tree.GetFromId(9);
+ EXPECT_EQ(4, cell_1_1->GetTableCellAriaRowIndex());
+ EXPECT_EQ(2, cell_1_1->GetTableCellAriaColIndex());
+
+ AXNode* cell_1_2 = tree.GetFromId(10);
+ EXPECT_EQ(4, cell_1_2->GetTableCellAriaRowIndex());
+ EXPECT_EQ(3, cell_1_2->GetTableCellAriaColIndex());
+
+ // The last row has the ARIA row index set to 4 again, which is
+ // illegal so we should get 5. The cells have column indices of
+ // 3, 2, 1 which is illegal so we ignore the latter two and should
+ // end up with column indices of 3, 4, 5.
+
+ AXNode* cell_2_0 = tree.GetFromId(11);
+ EXPECT_EQ(5, cell_2_0->GetTableCellAriaRowIndex());
+ EXPECT_EQ(3, cell_2_0->GetTableCellAriaColIndex());
+
+ AXNode* cell_2_1 = tree.GetFromId(12);
+ EXPECT_EQ(5, cell_2_1->GetTableCellAriaRowIndex());
+ EXPECT_EQ(4, cell_2_1->GetTableCellAriaColIndex());
+
+ AXNode* cell_2_2 = tree.GetFromId(13);
+ EXPECT_EQ(5, cell_2_2->GetTableCellAriaRowIndex());
+ EXPECT_EQ(5, cell_2_2->GetTableCellAriaColIndex());
+}
+
+TEST_F(AXTableInfoTest, TableChanges) {
+ // Simple 2 col x 1 row table
+ AXTreeUpdate initial_state;
+ initial_state.root_id = 1;
+ initial_state.nodes.resize(4);
+ MakeTable(&initial_state.nodes[0], 1, 0, 0);
+ initial_state.nodes[0].child_ids = {2};
+ MakeRow(&initial_state.nodes[1], 2, 0);
+ initial_state.nodes[1].child_ids = {3, 4};
+ MakeCell(&initial_state.nodes[2], 3, 0, 0);
+ MakeCell(&initial_state.nodes[3], 4, 0, 1);
+ AXTree tree(initial_state);
+
+ AXTableInfo* table_info = GetTableInfo(&tree, tree.root());
+ EXPECT_TRUE(table_info);
+
+ EXPECT_EQ(1, table_info->row_count);
+ EXPECT_EQ(2, table_info->col_count);
+
+ // Update the tree to remove the table role.
+ AXTreeUpdate update = initial_state;
+ update.nodes[0].role = ax::mojom::Role::kGroup;
+ ASSERT_TRUE(tree.Unserialize(update));
+
+ table_info = GetTableInfo(&tree, tree.root());
+ EXPECT_FALSE(table_info);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/ax_tree.cc b/chromium/ui/accessibility/ax_tree.cc
index 648a3f3c30d..1b5932fbc80 100644
--- a/chromium/ui/accessibility/ax_tree.cc
+++ b/chromium/ui/accessibility/ax_tree.cc
@@ -8,8 +8,10 @@
#include <set>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_table_info.h"
#include "ui/gfx/transform.h"
@@ -173,7 +175,7 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node,
// If |bounds| is uninitialized, which is not the same as empty,
// start with the node bounds.
if (bounds.width() == 0 && bounds.height() == 0) {
- bounds = node->data().location;
+ bounds = node->data().relative_bounds.bounds;
// If the node bounds is empty (either width or height is zero),
// try to compute good bounds from the children.
@@ -187,12 +189,13 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node,
}
}
} else {
- bounds.Offset(node->data().location.x(), node->data().location.y());
+ bounds.Offset(node->data().relative_bounds.bounds.x(),
+ node->data().relative_bounds.bounds.y());
}
while (node != nullptr) {
- if (node->data().transform)
- node->data().transform->TransformRect(&bounds);
+ if (node->data().relative_bounds.transform)
+ node->data().relative_bounds.transform->TransformRect(&bounds);
const AXNode* container;
// Normally we apply any transforms and offsets for each node and
@@ -202,13 +205,13 @@ gfx::RectF AXTree::RelativeToTreeBounds(const AXNode* node,
if (bounds.width() == 0 && bounds.height() == 0)
container = node->parent();
else
- container = GetFromId(node->data().offset_container_id);
+ container = GetFromId(node->data().relative_bounds.offset_container_id);
if (!container && container != root())
container = root();
if (!container || container == node)
break;
- gfx::RectF container_bounds = container->data().location;
+ gfx::RectF container_bounds = container->data().relative_bounds.bounds;
bounds.Offset(container_bounds.x(), container_bounds.y());
// If we don't have any size yet, take the size from this ancestor.
@@ -333,6 +336,13 @@ std::set<int32_t> AXTree::GetNodeIdsForChildTreeId(
return std::set<int32_t>();
}
+const std::set<AXTreeID> AXTree::GetAllChildTreeIds() const {
+ std::set<AXTreeID> result;
+ for (auto entry : child_tree_id_reverse_map_)
+ result.insert(entry.first);
+ return result;
+}
+
bool AXTree::Unserialize(const AXTreeUpdate& update) {
AXTreeUpdateState update_state;
int32_t old_root_id = root_ ? root_->id() : 0;
@@ -461,7 +471,14 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) {
return true;
}
-AXTableInfo* AXTree::GetTableInfo(AXNode* table_node) {
+AXTableInfo* AXTree::GetTableInfo(const AXNode* const_table_node) const {
+ // Note: the const_casts are here because we want this function to be able
+ // to be called from a const virtual function on AXNode. AXTableInfo is
+ // computed on demand and cached, but that's an implementation detail
+ // we want to hide from users of this API.
+ AXNode* table_node = const_cast<AXNode*>(const_table_node);
+ AXTree* tree = const_cast<AXTree*>(this);
+
DCHECK(table_node);
const auto& cached = table_info_map_.find(table_node->id());
if (cached != table_info_map_.end()) {
@@ -474,21 +491,23 @@ AXTableInfo* AXTree::GetTableInfo(AXNode* table_node) {
// If Update() returned false, this is no longer a valid table.
// Remove it from the map.
delete table_info;
+ table_info = nullptr;
table_info_map_.erase(table_node->id());
}
+ // See note about const_cast, above.
if (delegate_)
- delegate_->OnNodeChanged(this, table_node);
+ delegate_->OnNodeChanged(tree, table_node);
}
return table_info;
}
- AXTableInfo* table_info = AXTableInfo::Create(this, table_node);
+ AXTableInfo* table_info = AXTableInfo::Create(tree, table_node);
if (!table_info)
return nullptr;
table_info_map_[table_node->id()] = table_info;
if (delegate_)
- delegate_->OnNodeChanged(this, table_node);
+ delegate_->OnNodeChanged(tree, table_node);
return table_info;
}
@@ -501,7 +520,7 @@ AXNode* AXTree::CreateNode(AXNode* parent,
int32_t id,
int32_t index_in_parent,
AXTreeUpdateState* update_state) {
- AXNode* new_node = new AXNode(parent, id, index_in_parent);
+ AXNode* new_node = new AXNode(this, parent, id, index_in_parent);
id_map_[new_node->id()] = new_node;
if (delegate_) {
if (update_state->HasChangedNode(new_node) &&
@@ -672,8 +691,8 @@ void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
const AXNodeData& old_data = node->data();
int id = new_data.id;
- auto int_callback = [this, node, id](ax::mojom::IntAttribute attr,
- const int& old_id, const int& new_id) {
+ auto int_callback = [this, id](ax::mojom::IntAttribute attr,
+ const int& old_id, const int& new_id) {
if (!IsNodeIdIntAttribute(attr))
return;
@@ -694,10 +713,9 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes,
0, int_callback);
- auto intlist_callback = [this, node, id](
- ax::mojom::IntListAttribute attr,
- const std::vector<int32_t>& old_idlist,
- const std::vector<int32_t>& new_idlist) {
+ auto intlist_callback = [this, id](ax::mojom::IntListAttribute attr,
+ const std::vector<int32_t>& old_idlist,
+ const std::vector<int32_t>& new_idlist) {
if (!IsNodeIdIntListAttribute(attr))
return;
@@ -716,9 +734,9 @@ void AXTree::UpdateReverseRelations(AXNode* node, const AXNodeData& new_data) {
new_data.intlist_attributes,
std::vector<int32_t>(), intlist_callback);
- auto string_callback = [this, node, id](ax::mojom::StringAttribute attr,
- const std::string& old_string,
- const std::string& new_string) {
+ auto string_callback = [this, id](ax::mojom::StringAttribute attr,
+ const std::string& old_string,
+ const std::string& new_string) {
if (attr == ax::mojom::StringAttribute::kChildTreeId) {
// Remove old_string -> id from the map, and clear map keys if
// their values are now empty.
diff --git a/chromium/ui/accessibility/ax_tree.h b/chromium/ui/accessibility/ax_tree.h
index 993eb22faab..fb8f2b74d68 100644
--- a/chromium/ui/accessibility/ax_tree.h
+++ b/chromium/ui/accessibility/ax_tree.h
@@ -11,13 +11,13 @@
#include "base/containers/hash_tables.h"
#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_update.h"
namespace ui {
-class AXNode;
class AXTableInfo;
class AXTree;
struct AXTreeUpdateState;
@@ -157,7 +157,7 @@ class AX_EXPORT AXTreeDelegate {
// used as a source for sending updates to another client tree.
// It's designed to be subclassed to implement support for native
// accessibility APIs on a specific platform.
-class AX_EXPORT AXTree {
+class AX_EXPORT AXTree : public AXNode::OwnerTree {
public:
typedef std::map<ax::mojom::IntAttribute,
std::map<int32_t, std::set<int32_t>>>
@@ -177,8 +177,9 @@ class AX_EXPORT AXTree {
const AXTreeData& data() const { return data_; }
+ // AXNode::OwnerTree override.
// Returns the AXNode with the given |id| if it is part of this AXTree.
- AXNode* GetFromId(int32_t id) const;
+ AXNode* GetFromId(int32_t id) const override;
// Returns true on success. If it returns false, it's a fatal error
// and this tree should be destroyed, and the source of the tree update
@@ -226,6 +227,9 @@ class AX_EXPORT AXTree {
// have a kChildTreeId int attribute with that value.
std::set<int32_t> GetNodeIdsForChildTreeId(AXTreeID child_tree_id) const;
+ // Get all of the child tree IDs referenced by any node in this tree.
+ const std::set<AXTreeID> GetAllChildTreeIds() const;
+
// Map from a relation attribute to a map from a target id to source ids.
const IntReverseRelationMap& int_reverse_relations() {
return int_reverse_relations_;
@@ -234,16 +238,6 @@ class AX_EXPORT AXTree {
return intlist_reverse_relations_;
}
- // Given a node in this accessibility tree that corresponds to a table
- // or grid, return an object containing information about the
- // table structure. This object is computed lazily on-demand and
- // cached until the next time the tree is updated. Clients should
- // not retain this pointer, they should just request it every time
- // it's needed.
- //
- // Returns nullptr if the node is not a valid table.
- AXTableInfo* GetTableInfo(AXNode* table_node);
-
// Return a multi-line indented string representation, for logging.
std::string ToString() const;
@@ -264,6 +258,20 @@ class AX_EXPORT AXTree {
int32_t GetNextNegativeInternalNodeId();
private:
+ friend class AXTableInfoTest;
+
+ // AXNode::OwnerTree override.
+ //
+ // Given a node in this accessibility tree that corresponds to a table
+ // or grid, return an object containing information about the
+ // table structure. This object is computed lazily on-demand and
+ // cached until the next time the tree is updated. Clients should
+ // not retain this pointer, they should just request it every time
+ // it's needed.
+ //
+ // Returns nullptr if the node is not a valid table.
+ AXTableInfo* GetTableInfo(const AXNode* table_node) const override;
+
AXNode* CreateNode(AXNode* parent,
int32_t id,
int32_t index_in_parent,
@@ -322,7 +330,7 @@ class AX_EXPORT AXTree {
// Map from node ID to cached table info, if the given node is a table.
// Invalidated every time the tree is updated.
- base::hash_map<int32_t, AXTableInfo*> table_info_map_;
+ mutable base::hash_map<int32_t, AXTableInfo*> table_info_map_;
// The next negative node ID to use for internal nodes.
int32_t next_negative_internal_node_id_ = -1;
diff --git a/chromium/ui/accessibility/ax_tree_combiner.cc b/chromium/ui/accessibility/ax_tree_combiner.cc
index b0ab36fa1f4..207a2aa3050 100644
--- a/chromium/ui/accessibility/ax_tree_combiner.cc
+++ b/chromium/ui/accessibility/ax_tree_combiner.cc
@@ -91,8 +91,9 @@ void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) {
node.child_ids[j] = MapId(tree_id, node.child_ids[j]);
// Map the container id.
- if (node.offset_container_id > 0)
- node.offset_container_id = MapId(tree_id, node.offset_container_id);
+ if (node.relative_bounds.offset_container_id > 0)
+ node.relative_bounds.offset_container_id =
+ MapId(tree_id, node.relative_bounds.offset_container_id);
// Map other int attributes that refer to node IDs.
for (size_t j = 0; j < node.int_attributes.size(); ++j) {
diff --git a/chromium/ui/accessibility/ax_tree_unittest.cc b/chromium/ui/accessibility/ax_tree_unittest.cc
index 42d660a491d..109eda97e8f 100644
--- a/chromium/ui/accessibility/ax_tree_unittest.cc
+++ b/chromium/ui/accessibility/ax_tree_unittest.cc
@@ -231,19 +231,19 @@ TEST(AXTreeTest, SerializeSimpleAXTree) {
root.id = 1;
root.role = ax::mojom::Role::kDialog;
root.AddState(ax::mojom::State::kFocusable);
- root.location = gfx::RectF(0, 0, 800, 600);
+ root.relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
root.child_ids.push_back(2);
root.child_ids.push_back(3);
AXNodeData button;
button.id = 2;
button.role = ax::mojom::Role::kButton;
- button.location = gfx::RectF(20, 20, 200, 30);
+ button.relative_bounds.bounds = gfx::RectF(20, 20, 200, 30);
AXNodeData checkbox;
checkbox.id = 3;
checkbox.role = ax::mojom::Role::kCheckBox;
- checkbox.location = gfx::RectF(20, 50, 200, 30);
+ checkbox.relative_bounds.bounds = gfx::RectF(20, 50, 200, 30);
AXTreeUpdate initial_state;
initial_state.root_id = 1;
@@ -923,10 +923,10 @@ TEST(AXTreeTest, GetBoundsBasic) {
tree_update.root_id = 1;
tree_update.nodes.resize(2);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(100, 10, 400, 300);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(100, 10, 400, 300);
AXTree tree(tree_update);
EXPECT_EQ("(0, 0) size (800 x 600)", GetBoundsAsString(tree, 1));
@@ -940,16 +940,17 @@ TEST(AXTreeTest, EmptyNodeBoundsIsUnionOfChildren) {
tree_update.root_id = 1;
tree_update.nodes.resize(4);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(); // Deliberately empty.
+ tree_update.nodes[1].relative_bounds.bounds =
+ gfx::RectF(); // Deliberately empty.
tree_update.nodes[1].child_ids.push_back(3);
tree_update.nodes[1].child_ids.push_back(4);
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF(100, 10, 400, 20);
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(100, 10, 400, 20);
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].location = gfx::RectF(200, 30, 400, 20);
+ tree_update.nodes[3].relative_bounds.bounds = gfx::RectF(200, 30, 400, 20);
AXTree tree(tree_update);
EXPECT_EQ("(100, 10) size (500 x 40)", GetBoundsAsString(tree, 2));
@@ -962,20 +963,21 @@ TEST(AXTreeTest, EmptyNodeNotOffscreenEvenIfAllChildrenOffscreen) {
tree_update.root_id = 1;
tree_update.nodes.resize(4);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].role = ax::mojom::Role::kRootWebArea;
tree_update.nodes[0].AddBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, true);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(); // Deliberately empty.
+ tree_update.nodes[1].relative_bounds.bounds =
+ gfx::RectF(); // Deliberately empty.
tree_update.nodes[1].child_ids.push_back(3);
tree_update.nodes[1].child_ids.push_back(4);
// Both children are offscreen
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF(900, 10, 400, 20);
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(900, 10, 400, 20);
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].location = gfx::RectF(1000, 30, 400, 20);
+ tree_update.nodes[3].relative_bounds.bounds = gfx::RectF(1000, 30, 400, 20);
AXTree tree(tree_update);
EXPECT_FALSE(IsNodeOffscreen(tree, 2));
@@ -989,17 +991,17 @@ TEST(AXTreeTest, GetBoundsWithTransform) {
tree_update.root_id = 1;
tree_update.nodes.resize(3);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 400, 300);
- tree_update.nodes[0].transform.reset(new gfx::Transform());
- tree_update.nodes[0].transform->Scale(2.0, 2.0);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 400, 300);
+ tree_update.nodes[0].relative_bounds.transform.reset(new gfx::Transform());
+ tree_update.nodes[0].relative_bounds.transform->Scale(2.0, 2.0);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[0].child_ids.push_back(3);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(20, 10, 50, 5);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(20, 10, 50, 5);
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF(20, 30, 50, 5);
- tree_update.nodes[2].transform.reset(new gfx::Transform());
- tree_update.nodes[2].transform->Scale(2.0, 2.0);
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(20, 30, 50, 5);
+ tree_update.nodes[2].relative_bounds.transform.reset(new gfx::Transform());
+ tree_update.nodes[2].relative_bounds.transform->Scale(2.0, 2.0);
AXTree tree(tree_update);
EXPECT_EQ("(0, 0) size (800 x 600)", GetBoundsAsString(tree, 1));
@@ -1014,17 +1016,17 @@ TEST(AXTreeTest, GetBoundsWithContainerId) {
tree_update.root_id = 1;
tree_update.nodes.resize(4);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(100, 50, 600, 500);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(100, 50, 600, 500);
tree_update.nodes[1].child_ids.push_back(3);
tree_update.nodes[1].child_ids.push_back(4);
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].offset_container_id = 2;
- tree_update.nodes[2].location = gfx::RectF(20, 30, 50, 5);
+ tree_update.nodes[2].relative_bounds.offset_container_id = 2;
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(20, 30, 50, 5);
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].location = gfx::RectF(20, 30, 50, 5);
+ tree_update.nodes[3].relative_bounds.bounds = gfx::RectF(20, 30, 50, 5);
AXTree tree(tree_update);
EXPECT_EQ("(120, 80) size (50 x 5)", GetBoundsAsString(tree, 3));
@@ -1038,16 +1040,16 @@ TEST(AXTreeTest, GetBoundsWithScrolling) {
tree_update.root_id = 1;
tree_update.nodes.resize(3);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(100, 50, 600, 500);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(100, 50, 600, 500);
tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 5);
tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kScrollY, 10);
tree_update.nodes[1].child_ids.push_back(3);
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].offset_container_id = 2;
- tree_update.nodes[2].location = gfx::RectF(20, 30, 50, 5);
+ tree_update.nodes[2].relative_bounds.offset_container_id = 2;
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(20, 30, 50, 5);
AXTree tree(tree_update);
EXPECT_EQ("(115, 70) size (50 x 5)", GetBoundsAsString(tree, 3));
@@ -1058,15 +1060,15 @@ TEST(AXTreeTest, GetBoundsEmptyBoundsInheritsFromParent) {
tree_update.root_id = 1;
tree_update.nodes.resize(3);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[1].AddBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, true);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(300, 200, 100, 100);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(300, 200, 100, 100);
tree_update.nodes[1].child_ids.push_back(3);
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF();
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF();
AXTree tree(tree_update);
EXPECT_EQ("(0, 0) size (800 x 600)", GetBoundsAsString(tree, 1));
@@ -1085,7 +1087,7 @@ TEST(AXTreeTest, GetBoundsCropsChildToRoot) {
tree_update.root_id = 1;
tree_update.nodes.resize(5);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].AddBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, true);
tree_update.nodes[0].child_ids.push_back(2);
@@ -1094,16 +1096,17 @@ TEST(AXTreeTest, GetBoundsCropsChildToRoot) {
tree_update.nodes[0].child_ids.push_back(5);
// Cropped in the top left
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(-100, -100, 150, 150);
+ tree_update.nodes[1].relative_bounds.bounds =
+ gfx::RectF(-100, -100, 150, 150);
// Cropped in the bottom right
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF(700, 500, 150, 150);
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(700, 500, 150, 150);
// Offscreen on the top
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].location = gfx::RectF(50, -200, 150, 150);
+ tree_update.nodes[3].relative_bounds.bounds = gfx::RectF(50, -200, 150, 150);
// Offscreen on the bottom
tree_update.nodes[4].id = 5;
- tree_update.nodes[4].location = gfx::RectF(50, 700, 150, 150);
+ tree_update.nodes[4].relative_bounds.bounds = gfx::RectF(50, 700, 150, 150);
AXTree tree(tree_update);
EXPECT_EQ("(0, 0) size (50 x 50)", GetBoundsAsString(tree, 2));
@@ -1124,32 +1127,32 @@ TEST(AXTreeTest, GetBoundsSetsOffscreenIfClipsChildren) {
tree_update.root_id = 1;
tree_update.nodes.resize(5);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].AddBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, true);
tree_update.nodes[0].child_ids.push_back(2);
tree_update.nodes[0].child_ids.push_back(3);
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(0, 0, 200, 200);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(0, 0, 200, 200);
tree_update.nodes[1].AddBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, true);
tree_update.nodes[1].child_ids.push_back(4);
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF(0, 0, 200, 200);
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(0, 0, 200, 200);
tree_update.nodes[2].child_ids.push_back(5);
// Clipped by its parent
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].location = gfx::RectF(250, 250, 100, 100);
- tree_update.nodes[3].offset_container_id = 2;
+ tree_update.nodes[3].relative_bounds.bounds = gfx::RectF(250, 250, 100, 100);
+ tree_update.nodes[3].relative_bounds.offset_container_id = 2;
// Outside of its parent, but its parent does not clip children,
// so it should not be offscreen.
tree_update.nodes[4].id = 5;
- tree_update.nodes[4].location = gfx::RectF(250, 250, 100, 100);
- tree_update.nodes[4].offset_container_id = 3;
+ tree_update.nodes[4].relative_bounds.bounds = gfx::RectF(250, 250, 100, 100);
+ tree_update.nodes[4].relative_bounds.offset_container_id = 3;
AXTree tree(tree_update);
EXPECT_TRUE(IsNodeOffscreen(tree, 4));
@@ -1161,7 +1164,7 @@ TEST(AXTreeTest, GetBoundsUpdatesOffscreen) {
tree_update.root_id = 1;
tree_update.nodes.resize(5);
tree_update.nodes[0].id = 1;
- tree_update.nodes[0].location = gfx::RectF(0, 0, 800, 600);
+ tree_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
tree_update.nodes[0].role = ax::mojom::Role::kRootWebArea;
tree_update.nodes[0].AddBoolAttribute(
ax::mojom::BoolAttribute::kClipsChildren, true);
@@ -1171,16 +1174,16 @@ TEST(AXTreeTest, GetBoundsUpdatesOffscreen) {
tree_update.nodes[0].child_ids.push_back(5);
// Fully onscreen
tree_update.nodes[1].id = 2;
- tree_update.nodes[1].location = gfx::RectF(10, 10, 150, 150);
+ tree_update.nodes[1].relative_bounds.bounds = gfx::RectF(10, 10, 150, 150);
// Cropped in the bottom right
tree_update.nodes[2].id = 3;
- tree_update.nodes[2].location = gfx::RectF(700, 500, 150, 150);
+ tree_update.nodes[2].relative_bounds.bounds = gfx::RectF(700, 500, 150, 150);
// Offscreen on the top
tree_update.nodes[3].id = 4;
- tree_update.nodes[3].location = gfx::RectF(50, -200, 150, 150);
+ tree_update.nodes[3].relative_bounds.bounds = gfx::RectF(50, -200, 150, 150);
// Offscreen on the bottom
tree_update.nodes[4].id = 5;
- tree_update.nodes[4].location = gfx::RectF(50, 700, 150, 150);
+ tree_update.nodes[4].relative_bounds.bounds = gfx::RectF(50, 700, 150, 150);
AXTree tree(tree_update);
EXPECT_FALSE(IsNodeOffscreen(tree, 2));
@@ -1469,4 +1472,400 @@ TEST(AXTreeTest, ChildTreeIds) {
EXPECT_EQ(0U, child_tree_93_nodes.size());
}
+// Tests PosInSet and SetSize int attributes work if assigned.
+TEST(AXTreeTest, TestSetSizePosInSetAssigned) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 2);
+ tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 12);
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 5);
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 12);
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 9);
+ tree_update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 12);
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 2);
+ EXPECT_EQ(item1->GetSetSize(), 12);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 5);
+ EXPECT_EQ(item2->GetSetSize(), 12);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 9);
+ EXPECT_EQ(item3->GetSetSize(), 12);
+}
+
+// Tests that PosInSet and SetSize can be calculated if not assigned.
+TEST(AXTreeTest, TestSetSizePosInSetUnassigned) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem;
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 3);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 2);
+ EXPECT_EQ(item2->GetSetSize(), 3);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 3);
+ EXPECT_EQ(item3->GetSetSize(), 3);
+}
+
+// Tests PosInSet unassigned, while SetSize assigned in container.
+TEST(AXTreeTest, TestSetSizeAssignedInContainer) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 7);
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem;
+ AXTree tree(tree_update);
+
+ // Items should inherit SetSize from container if not specified.
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetSetSize(), 7);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetSetSize(), 7);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetSetSize(), 7);
+}
+
+// Tests PosInSet and SetSize on a list containing various roles.
+// Roles for items and associated container should match up.
+TEST(AXTreeTest, TestSetSizePosInSetDiverseList) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(9);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4, 5, 6, 7, 8, 9};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 3
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kMenuItem; // 0 of 0
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 2 of 3
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kMenuItem; // 0 of 0
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kArticle; // 0 of 0
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].role = ax::mojom::Role::kArticle; // 0 of 0
+ tree_update.nodes[7].id = 8;
+ tree_update.nodes[7].role = ax::mojom::Role::kListItem; // 3 of 3
+ tree_update.nodes[8].id = 9;
+ tree_update.nodes[8].role = ax::mojom::Role::kImage; // 0 of 0
+ AXTree tree(tree_update);
+
+ AXNode* listitem1 = tree.GetFromId(2);
+ EXPECT_EQ(listitem1->GetPosInSet(), 1);
+ EXPECT_EQ(listitem1->GetSetSize(), 3);
+ AXNode* menuitem1 = tree.GetFromId(3);
+ EXPECT_EQ(menuitem1->GetPosInSet(), 0);
+ EXPECT_EQ(menuitem1->GetSetSize(), 0);
+ AXNode* listitem2 = tree.GetFromId(4);
+ EXPECT_EQ(listitem2->GetPosInSet(), 2);
+ EXPECT_EQ(listitem2->GetSetSize(), 3);
+ AXNode* menuitem2 = tree.GetFromId(5);
+ EXPECT_EQ(menuitem2->GetPosInSet(), 0);
+ EXPECT_EQ(menuitem2->GetSetSize(), 0);
+ AXNode* article1 = tree.GetFromId(6);
+ EXPECT_EQ(article1->GetPosInSet(), 0);
+ EXPECT_EQ(article1->GetSetSize(), 0);
+ AXNode* article2 = tree.GetFromId(7);
+ EXPECT_EQ(article2->GetPosInSet(), 0);
+ EXPECT_EQ(article2->GetSetSize(), 0);
+ AXNode* listitem3 = tree.GetFromId(8);
+ EXPECT_EQ(listitem3->GetPosInSet(), 3);
+ EXPECT_EQ(listitem3->GetSetSize(), 3);
+ AXNode* image = tree.GetFromId(9);
+ EXPECT_EQ(image->GetPosInSet(), 0);
+ EXPECT_EQ(image->GetSetSize(), 0);
+}
+
+// Tests PosInSet and SetSize on a nested list.
+TEST(AXTreeTest, TestSetSizePosInSetNestedList) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(7);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4, 7};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kList;
+ tree_update.nodes[3].child_ids = {5, 6};
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].role = ax::mojom::Role::kListItem;
+ AXTree tree(tree_update);
+
+ AXNode* outer_item1 = tree.GetFromId(2);
+ EXPECT_EQ(outer_item1->GetPosInSet(), 1);
+ EXPECT_EQ(outer_item1->GetSetSize(), 3);
+ AXNode* outer_item2 = tree.GetFromId(3);
+ EXPECT_EQ(outer_item2->GetPosInSet(), 2);
+ EXPECT_EQ(outer_item2->GetSetSize(), 3);
+
+ // List object itself should not report posinset or setsize.
+ // TODO (akihiroota): Lists should report setsize in the future.
+ AXNode* inner_list = tree.GetFromId(4);
+ EXPECT_EQ(inner_list->GetPosInSet(), 0);
+ EXPECT_EQ(inner_list->GetSetSize(), 0);
+
+ AXNode* inner_item1 = tree.GetFromId(5);
+ EXPECT_EQ(inner_item1->GetPosInSet(), 1);
+ EXPECT_EQ(inner_item1->GetSetSize(), 2);
+ AXNode* inner_item2 = tree.GetFromId(6);
+ EXPECT_EQ(inner_item2->GetPosInSet(), 2);
+ EXPECT_EQ(inner_item2->GetSetSize(), 2);
+
+ AXNode* outer_item3 = tree.GetFromId(7);
+ EXPECT_EQ(outer_item3->GetPosInSet(), 3);
+ EXPECT_EQ(outer_item3->GetSetSize(), 3);
+}
+
+// Tests PosInSet can be calculated if one item specifies PosInSet, but others
+// are missing.
+TEST(AXTreeTest, TestPosInSetMissing) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 20);
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 13);
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem;
+ AXTree tree(tree_update);
+
+ // Item1 should have pos of 12, since item2 is assigned a pos of 13.
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 20);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 13);
+ EXPECT_EQ(item2->GetSetSize(), 20);
+ // Item2 should have pos of 14, since item2 is assigned a pos of 13.
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 14);
+ EXPECT_EQ(item3->GetSetSize(), 20);
+}
+
+// A more difficult test that invovles missing PosInSet and SetSize values.
+TEST(AXTreeTest, TestSetSizePosInSetMissingDifficult) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(6);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4, 5, 6};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 11
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
+ 5); // 5 of 11
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 6 of 11
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kListItem;
+ tree_update.nodes[4].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
+ 10); // 10 of 11
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kListItem; // 11 of 11
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 11);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 5);
+ EXPECT_EQ(item2->GetSetSize(), 11);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 6);
+ EXPECT_EQ(item3->GetSetSize(), 11);
+ AXNode* item4 = tree.GetFromId(5);
+ EXPECT_EQ(item4->GetPosInSet(), 10);
+ EXPECT_EQ(item4->GetSetSize(), 11);
+ AXNode* item5 = tree.GetFromId(6);
+ EXPECT_EQ(item5->GetPosInSet(), 11);
+ EXPECT_EQ(item5->GetSetSize(), 11);
+}
+
+// Tests that code overwrites decreasing SetSize assignments to largest of
+// assigned values.
+TEST(AXTreeTest, TestSetSizeDecreasing) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 5
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem; // 2 of 5
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 5);
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 3 of 5
+ tree_update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kSetSize, 4);
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 5);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 2);
+ EXPECT_EQ(item2->GetSetSize(), 5);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 3);
+ EXPECT_EQ(item3->GetSetSize(), 5);
+}
+
+// Tests that code overwrites decreasing PosInSet values.
+TEST(AXTreeTest, TestPosInSetDecreasing) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 8
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem; // 7 of 8
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 7);
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 8 of 8
+ tree_update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 3);
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 8);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 7);
+ EXPECT_EQ(item2->GetSetSize(), 8);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 8);
+ EXPECT_EQ(item3->GetSetSize(), 8);
+}
+
+// Tests that code overwrites duplicate PosInSet values. Note this case is
+// tricky; an update to the second element causes an update to the third
+// element.
+TEST(AXTreeTest, TestPosInSetDuplicates) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(4);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 4};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem; // 6 of 8
+ tree_update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 6);
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kListItem; // 7 of 8
+ tree_update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 6);
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 8 of 8
+ tree_update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 7);
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 6);
+ EXPECT_EQ(item1->GetSetSize(), 8);
+ AXNode* item2 = tree.GetFromId(3);
+ EXPECT_EQ(item2->GetPosInSet(), 7);
+ EXPECT_EQ(item2->GetSetSize(), 8);
+ AXNode* item3 = tree.GetFromId(4);
+ EXPECT_EQ(item3->GetPosInSet(), 8);
+ EXPECT_EQ(item3->GetSetSize(), 8);
+}
+
+// Tests PosInSet and SetSize when some list items are nested in a generic
+// container.
+TEST(AXTreeTest, TestSetSizePosInSetNestedContainer) {
+ AXTreeUpdate tree_update;
+ tree_update.root_id = 1;
+ tree_update.nodes.resize(7);
+ tree_update.nodes[0].id = 1;
+ tree_update.nodes[0].role = ax::mojom::Role::kList;
+ tree_update.nodes[0].child_ids = {2, 3, 7};
+ tree_update.nodes[1].id = 2;
+ tree_update.nodes[1].role = ax::mojom::Role::kListItem; // 1 of 4
+ tree_update.nodes[2].id = 3;
+ tree_update.nodes[2].role = ax::mojom::Role::kGenericContainer;
+ tree_update.nodes[2].child_ids = {4, 5};
+ tree_update.nodes[3].id = 4;
+ tree_update.nodes[3].role = ax::mojom::Role::kListItem; // 2 of 4
+ tree_update.nodes[4].id = 5;
+ tree_update.nodes[4].role = ax::mojom::Role::kIgnored;
+ tree_update.nodes[4].child_ids = {6};
+ tree_update.nodes[5].id = 6;
+ tree_update.nodes[5].role = ax::mojom::Role::kListItem; // 3 of 4
+ tree_update.nodes[6].id = 7;
+ tree_update.nodes[6].role = ax::mojom::Role::kListItem; // 4 of 4
+ AXTree tree(tree_update);
+
+ AXNode* item1 = tree.GetFromId(2);
+ EXPECT_EQ(item1->GetPosInSet(), 1);
+ EXPECT_EQ(item1->GetSetSize(), 4);
+ AXNode* g_container = tree.GetFromId(3);
+ EXPECT_EQ(g_container->GetPosInSet(), 0);
+ EXPECT_EQ(g_container->GetSetSize(), 0);
+ AXNode* item2 = tree.GetFromId(4);
+ EXPECT_EQ(item2->GetPosInSet(), 2);
+ EXPECT_EQ(item2->GetSetSize(), 4);
+ AXNode* ignored = tree.GetFromId(5);
+ EXPECT_EQ(ignored->GetPosInSet(), 0);
+ EXPECT_EQ(ignored->GetSetSize(), 0);
+ AXNode* item3 = tree.GetFromId(6);
+ EXPECT_EQ(item3->GetPosInSet(), 3);
+ EXPECT_EQ(item3->GetSetSize(), 4);
+ AXNode* item4 = tree.GetFromId(7);
+ EXPECT_EQ(item4->GetPosInSet(), 4);
+ EXPECT_EQ(item4->GetSetSize(), 4);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb
index 597f120249d..a816afcfad0 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_bn.xtb
@@ -18,7 +18,7 @@
<translation id="2648340354586434750">শব্দগুলির দ্বারা সরাতে &lt;span class='key'&gt;বিকল্প&lt;/span&gt; টিপে ধরে রাখুন৷</translation>
<translation id="2795227192542594043">এই এক্সটেনশনটি আপনাকে ওয়েব পৃষ্ঠাটির উপর একটি কার্সার দেয়, আপনাকে কীবোর্ড দিয়ে টেক্সট নির্বাচন করতে দেয়৷</translation>
<translation id="2808027189040546825">পদক্ষেপ ১: ক্ষীণতম তারকা সহ সারিটি বেছে নিন:</translation>
-<translation id="2965611304828530558">&lt;p&gt;যখন আপনি কোনো লিঙ্ক অ্যাক্সেস করেন বা নিয়ন্ত্রণ করেন, তখন এটি স্বয়ংক্রিয়ভাবে ফোকাস করবে৷ কোনো লিঙ্ক বা বোতামে ক্লিক করতে &lt;span class='key'&gt;Enter&lt;/span&gt; টিপুন৷ &lt;/p&gt; &lt;p&gt; যখন কোনো ফোকাস করা নিয়ন্ত্রণ (কোনো পাঠ্য বক্স বা তালিকা বক্স) নির্দেশক তীরচিহ্নগুলি ক্যাপচার করে, তখন ক্যারেট ব্রাউজিং করা চালিয়ে যেতে বাঁ বা ডান তীর অনুসরণ করে &lt;span class='key'&gt;Esc&lt;/span&gt; টিপুন৷ &lt;/p&gt; &lt;p&gt; অন্যথা, পরবর্তী ফোকাসযোগ্য নিয়ন্ত্রণে সরে যেতে &lt;span class='key'&gt;Tab&lt;/span&gt; টিপুন৷ &lt;/p&gt;</translation>
+<translation id="2965611304828530558">&lt;p&gt;যখন আপনি কোনও লিঙ্ক অ্যাক্সেস করেন বা নিয়ন্ত্রণ করেন, তখন এটি অটোমেটিক ফোকাস করবে৷ কোনও লিঙ্ক বা বোতামে ক্লিক করতে &lt;span class='key'&gt;Enter&lt;/span&gt; টিপুন৷ &lt;/p&gt; &lt;p&gt; যখন কোনও ফোকাস করা নিয়ন্ত্রণ (কোনও টেক্সট বক্স বা তালিকা বক্স) নির্দেশক তীরচিহ্নগুলি ক্যাপচার করে, তখন ক্যারেট ব্রাউজিং করা চালিয়ে যেতে বাম বা ডান তীর অনুসরণ করে &lt;span class='key'&gt;Esc&lt;/span&gt; টিপুন৷ &lt;/p&gt; &lt;p&gt; না হলে, পরবর্তী ফোকাস করা যায় এমন নিয়ন্ত্রণে সরে যেতে &lt;span class='key'&gt;Tab&lt;/span&gt; টিপুন৷ &lt;/p&gt;</translation>
<translation id="3252573918265662711">সেটআপ</translation>
<translation id="3410969471888629217">সাইট কাস্টমাইজেশনগুলি মুছুন</translation>
<translation id="3435896845095436175">সক্ষম করুন</translation>
diff --git a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb
index a3f0749949d..4327852e622 100644
--- a/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb
+++ b/chromium/ui/accessibility/extensions/strings/accessibility_extensions_strings_te.xtb
@@ -12,19 +12,19 @@
<translation id="1996252509865389616">ప్రారంభించాలా?</translation>
<translation id="2079545284768500474">చర్య రద్దు</translation>
<translation id="2179565792157161713">సుదీర్ఘ వివరణను కొత్త ట్యాబ్‌లో తెరువు</translation>
-<translation id="2223143012868735942">రంగు గ్రాహ్యతను మెరుగుపరచడానికి అనుకూలీకృత రంగు ఫిల్టర్ వెబ్‌పేజీలకు వర్తింపజేయబడింది.</translation>
+<translation id="2223143012868735942">రంగు గ్రాహ్యతను మెరుగుపరచడానికి, అనుకూలీకరించగల రంగు ఫిల్టర్ వెబ్‌పేజీలకు వర్తింపజేయబడింది.</translation>
<translation id="2394933097471027016">ఇప్పుడే దీన్ని ప్రయత్నించండి - కేరెట్ బ్రౌజింగ్ ఈ పేజీలో ఎల్లప్పుడూ ప్రారంభించబడి ఉంటుంది!</translation>
<translation id="2471847333270902538"><ph name="SITE" /> కోసం రంగు స్కీమ్:</translation>
<translation id="2648340354586434750">పదాల వారీగా తరలించడానికి &lt;span class='key'&gt;Option&lt;/span&gt;ని నొక్కి పట్టుకోండి.</translation>
<translation id="2795227192542594043">ఈ పొడిగింపు మీకు వెబ్ పేజీలో తరలించదగిన కర్సర్‌ను అందిస్తుంది, కీబోర్డ్‌తో వచనాన్ని ఎంచుకోవడానికి మిమ్మల్ని అనుమతిస్తుంది.</translation>
<translation id="2808027189040546825">దశ 1: మిరుమిట్లు గొలిపే నక్షత్రాలు గల అడ్డు వరుసను ఎంచుకోండి:</translation>
-<translation id="2965611304828530558">&lt;p&gt;మీరు లింక్ లేదా నియంత్రణ వద్ద ఉంటే, స్వయంచాలకంగా దానిపై దృష్టి కేంద్రీకరించబడుతుంది. లింక్ లేదా బటన్‌ను క్లిక్ చేయడానికి &lt;span class='key'&gt;Enter&lt;/span&gt; నొక్కండి. &lt;/p&gt; &lt;p&gt; దృష్టి కేంద్రీకృత నియంత్రణ (వచన పెట్టె లేదా జాబితా పెట్టె వంటిది) బాణం కీలను క్యాప్చర్ చేస్తున్నప్పుడు, కేరెట్ బ్రౌజింగ్‌ను కొనసాగించడానికి &lt;span class='key'&gt;Esc&lt;/span&gt; నొక్కి, ఆపై ఎడమ లేదా కుడి బాణం నొక్కండి. &lt;/p&gt; &lt;p&gt; ప్రత్యామ్నాయంగా, తదుపరి దృష్టి కేంద్రీకృత నియంత్రణకు తరలించడానికి &lt;span class='key'&gt;Tab&lt;/span&gt; నొక్కండి. &lt;/p&gt;</translation>
+<translation id="2965611304828530558">&lt;p&gt;మీరు లింక్ లేదా నియంత్రణ వద్ద ఉంటే, ఆటోమేటిక్‌గా దానిపై దృష్టి కేంద్రీకరించబడుతుంది. లింక్ లేదా బటన్‌ను క్లిక్ చేయడానికి &lt;span class='key'&gt;Enter&lt;/span&gt; నొక్కండి. &lt;/p&gt; &lt;p&gt; దృష్టి కేంద్రీకృత నియంత్రణ (వచన బాక్స్‌ లేదా జాబితా బాక్స్‌ వంటిది) బాణం కీలను క్యాప్చర్ చేస్తున్నప్పుడు, కేరెట్ బ్రౌజింగ్‌ను కొనసాగించడానికి &lt;span class='key'&gt;Esc&lt;/span&gt; నొక్కి, ఆపై ఎడమ లేదా కుడి బాణం నొక్కండి. &lt;/p&gt; &lt;p&gt; ప్రత్యామ్నాయంగా, తదుపరి దృష్టి కేంద్రీకృత నియంత్రణకు తరలించడానికి &lt;span class='key'&gt;Tab&lt;/span&gt; నొక్కండి. &lt;/p&gt;</translation>
<translation id="3252573918265662711">సెటప్ చేయి</translation>
<translation id="3410969471888629217">సైట్ అనుకూలీకరణలను విస్మరించు</translation>
<translation id="3435896845095436175">ప్రారంభించండి</translation>
<translation id="3622586652998721735">డిఫాల్ట్ స్కీమ్‌గా సెట్ చేయి</translation>
-<translation id="3812541808639806898">చిత్రం Alt వచన వ్యూయర్</translation>
-<translation id="381767806621926835">"longdesc" లేదా "aria-describedat" లక్షణం ఉన్న ఏదైనా అంశం యొక్క సుదీర్ఘ వివరణను ప్రాప్యత చేయడానికి దానిపై కుడి క్లిక్ చేయండి.</translation>
+<translation id="3812541808639806898">చిత్రం ప్రత్యామ్నాయ వచన వ్యూయర్</translation>
+<translation id="381767806621926835">"longdesc" లేదా "aria-describedat" లక్షణం ఉన్న ఏదైనా అంశం యొక్క సుదీర్ఘ వివరణను యాక్సెస్ చేయడానికి దానిపై కుడి క్లిక్ చేయండి.</translation>
<translation id="4023902424053835668">బాణం కీలను ఉపయోగించి వెబ్ పేజీల వచనాన్ని బ్రౌజ్ చేయండి.</translation>
<translation id="4388820049312272371">కర్సర్ స్థానాన్ని శీఘ్ర ఫ్లాష్‌తో హైలైట్ చేయండి.</translation>
<translation id="4394049700291259645">ఆపివెయ్యి</translation>
@@ -57,13 +57,13 @@
<translation id="7384431257964758081">అధిక కాంట్రాస్ట్ ప్రారంభించబడింది</translation>
<translation id="7586636300921797327">దశ 2: ఎంచుకున్న అడ్డు వరుసలో అన్ని నక్షత్రాలు కనిపించే విధంగా స్లయిడర్‌ను
సర్దుబాటు చేయండి</translation>
-<translation id="7658239707568436148">రద్దు చెయ్యి</translation>
-<translation id="786423340267544509">aria-describedat లేదా longdesc లక్షణాలు ఉన్న మూలకాలకు హద్దును జోడిస్తుంది.</translation>
+<translation id="7658239707568436148">రద్దు చేయి</translation>
+<translation id="786423340267544509">aria-describedat లేదా longdesc ఫీచర్‌లు ఉన్న మూలకాలకు హద్దును జోడించు.</translation>
<translation id="7942349550061667556">ఎరుపు</translation>
<translation id="8254860724243898966">కేరెట్ బ్రౌజింగ్‌ను ఆన్ చేయడానికి &lt;span class='key'&gt;Alt&lt;/span&gt; + &lt;img src='increase_brightness.png'&gt; (Increase Brightness కీ లేదా F7) నొక్కండి. అలాగే ఆఫ్ చేయడానికి దాన్నే మళ్లీ నొక్కండి.</translation>
<translation id="8260673944985561857">కేరెట్ బ్రౌజింగ్ ఎంపికలు</translation>
<translation id="8321034316479930120">యానిమేషన్ విధానం</translation>
<translation id="8480209185614411573">అధిక కాంట్రాస్ట్</translation>
<translation id="8609925175482059018">కేరెట్ బ్రౌజింగ్‌ను ఆన్ చేయడానికి &lt;span class='key'&gt;F7&lt;/span&gt; నొక్కండి. అలాగే ఆఫ్ చేయడానికి దాన్నే మళ్లీ నొక్కండి.</translation>
-<translation id="894241283505723656">సందర్భ మెనులో సుదీర్ఘ వివరణలు</translation>
+<translation id="894241283505723656">సందర్భోచిత మెనూలో సుదీర్ఘ వివరణలు</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/ui/accessibility/fuzz_corpus/ax_table_fuzzer_seed.bin b/chromium/ui/accessibility/fuzz_corpus/ax_table_fuzzer_seed.bin
new file mode 100644
index 00000000000..5befdf2457f
--- /dev/null
+++ b/chromium/ui/accessibility/fuzz_corpus/ax_table_fuzzer_seed.bin
Binary files differ
diff --git a/chromium/ui/accessibility/mojom/BUILD.gn b/chromium/ui/accessibility/mojom/BUILD.gn
index ac10ca35074..65d4a61033e 100644
--- a/chromium/ui/accessibility/mojom/BUILD.gn
+++ b/chromium/ui/accessibility/mojom/BUILD.gn
@@ -11,6 +11,7 @@ mojom("mojom") {
"ax_event.mojom",
"ax_host.mojom",
"ax_node_data.mojom",
+ "ax_relative_bounds.mojom",
"ax_tree_data.mojom",
"ax_tree_id.mojom",
"ax_tree_update.mojom",
diff --git a/chromium/ui/accessibility/mojom/ax_node_data.mojom b/chromium/ui/accessibility/mojom/ax_node_data.mojom
index bbaef03c247..bb15b5ff407 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data.mojom
+++ b/chromium/ui/accessibility/mojom/ax_node_data.mojom
@@ -5,8 +5,7 @@
module ax.mojom;
import "ui/accessibility/ax_enums.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-import "ui/gfx/mojo/transform.mojom";
+import "ui/accessibility/mojom/ax_relative_bounds.mojom";
// See ui::AXNodeData for comments / explanations of these fields.
struct AXNodeData {
@@ -24,7 +23,5 @@ struct AXNodeData {
stringlist_attributes;
map<string, string> html_attributes;
array<int32> child_ids;
- int32 offset_container_id;
- gfx.mojom.RectF location;
- gfx.mojom.Transform transform;
+ ax.mojom.AXRelativeBounds relative_bounds;
};
diff --git a/chromium/ui/accessibility/mojom/ax_node_data.typemap b/chromium/ui/accessibility/mojom/ax_node_data.typemap
index 4a36ac29159..1d266cfd301 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data.typemap
+++ b/chromium/ui/accessibility/mojom/ax_node_data.typemap
@@ -11,9 +11,5 @@ sources = [
]
public_deps = [
"//ui/accessibility",
- "//ui/gfx",
- "//ui/gfx/geometry/mojo",
- "//ui/gfx/geometry/mojo:struct_traits",
- "//ui/gfx/mojo",
]
type_mappings = [ "ax.mojom.AXNodeData=ui::AXNodeData" ]
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
index 22873c6b4be..f8c84a97b1d 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "ui/accessibility/mojom/ax_node_data_mojom_traits.h"
+#include "ui/accessibility/mojom/ax_relative_bounds.mojom-shared.h"
+#include "ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h"
namespace mojo {
@@ -78,16 +80,6 @@ StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::html_attributes(
}
// static
-gfx::Transform
-StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::transform(
- const ui::AXNodeData& p) {
- if (p.transform)
- return *p.transform;
- else
- return gfx::Transform();
-}
-
-// static
bool StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::Read(
ax::mojom::AXNodeDataDataView data,
ui::AXNodeData* out) {
@@ -143,16 +135,8 @@ bool StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::Read(
if (!data.ReadChildIds(&out->child_ids))
return false;
- out->offset_container_id = data.offset_container_id();
-
- if (!data.ReadLocation(&out->location))
- return false;
-
- gfx::Transform transform;
- if (!data.ReadTransform(&transform))
+ if (!data.ReadRelativeBounds(&out->relative_bounds))
return false;
- if (!transform.IsIdentity())
- out->transform.reset(new gfx::Transform(transform));
return true;
}
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
index 22c44e975de..6dee8a691d6 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits.h
@@ -6,10 +6,8 @@
#define UI_ACCESSIBILITY_MOJOM_AX_NODE_DATA_MOJOM_TRAITS_H_
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_relative_bounds.h"
#include "ui/accessibility/mojom/ax_node_data.mojom-shared.h"
-#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
-#include "ui/gfx/mojo/transform.mojom.h"
-#include "ui/gfx/mojo/transform_struct_traits.h"
namespace mojo {
@@ -37,11 +35,9 @@ struct StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData> {
static std::vector<int32_t> child_ids(const ui::AXNodeData& p) {
return p.child_ids;
}
- static int32_t offset_container_id(const ui::AXNodeData& p) {
- return p.offset_container_id;
+ static ui::AXRelativeBounds relative_bounds(const ui::AXNodeData& p) {
+ return p.relative_bounds;
}
- static gfx::RectF location(const ui::AXNodeData& p) { return p.location; }
- static gfx::Transform transform(const ui::AXNodeData& p);
static bool Read(ax::mojom::AXNodeDataDataView data, ui::AXNodeData* out);
};
diff --git a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
index 2e25fdda961..d181737b140 100644
--- a/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_node_data_mojom_traits_unittest.cc
@@ -7,6 +7,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/mojom/ax_node_data.mojom.h"
+#include "ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h"
using mojo::test::SerializeAndDeserialize;
@@ -106,29 +107,29 @@ TEST(AXNodeDataMojomTraitsTest, ChildIds) {
TEST(AXNodeDataMojomTraitsTest, OffsetContainerID) {
ui::AXNodeData input, output;
- input.offset_container_id = 10;
+ input.relative_bounds.offset_container_id = 10;
EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
- EXPECT_EQ(10, output.offset_container_id);
+ EXPECT_EQ(10, output.relative_bounds.offset_container_id);
}
-TEST(AXNodeDataMojomTraitsTest, Location) {
+TEST(AXNodeDataMojomTraitsTest, RelativeBounds) {
ui::AXNodeData input, output;
- input.location = gfx::RectF(1, 2, 3, 4);
+ input.relative_bounds.bounds = gfx::RectF(1, 2, 3, 4);
EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
- EXPECT_EQ(1, output.location.x());
- EXPECT_EQ(2, output.location.y());
- EXPECT_EQ(3, output.location.width());
- EXPECT_EQ(4, output.location.height());
+ EXPECT_EQ(1, output.relative_bounds.bounds.x());
+ EXPECT_EQ(2, output.relative_bounds.bounds.y());
+ EXPECT_EQ(3, output.relative_bounds.bounds.width());
+ EXPECT_EQ(4, output.relative_bounds.bounds.height());
}
TEST(AXNodeDataMojomTraitsTest, Transform) {
ui::AXNodeData input, output;
EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
- EXPECT_FALSE(output.transform);
+ EXPECT_FALSE(output.relative_bounds.transform);
- input.transform = std::make_unique<gfx::Transform>();
- input.transform->Scale(2.0, 2.0);
+ input.relative_bounds.transform = std::make_unique<gfx::Transform>();
+ input.relative_bounds.transform->Scale(2.0, 2.0);
EXPECT_TRUE(SerializeAndDeserialize<ax::mojom::AXNodeData>(&input, &output));
- EXPECT_TRUE(output.transform);
- EXPECT_FALSE(output.transform->IsIdentity());
+ EXPECT_TRUE(output.relative_bounds.transform);
+ EXPECT_FALSE(output.relative_bounds.transform->IsIdentity());
}
diff --git a/chromium/ui/accessibility/mojom/ax_relative_bounds.mojom b/chromium/ui/accessibility/mojom/ax_relative_bounds.mojom
new file mode 100644
index 00000000000..52b622538c8
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_relative_bounds.mojom
@@ -0,0 +1,15 @@
+// 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.
+
+module ax.mojom;
+
+import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/mojo/transform.mojom";
+
+// See ui::RelativeBounds for documentation.
+struct AXRelativeBounds {
+ int32 offset_container_id;
+ gfx.mojom.RectF bounds;
+ gfx.mojom.Transform transform;
+};
diff --git a/chromium/ui/accessibility/mojom/ax_relative_bounds.typemap b/chromium/ui/accessibility/mojom/ax_relative_bounds.typemap
new file mode 100644
index 00000000000..ccdf2b90081
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_relative_bounds.typemap
@@ -0,0 +1,19 @@
+# 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.
+
+mojom = "//ui/accessibility/mojom/ax_relative_bounds.mojom"
+public_headers = [ "//ui/accessibility/ax_relative_bounds.h" ]
+traits_headers =
+ [ "//ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h" ]
+sources = [
+ "ax_relative_bounds_mojom_traits.cc",
+ "ax_relative_bounds_mojom_traits.h",
+]
+public_deps = [
+ "//ui/gfx",
+ "//ui/gfx/geometry/mojo",
+ "//ui/gfx/geometry/mojo:struct_traits",
+ "//ui/gfx/mojo",
+]
+type_mappings = [ "ax.mojom.AXRelativeBounds=ui::AXRelativeBounds" ]
diff --git a/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.cc b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.cc
new file mode 100644
index 00000000000..27effb18fa6
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.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/accessibility/mojom/ax_relative_bounds_mojom_traits.h"
+
+namespace mojo {
+
+// static
+gfx::Transform
+StructTraits<ax::mojom::AXRelativeBoundsDataView,
+ ui::AXRelativeBounds>::transform(const ui::AXRelativeBounds& p) {
+ if (p.transform)
+ return *p.transform;
+ else
+ return gfx::Transform();
+}
+
+// static
+bool StructTraits<ax::mojom::AXRelativeBoundsDataView, ui::AXRelativeBounds>::
+ Read(ax::mojom::AXRelativeBoundsDataView data, ui::AXRelativeBounds* out) {
+ out->offset_container_id = data.offset_container_id();
+
+ gfx::Transform transform;
+ if (!data.ReadTransform(&transform))
+ return false;
+ if (!transform.IsIdentity())
+ out->transform.reset(new gfx::Transform(transform));
+
+ if (!data.ReadBounds(&out->bounds))
+ return false;
+
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h
new file mode 100644
index 00000000000..3752c95d593
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCESSIBILITY_MOJOM_AX_RELATIVE_BOUNDS_MOJOM_TRAITS_H_
+#define UI_ACCESSIBILITY_MOJOM_AX_RELATIVE_BOUNDS_MOJOM_TRAITS_H_
+
+#include "ui/accessibility/ax_relative_bounds.h"
+#include "ui/accessibility/mojom/ax_relative_bounds.mojom-shared.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/mojo/transform.mojom.h"
+#include "ui/gfx/mojo/transform_struct_traits.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<ax::mojom::AXRelativeBoundsDataView, ui::AXRelativeBounds> {
+ static int32_t offset_container_id(const ui::AXRelativeBounds& p) {
+ return p.offset_container_id;
+ }
+
+ static gfx::RectF bounds(const ui::AXRelativeBounds& p) { return p.bounds; }
+
+ static gfx::Transform transform(const ui::AXRelativeBounds& p);
+
+ static bool Read(ax::mojom::AXRelativeBoundsDataView data,
+ ui::AXRelativeBounds* out);
+};
+
+} // namespace mojo
+
+#endif // UI_ACCESSIBILITY_MOJOM_AX_RELATIVE_BOUNDS_MOJOM_TRAITS_H_
diff --git a/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc
new file mode 100644
index 00000000000..761c6439f2a
--- /dev/null
+++ b/chromium/ui/accessibility/mojom/ax_relative_bounds_mojom_traits_unittest.cc
@@ -0,0 +1,30 @@
+// 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/accessibility/mojom/ax_relative_bounds_mojom_traits.h"
+
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_relative_bounds.h"
+#include "ui/accessibility/mojom/ax_relative_bounds.mojom.h"
+
+using mojo::test::SerializeAndDeserialize;
+
+TEST(AXRelativeBoundsMojomTraitsTest, RoundTrip) {
+ ui::AXRelativeBounds input;
+ input.offset_container_id = 111;
+ input.bounds = gfx::RectF(1, 2, 3, 4);
+ input.transform = std::make_unique<gfx::Transform>();
+ input.transform->Scale(1.0, 2.0);
+
+ ui::AXRelativeBounds output;
+ EXPECT_TRUE(
+ SerializeAndDeserialize<ax::mojom::AXRelativeBounds>(&input, &output));
+ EXPECT_EQ(111, output.offset_container_id);
+ EXPECT_EQ(1, output.bounds.x());
+ EXPECT_EQ(2, output.bounds.y());
+ EXPECT_EQ(3, output.bounds.width());
+ EXPECT_EQ(4, output.bounds.height());
+ EXPECT_FALSE(output.transform->IsIdentity());
+}
diff --git a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
index 53dbf6d23f0..18a83b49bc2 100644
--- a/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
+++ b/chromium/ui/accessibility/mojom/ax_tree_update_mojom_traits_unittest.cc
@@ -6,6 +6,7 @@
#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_tree_update.h"
+#include "ui/accessibility/mojom/ax_relative_bounds_mojom_traits.h"
#include "ui/accessibility/mojom/ax_tree_update.mojom.h"
using mojo::test::SerializeAndDeserialize;
diff --git a/chromium/ui/accessibility/mojom/typemaps.gni b/chromium/ui/accessibility/mojom/typemaps.gni
index ba8b1e10e01..6095574abeb 100644
--- a/chromium/ui/accessibility/mojom/typemaps.gni
+++ b/chromium/ui/accessibility/mojom/typemaps.gni
@@ -7,6 +7,7 @@ typemaps = [
"//ui/accessibility/mojom/ax_assistant_structure.typemap",
"//ui/accessibility/mojom/ax_event.typemap",
"//ui/accessibility/mojom/ax_node_data.typemap",
+ "//ui/accessibility/mojom/ax_relative_bounds.typemap",
"//ui/accessibility/mojom/ax_tree_data.typemap",
"//ui/accessibility/mojom/ax_tree_id.typemap",
"//ui/accessibility/mojom/ax_tree_update.typemap",
diff --git a/chromium/ui/accessibility/platform/DEPS b/chromium/ui/accessibility/platform/DEPS
new file mode 100644
index 00000000000..d457dd7de92
--- /dev/null
+++ b/chromium/ui/accessibility/platform/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+ "atk_util_auralinux_x11.cc": [
+ "+ui/events/x",
+ ]
+}
diff --git a/chromium/ui/accessibility/platform/atk_util_auralinux.cc b/chromium/ui/accessibility/platform/atk_util_auralinux.cc
index eab53e188d3..ffe381f74f2 100644
--- a/chromium/ui/accessibility/platform/atk_util_auralinux.cc
+++ b/chromium/ui/accessibility/platform/atk_util_auralinux.cc
@@ -3,9 +3,12 @@
// found in the LICENSE file.
#include <atk/atk.h>
+#include <map>
+#include <utility>
#include "base/environment.h"
#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
#include "ui/accessibility/platform/atk_util_auralinux.h"
#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
@@ -75,6 +78,26 @@ static G_CONST_RETURN gchar* atk_util_auralinux_get_toolkit_version(void) {
return "1.0";
}
+using KeySnoopFuncMap = std::map<guint, std::pair<AtkKeySnoopFunc, gpointer>>;
+static KeySnoopFuncMap& GetActiveKeySnoopFunctions() {
+ static base::NoDestructor<KeySnoopFuncMap> active_key_snoop_functions;
+ return *active_key_snoop_functions;
+}
+
+static guint atk_util_add_key_event_listener(AtkKeySnoopFunc key_snoop_function,
+ gpointer data) {
+ static guint current_key_event_listener_id = 0;
+
+ current_key_event_listener_id++;
+ GetActiveKeySnoopFunctions()[current_key_event_listener_id] =
+ std::make_pair(key_snoop_function, data);
+ return current_key_event_listener_id;
+}
+
+static void atk_util_remove_key_event_listener(guint listener_id) {
+ GetActiveKeySnoopFunctions().erase(listener_id);
+}
+
static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) {
AtkUtilClass *atk_class;
gpointer data;
@@ -85,6 +108,8 @@ static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) {
atk_class->get_root = atk_util_auralinux_get_root;
atk_class->get_toolkit_name = atk_util_auralinux_get_toolkit_name;
atk_class->get_toolkit_version = atk_util_auralinux_get_toolkit_version;
+ atk_class->add_key_event_listener = atk_util_add_key_event_listener;
+ atk_class->remove_key_event_listener = atk_util_remove_key_event_listener;
}
G_END_DECLS
@@ -130,4 +155,35 @@ void AtkUtilAuraLinux::InitializeForTesting() {
InitializeAsync();
}
+// static
+DiscardAtkKeyEvent AtkUtilAuraLinux::HandleAtkKeyEvent(
+ AtkKeyEventStruct* key_event) {
+ DCHECK(key_event);
+
+ if (!GetInstance()->ShouldEnableAccessibility())
+ return DiscardAtkKeyEvent::Retain;
+
+ GetInstance()->InitializeAsync();
+
+ bool discard = false;
+ for (auto& entry : GetActiveKeySnoopFunctions()) {
+ AtkKeySnoopFunc key_snoop_function = entry.second.first;
+ gpointer data = entry.second.second;
+
+ // We want to ensure that all functions are called. We will discard this
+ // event if at least one function suggests that we do it, but we still
+ // need to call the functions that follow it in the map iterator.
+ if (key_snoop_function(key_event, data) != 0)
+ discard = true;
+ }
+ return discard ? DiscardAtkKeyEvent::Discard : DiscardAtkKeyEvent::Retain;
+}
+
+#if !defined(USE_X11)
+DiscardAtkKeyEvent AtkUtilAuraLinux::HandleKeyEvent(
+ const ui::KeyEvent& ui_key_event) {
+ NOTREACHED();
+}
+#endif
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/atk_util_auralinux.h b/chromium/ui/accessibility/platform/atk_util_auralinux.h
index 286d49a7203..b846d5fb8ee 100644
--- a/chromium/ui/accessibility/platform/atk_util_auralinux.h
+++ b/chromium/ui/accessibility/platform/atk_util_auralinux.h
@@ -5,12 +5,34 @@
#ifndef UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
#define UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
+#include <atk/atk.h>
+
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "ui/accessibility/ax_export.h"
+#if defined(USE_X11)
+#include "ui/gfx/x/x11.h"
+#endif
+
namespace ui {
+// These values are duplicates of the GDK values that can be found in
+// <gdk/gdktypes.h>. ATK expects the GDK values, but we don't want to depend on
+// GDK here.
+typedef enum {
+ kAtkShiftMask = 1 << 0,
+ kAtkLockMask = 1 << 1,
+ kAtkControlMask = 1 << 2,
+ kAtkMod1Mask = 1 << 3,
+ kAtkMod2Mask = 1 << 4,
+ kAtkMod3Mask = 1 << 5,
+ kAtkMod4Mask = 1 << 6,
+ KAtkMod5Mask = 1 << 7,
+} AtkKeyModifierMask;
+
+enum DiscardAtkKeyEvent { Discard, Retain };
+
// This singleton class initializes ATK (accessibility toolkit) and
// registers an implementation of the AtkUtil class, a global class that
// every accessible application needs to register once.
@@ -24,6 +46,12 @@ class AX_EXPORT AtkUtilAuraLinux {
void InitializeAsync();
void InitializeForTesting();
+ static DiscardAtkKeyEvent HandleAtkKeyEvent(AtkKeyEventStruct* key_event);
+
+#if defined(USE_X11)
+ static DiscardAtkKeyEvent HandleKeyEvent(XEvent* xevent);
+#endif
+
private:
friend struct base::DefaultSingletonTraits<AtkUtilAuraLinux>;
diff --git a/chromium/ui/accessibility/platform/atk_util_auralinux_unittest.cc b/chromium/ui/accessibility/platform/atk_util_auralinux_unittest.cc
new file mode 100644
index 00000000000..bbb70fb0077
--- /dev/null
+++ b/chromium/ui/accessibility/platform/atk_util_auralinux_unittest.cc
@@ -0,0 +1,79 @@
+// 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.
+
+// Chromium cannot upgrade to ATK 2.12 API as it still needs to run
+// valid builds for Ubuntu Trusty.
+#define ATK_DISABLE_DEPRECATION_WARNINGS
+
+#include <atk/atk.h>
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/platform/atk_util_auralinux.h"
+#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
+#include "ui/accessibility/platform/ax_platform_node_unittest.h"
+#include "ui/accessibility/platform/test_ax_node_wrapper.h"
+
+namespace ui {
+
+class AtkUtilAuraLinuxTest : public AXPlatformNodeTest {
+ public:
+ AtkUtilAuraLinuxTest() {
+ // We need to create a platform node in order to install it as the root
+ // ATK node. The ATK bridge will complain if we try to use it without a
+ // root node installed.
+ AXNodeData root;
+ root.id = 1;
+ Init(root);
+
+ TestAXNodeWrapper* wrapper =
+ TestAXNodeWrapper::GetOrCreate(tree_.get(), GetRootNode());
+ if (!wrapper)
+ NOTREACHED();
+ AXPlatformNodeAuraLinux::SetApplication(wrapper->ax_platform_node());
+
+ AtkUtilAuraLinux::GetInstance()->InitializeForTesting();
+ }
+
+ ~AtkUtilAuraLinuxTest() override {
+ TestAXNodeWrapper* wrapper =
+ TestAXNodeWrapper::GetOrCreate(tree_.get(), GetRootNode());
+ if (!wrapper)
+ NOTREACHED();
+ g_object_unref(wrapper->ax_platform_node()->GetNativeViewAccessible());
+ }
+};
+
+TEST_F(AtkUtilAuraLinuxTest, KeySnooping) {
+ AtkKeySnoopFunc key_snoop_func = reinterpret_cast<AtkKeySnoopFunc>(
+ +[](AtkKeyEventStruct* key_event, int* keyval_seen) {
+ *keyval_seen = key_event->keyval;
+ });
+
+ int keyval_seen = 0;
+ guint listener_id = atk_add_key_event_listener(key_snoop_func, &keyval_seen);
+
+ AtkKeyEventStruct atk_key_event;
+ atk_key_event.type = ATK_KEY_EVENT_PRESS;
+ atk_key_event.state = 0;
+ atk_key_event.keyval = 55;
+ atk_key_event.keycode = 10;
+ atk_key_event.timestamp = 10;
+ atk_key_event.string = nullptr;
+ atk_key_event.length = 0;
+
+ AtkUtilAuraLinux* atk_util = AtkUtilAuraLinux::GetInstance();
+ atk_util->HandleAtkKeyEvent(&atk_key_event);
+ EXPECT_EQ(keyval_seen, 55);
+
+ atk_remove_key_event_listener(listener_id);
+
+ keyval_seen = 0;
+ atk_util->HandleAtkKeyEvent(&atk_key_event);
+
+ EXPECT_EQ(keyval_seen, 0);
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/atk_util_auralinux_x11.cc b/chromium/ui/accessibility/platform/atk_util_auralinux_x11.cc
new file mode 100644
index 00000000000..143d9ca871f
--- /dev/null
+++ b/chromium/ui/accessibility/platform/atk_util_auralinux_x11.cc
@@ -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.
+
+#include <atk/atk.h>
+
+#include "ui/accessibility/platform/atk_util_auralinux.h"
+#include "ui/events/x/events_x_utils.h"
+
+namespace ui {
+
+// static
+DiscardAtkKeyEvent AtkUtilAuraLinux::HandleKeyEvent(XEvent* xevent) {
+ if (!GetInstance()->ShouldEnableAccessibility())
+ return DiscardAtkKeyEvent::Retain;
+
+ AtkKeyEventStruct atk_key_event;
+ if (xevent->type == KeyPress)
+ atk_key_event.type = ATK_KEY_EVENT_PRESS;
+ else if (xevent->type == KeyRelease)
+ atk_key_event.type = ATK_KEY_EVENT_RELEASE;
+ else
+ NOTREACHED() << xevent->type;
+
+ XKeyEvent& xkey = xevent->xkey;
+ KeySym keysym = NoSymbol;
+ XLookupString(&xkey, nullptr, 0, &keysym, nullptr);
+
+ atk_key_event.state = xkey.state;
+ atk_key_event.keyval = keysym;
+ atk_key_event.keycode = xkey.keycode;
+ atk_key_event.timestamp = xkey.time;
+
+ // This string property matches the one that was removed from GdkEventKey. In
+ // the future, ATK clients should no longer rely on it, so we set it to null.
+ atk_key_event.string = nullptr;
+ atk_key_event.length = 0;
+
+ int flags = ui::EventFlagsFromXEvent(*xevent);
+ if (flags & ui::EF_SHIFT_DOWN)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkShiftMask;
+ if (flags & ui::EF_CAPS_LOCK_ON)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkLockMask;
+ if (flags & ui::EF_CONTROL_DOWN)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkControlMask;
+ if (flags & ui::EF_ALT_DOWN)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkMod1Mask;
+ if (flags & ui::EF_NUM_LOCK_ON)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkMod2Mask;
+ if (flags & ui::EF_MOD3_DOWN)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkMod3Mask;
+ if (flags & ui::EF_COMMAND_DOWN)
+ atk_key_event.state |= AtkKeyModifierMask::kAtkMod4Mask;
+ if (flags & ui::EF_ALTGR_DOWN)
+ atk_key_event.state |= AtkKeyModifierMask::KAtkMod5Mask;
+
+ return HandleAtkKeyEvent(&atk_key_event);
+}
+
+} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node.cc b/chromium/ui/accessibility/platform/ax_platform_node.cc
index a4f31d93770..840944be2f7 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node.cc
@@ -61,7 +61,7 @@ void AXPlatformNode::Destroy() {
}
int32_t AXPlatformNode::GetUniqueId() const {
- DCHECK(GetDelegate()); // Must be called after Init()
+ DCHECK(GetDelegate()) << "|GetUniqueId| must be called after |Init|.";
return GetDelegate() ? GetDelegate()->GetUniqueId().Get() : -1;
}
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
index c61d9ea4e11..154ffcbaf9d 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -52,7 +52,7 @@ typedef struct _AXPlatformNodeAuraLinuxClass AXPlatformNodeAuraLinuxClass;
// TODO(aleventhal) Remove this and use atk_role_get_name() once the following
// GNOME bug is fixed: https://bugzilla.gnome.org/show_bug.cgi?id=795983
-const char* role_names[] = {
+const char* const kRoleNames[] = {
"invalid", // ATK_ROLE_INVALID.
"accelerator label",
"alert",
@@ -358,6 +358,15 @@ static gfx::Point FindAtkObjectParentCoords(AtkObject* atk_object) {
return FindAtkObjectParentCoords(atk_object);
}
+static AtkObject* FindAtkObjectParentFrame(AtkObject* atk_object) {
+ while (atk_object) {
+ if (atk_object_get_role(atk_object) == ATK_ROLE_FRAME)
+ return atk_object;
+ atk_object = atk_object_get_parent(atk_object);
+ }
+ return nullptr;
+}
+
static void AXPlatformNodeAuraLinuxGetExtents(AtkComponent* atk_component,
gint* x,
gint* y,
@@ -960,6 +969,12 @@ static const GInterfaceInfo TextInfo = {
reinterpret_cast<GInterfaceInitFunc>(AXTextInterfaceBaseInit), nullptr,
nullptr};
+static void AXWindowInterfaceBaseInit(AtkWindowIface* iface) {}
+
+static const GInterfaceInfo WindowInfo = {
+ reinterpret_cast<GInterfaceInitFunc>(AXWindowInterfaceBaseInit), nullptr,
+ nullptr};
+
//
// The rest of the AXPlatformNodeAtk code, not specific to one
// of the Atk* interfaces.
@@ -1033,18 +1048,27 @@ void AXPlatformNodeAuraLinuxDetach(AXPlatformNodeAuraLinuxObject* atk_object) {
G_END_DECLS
-void AXPlatformNodeAuraLinux::EnsureGTypeInit() {
-#if !GLIB_CHECK_VERSION(2, 36, 0)
- static bool first_time = true;
- if (UNLIKELY(first_time)) {
- g_type_init();
- first_time = false;
- }
-#endif
-}
+namespace {
+
+// The root-level Application object that's the parent of all top-level windows.
+AXPlatformNode* g_root_application = nullptr;
+
+// The last AtkObject with keyboard focus. Tracking this is required to emit the
+// ATK_STATE_FOCUSED change to false.
+AtkObject* g_current_focused = nullptr;
-const char* AXPlatformNodeAuraLinux::GetUniqueAccessibilityGTypeName(
- int interface_mask) {
+// The last object which was selected. Tracking this is required because
+// widgets in the browser UI only emit notifications upon becoming selected,
+// but clients also expect notifications when items become unselected.
+AXPlatformNodeAuraLinux* g_current_selected = nullptr;
+
+// The AtkObject with role=ATK_ROLE_FRAME that represents the toplevel desktop
+// window with focus. If this window is not one of our windows, this value
+// should be null. This is a weak pointer as well, so its value will also be
+// null if if the AtkObject is destroyed.
+AtkObject* g_active_top_level_frame = nullptr;
+
+const char* GetUniqueAccessibilityGTypeName(int interface_mask) {
// 37 characters is enough for "AXPlatformNodeAuraLinux%x" with any integer
// value.
static char name[37];
@@ -1052,12 +1076,38 @@ const char* AXPlatformNodeAuraLinux::GetUniqueAccessibilityGTypeName(
return name;
}
-static bool IsRoleWithValueInterface(AtkRole role) {
+bool IsRoleWithValueInterface(AtkRole role) {
return role == ATK_ROLE_SCROLL_BAR || role == ATK_ROLE_SLIDER ||
role == ATK_ROLE_PROGRESS_BAR || role == ATK_ROLE_SEPARATOR ||
role == ATK_ROLE_SPIN_BUTTON;
}
+} // namespace
+
+static void SetActiveTopLevelFrame(AtkObject* new_top_level_frame) {
+ if (g_active_top_level_frame)
+ g_object_remove_weak_pointer(
+ G_OBJECT(g_active_top_level_frame),
+ reinterpret_cast<void**>(&g_active_top_level_frame));
+
+ g_active_top_level_frame = new_top_level_frame;
+
+ if (g_active_top_level_frame)
+ g_object_add_weak_pointer(
+ G_OBJECT(g_active_top_level_frame),
+ reinterpret_cast<void**>(&g_active_top_level_frame));
+}
+
+void AXPlatformNodeAuraLinux::EnsureGTypeInit() {
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+ static bool first_time = true;
+ if (UNLIKELY(first_time)) {
+ g_type_init();
+ first_time = false;
+ }
+#endif
+}
+
int AXPlatformNodeAuraLinux::GetGTypeInterfaceMask() {
int interface_mask = 0;
@@ -1094,6 +1144,9 @@ int AXPlatformNodeAuraLinux::GetGTypeInterfaceMask() {
if (role == ATK_ROLE_LINK)
interface_mask |= 1 << ATK_HYPERLINK_INTERFACE;
+ if (role == ATK_ROLE_FRAME)
+ interface_mask |= 1 << ATK_WINDOW_INTERFACE;
+
return interface_mask;
}
@@ -1135,6 +1188,8 @@ GType AXPlatformNodeAuraLinux::GetAccessibilityGType() {
g_type_add_interface_static(type, ATK_TYPE_HYPERTEXT, &HypertextInfo);
if (interface_mask_ & (1 << ATK_TEXT_INTERFACE))
g_type_add_interface_static(type, ATK_TYPE_TEXT, &TextInfo);
+ if (interface_mask_ & (1 << ATK_WINDOW_INTERFACE))
+ g_type_add_interface_static(type, ATK_TYPE_WINDOW, &WindowInfo);
return type;
}
@@ -1158,8 +1213,8 @@ void AXPlatformNodeAuraLinux::DestroyAtkObjects() {
atk_hyperlink_ = nullptr;
}
if (atk_object_) {
- if (atk_object_ == current_focused_)
- current_focused_ = nullptr;
+ if (atk_object_ == g_current_focused)
+ g_current_focused = nullptr;
AXPlatformNodeAuraLinuxDetach(AX_PLATFORM_NODE_AURALINUX(atk_object_));
g_object_unref(atk_object_);
atk_object_ = nullptr;
@@ -1200,11 +1255,13 @@ AXPlatformNodeAuraLinux* AXPlatformNodeAuraLinux::GetFromUniqueId(
//
// static
-AXPlatformNode* AXPlatformNodeAuraLinux::application_ = nullptr;
+void AXPlatformNodeAuraLinux::SetApplication(AXPlatformNode* application) {
+ g_root_application = application;
+}
// static
-void AXPlatformNodeAuraLinux::SetApplication(AXPlatformNode* application) {
- application_ = application;
+AXPlatformNode* AXPlatformNodeAuraLinux::application() {
+ return g_root_application;
}
// static
@@ -1589,6 +1646,8 @@ AtkRole AXPlatformNodeAuraLinux::GetAtkRole() {
void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
AXNodeData data = GetData();
+ if (atk_object_ == g_active_top_level_frame)
+ atk_state_set_add_state(atk_state_set, ATK_STATE_ACTIVE);
if (data.HasState(ax::mojom::State::kCollapsed))
atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDABLE);
if (data.HasState(ax::mojom::State::kDefault))
@@ -1684,13 +1743,12 @@ void AXPlatformNodeAuraLinux::GetAtkRelations(
AtkRelationSet* atk_relation_set) {
}
-AXPlatformNodeAuraLinux::AXPlatformNodeAuraLinux()
- : interface_mask_(0),
- atk_object_(nullptr),
- atk_hyperlink_(nullptr),
- weak_factory_(this) {}
+AXPlatformNodeAuraLinux::AXPlatformNodeAuraLinux() = default;
AXPlatformNodeAuraLinux::~AXPlatformNodeAuraLinux() {
+ if (g_current_selected == this)
+ g_current_selected = nullptr;
+
DestroyAtkObjects();
}
@@ -1728,7 +1786,7 @@ void AXPlatformNodeAuraLinux::AddAccessibilityTreeProperties(
AtkRole role = GetAtkRole();
if (role != ATK_ROLE_UNKNOWN) {
int role_index = static_cast<int>(role);
- dict->SetString("role", role_names[role_index]);
+ dict->SetString("role", kRoleNames[role_index]);
}
const gchar* name = atk_object_get_name(atk_object_);
if (name)
@@ -1773,37 +1831,60 @@ void AXPlatformNodeAuraLinux::OnExpandedStateChanged(bool is_expanded) {
is_expanded);
}
-AtkObject* AXPlatformNodeAuraLinux::current_focused_ = nullptr;
+void AXPlatformNodeAuraLinux::OnWindowActivated() {
+ AtkObject* parent_frame = FindAtkObjectParentFrame(atk_object_);
+ if (!parent_frame || parent_frame == g_active_top_level_frame)
+ return;
+
+ SetActiveTopLevelFrame(parent_frame);
+
+ g_signal_emit_by_name(parent_frame, "activate");
+ atk_object_notify_state_change(parent_frame, ATK_STATE_ACTIVE, TRUE);
+}
+
+void AXPlatformNodeAuraLinux::OnWindowDeactivated() {
+ AtkObject* parent_frame = FindAtkObjectParentFrame(atk_object_);
+ if (!parent_frame || parent_frame != g_active_top_level_frame)
+ return;
+
+ SetActiveTopLevelFrame(nullptr);
+
+ g_signal_emit_by_name(parent_frame, "deactivate");
+ atk_object_notify_state_change(parent_frame, ATK_STATE_ACTIVE, FALSE);
+}
void AXPlatformNodeAuraLinux::OnFocused() {
DCHECK(atk_object_);
- if (atk_object_ == current_focused_)
+ if (atk_object_get_role(atk_object_) == ATK_ROLE_FRAME) {
+ g_signal_emit_by_name(atk_object_, "activate");
+ atk_object_notify_state_change(atk_object_, ATK_STATE_ACTIVE, TRUE);
+ return;
+ }
+
+ if (atk_object_ == g_current_focused)
return;
- if (current_focused_) {
- g_signal_emit_by_name(current_focused_, "focus-event", false);
- atk_object_notify_state_change(ATK_OBJECT(current_focused_),
+ if (g_current_focused) {
+ g_signal_emit_by_name(g_current_focused, "focus-event", false);
+ atk_object_notify_state_change(ATK_OBJECT(g_current_focused),
ATK_STATE_FOCUSED, false);
}
- current_focused_ = atk_object_;
+ g_current_focused = atk_object_;
g_signal_emit_by_name(atk_object_, "focus-event", true);
atk_object_notify_state_change(ATK_OBJECT(atk_object_), ATK_STATE_FOCUSED,
true);
}
-base::WeakPtr<AXPlatformNodeAuraLinux>
- AXPlatformNodeAuraLinux::current_selected_ = nullptr;
-
void AXPlatformNodeAuraLinux::OnSelected() {
- if (current_selected_ && !current_selected_->GetData().GetBoolAttribute(
- ax::mojom::BoolAttribute::kSelected)) {
- atk_object_notify_state_change(ATK_OBJECT(current_selected_->atk_object_),
+ if (g_current_selected && !g_current_selected->GetData().GetBoolAttribute(
+ ax::mojom::BoolAttribute::kSelected)) {
+ atk_object_notify_state_change(ATK_OBJECT(g_current_selected->atk_object_),
ATK_STATE_SELECTED, false);
}
- current_selected_ = weak_factory_.GetWeakPtr();
+ g_current_selected = this;
if (ATK_IS_OBJECT(atk_object_)) {
atk_object_notify_state_change(ATK_OBJECT(atk_object_), ATK_STATE_SELECTED,
true);
@@ -1880,6 +1961,12 @@ void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(
case ax::mojom::Event::kValueChanged:
OnValueChanged();
break;
+ case ax::mojom::Event::kWindowActivated:
+ OnWindowActivated();
+ break;
+ case ax::mojom::Event::kWindowDeactivated:
+ OnWindowDeactivated();
+ break;
default:
break;
}
@@ -1940,7 +2027,7 @@ void AXPlatformNodeAuraLinux::GetPosition(gint* x, gint* y,
}
void AXPlatformNodeAuraLinux::GetSize(gint* width, gint* height) {
- gfx::Rect rect_size = gfx::ToEnclosingRect(GetData().location);
+ gfx::Rect rect_size = gfx::ToEnclosingRect(GetData().relative_bounds.bounds);
if (width)
*width = rect_size.width();
if (height)
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
index 48fd256d64b..b2b7f85da63 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -35,7 +35,7 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
// Set or get the root-level Application object that's the parent of all
// top-level windows.
static void SetApplication(AXPlatformNode* application);
- static AXPlatformNode* application() { return application_; }
+ static AXPlatformNode* application();
static void EnsureGTypeInit();
@@ -81,6 +81,8 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
void OnCheckedStateChanged();
void OnExpandedStateChanged(bool is_expanded);
void OnFocused();
+ void OnWindowActivated();
+ void OnWindowDeactivated();
void OnSelected();
void OnValueChanged();
@@ -119,8 +121,9 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
ATK_TABLE_INTERFACE,
ATK_TEXT_INTERFACE,
ATK_VALUE_INTERFACE,
+ ATK_WINDOW_INTERFACE,
};
- static const char* GetUniqueAccessibilityGTypeName(int interface_mask);
+
int GetGTypeInterfaceMask();
GType GetAccessibilityGType();
AtkObject* CreateAtkObject();
@@ -131,26 +134,11 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
// Keep information of latest AtkInterfaces mask to refresh atk object
// interfaces accordingly if needed.
- int interface_mask_;
+ int interface_mask_ = 0;
// We own a reference to these ref-counted objects.
- AtkObject* atk_object_;
- AtkHyperlink* atk_hyperlink_;
-
- // The root-level Application object that's the parent of all
- // top-level windows.
- static AXPlatformNode* application_;
-
- // The last AtkObject with keyboard focus. Tracking this is required
- // to emit the ATK_STATE_FOCUSED change to false.
- static AtkObject* current_focused_;
-
- // The last object which was selected. Tracking this is required because
- // widgets in the browser UI only emit notifications upon becoming selected,
- // but clients also expect notifications when items become unselected.
- static base::WeakPtr<AXPlatformNodeAuraLinux> current_selected_;
-
- base::WeakPtrFactory<AXPlatformNodeAuraLinux> weak_factory_;
+ AtkObject* atk_object_ = nullptr;
+ AtkHyperlink* atk_hyperlink_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeAuraLinux);
};
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index 21f086f22e0..f0dd65e3f6c 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -9,6 +9,7 @@
#include <atk/atk.h>
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
#include "ui/accessibility/platform/ax_platform_node_unittest.h"
#include "ui/accessibility/platform/test_ax_node_wrapper.h"
@@ -32,7 +33,19 @@ class AXPlatformNodeAuraLinuxTest : public AXPlatformNodeTest {
return atk_object;
}
+ TestAXNodeWrapper* GetRootWrapper() {
+ return TestAXNodeWrapper::GetOrCreate(tree_.get(), GetRootNode());
+ }
+
AtkObject* GetRootAtkObject() { return AtkObjectFromNode(GetRootNode()); }
+
+ AXPlatformNodeAuraLinux* GetRootPlatformNode() {
+ TestAXNodeWrapper* wrapper = GetRootWrapper();
+ if (!wrapper)
+ return nullptr;
+ AXPlatformNode* ax_platform_node = wrapper->ax_platform_node();
+ return static_cast<AXPlatformNodeAuraLinux*>(ax_platform_node);
+ }
};
static void EnsureAtkObjectHasAttributeWithValue(
@@ -615,16 +628,16 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkComponentRefAtPoint) {
root.id = 0;
root.child_ids.push_back(1);
root.child_ids.push_back(2);
- root.location = gfx::RectF(0, 0, 30, 30);
+ root.relative_bounds.bounds = gfx::RectF(0, 0, 30, 30);
AXNodeData node1;
node1.id = 1;
- node1.location = gfx::RectF(0, 0, 10, 10);
+ node1.relative_bounds.bounds = gfx::RectF(0, 0, 10, 10);
node1.SetName("Name1");
AXNodeData node2;
node2.id = 2;
- node2.location = gfx::RectF(20, 20, 10, 10);
+ node2.relative_bounds.bounds = gfx::RectF(20, 20, 10, 10);
node2.SetName("Name2");
Init(root, node1, node2);
@@ -655,12 +668,12 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkComponentsGetExtentsPositionSize) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kWindow;
- root.location = gfx::RectF(10, 40, 800, 600);
+ root.relative_bounds.bounds = gfx::RectF(10, 40, 800, 600);
root.child_ids.push_back(2);
AXNodeData child;
child.id = 2;
- child.location = gfx::RectF(100, 150, 200, 200);
+ child.relative_bounds.bounds = gfx::RectF(100, 150, 200, 200);
Init(root, child);
TestAXNodeWrapper::SetGlobalCoordinateOffset(gfx::Vector2d(100, 200));
@@ -943,4 +956,58 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkTextCharacterGranularity) {
g_object_unref(root_obj);
}
+//
+// AtkWindow interface and active state
+//
+//
+TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkWindowActive) {
+ AXNodeData root;
+ root.id = 1;
+ root.role = ax::mojom::Role::kWindow;
+ Init(root);
+
+ AtkObject* root_atk_object(GetRootAtkObject());
+ EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
+ g_object_ref(root_atk_object);
+
+ EXPECT_TRUE(ATK_IS_WINDOW(root_atk_object));
+
+ bool saw_activate = false;
+ bool saw_deactivate = false;
+
+ auto callback = G_CALLBACK(+[](AtkWindow*, bool* flag) { *flag = true; });
+ g_signal_connect(root_atk_object, "activate", callback, &saw_activate);
+ g_signal_connect(root_atk_object, "deactivate", callback, &saw_deactivate);
+
+ AtkStateSet* state_set = atk_object_ref_state_set(root_atk_object);
+ EXPECT_TRUE(ATK_IS_STATE_SET(state_set));
+ EXPECT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_ACTIVE));
+ g_object_unref(state_set);
+
+ static_cast<AXPlatformNodeAuraLinux*>(GetRootPlatformNode())
+ ->NotifyAccessibilityEvent(ax::mojom::Event::kWindowActivated);
+ EXPECT_TRUE(saw_activate);
+ EXPECT_FALSE(saw_deactivate);
+
+ state_set = atk_object_ref_state_set(root_atk_object);
+ EXPECT_TRUE(ATK_IS_STATE_SET(state_set));
+ EXPECT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_ACTIVE));
+ g_object_unref(state_set);
+
+ saw_activate = false;
+ saw_deactivate = false;
+
+ static_cast<AXPlatformNodeAuraLinux*>(GetRootPlatformNode())
+ ->NotifyAccessibilityEvent(ax::mojom::Event::kWindowDeactivated);
+ EXPECT_FALSE(saw_activate);
+ EXPECT_TRUE(saw_deactivate);
+
+ state_set = atk_object_ref_state_set(root_atk_object);
+ EXPECT_TRUE(ATK_IS_STATE_SET(state_set));
+ EXPECT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_ACTIVE));
+ g_object_unref(state_set);
+
+ g_object_unref(root_atk_object);
+}
+
} // namespace ui
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.cc b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
index e4a10976f4f..b321c498745 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.cc
@@ -23,17 +23,36 @@ namespace ui {
const base::char16 AXPlatformNodeBase::kEmbeddedCharacter = L'\xfffc';
+#if !BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY()
+// static
+AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
+ AXPlatformNodeBase* node = new AXPlatformNodeBase();
+ node->Init(delegate);
+ return node;
+}
+#endif
+
+AXPlatformNodeBase::AXPlatformNodeBase() = default;
+
+AXPlatformNodeBase::~AXPlatformNodeBase() = default;
+
void AXPlatformNodeBase::Init(AXPlatformNodeDelegate* delegate) {
delegate_ = delegate;
}
const AXNodeData& AXPlatformNodeBase::GetData() const {
- static base::NoDestructor<AXNodeData> empty_data;
+ static const base::NoDestructor<AXNodeData> empty_data;
if (delegate_)
return delegate_->GetData();
return *empty_data;
}
+gfx::NativeViewAccessible AXPlatformNodeBase::GetFocus() {
+ if (delegate_)
+ return delegate_->GetFocus();
+ return nullptr;
+}
+
gfx::NativeViewAccessible AXPlatformNodeBase::GetParent() {
if (delegate_)
return delegate_->GetParent();
@@ -52,6 +71,10 @@ gfx::NativeViewAccessible AXPlatformNodeBase::ChildAtIndex(int index) {
return nullptr;
}
+int AXPlatformNodeBase::GetIndexInParent() {
+ return -1;
+}
+
// AXPlatformNode overrides.
void AXPlatformNodeBase::Destroy() {
@@ -68,6 +91,13 @@ gfx::NativeViewAccessible AXPlatformNodeBase::GetNativeViewAccessible() {
return nullptr;
}
+void AXPlatformNodeBase::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
+}
+
+#if defined(OS_MACOSX)
+void AXPlatformNodeBase::AnnounceText(base::string16& text) {}
+#endif
+
AXPlatformNodeDelegate* AXPlatformNodeBase::GetDelegate() const {
return delegate_;
}
@@ -190,9 +220,8 @@ bool AXPlatformNodeBase::HasStringAttribute(
const std::string& AXPlatformNodeBase::GetStringAttribute(
ax::mojom::StringAttribute attribute) const {
- static base::NoDestructor<std::string> empty_data;
if (!delegate_)
- return *empty_data;
+ return base::EmptyString();
return GetData().GetStringAttribute(attribute);
}
@@ -228,7 +257,7 @@ bool AXPlatformNodeBase::HasIntListAttribute(
const std::vector<int32_t>& AXPlatformNodeBase::GetIntListAttribute(
ax::mojom::IntListAttribute attribute) const {
- static base::NoDestructor<std::vector<int32_t>> empty_data;
+ static const base::NoDestructor<std::vector<int32_t>> empty_data;
if (!delegate_)
return *empty_data;
return GetData().GetIntListAttribute(attribute);
@@ -242,12 +271,6 @@ bool AXPlatformNodeBase::GetIntListAttribute(
return GetData().GetIntListAttribute(attribute, value);
}
-AXPlatformNodeBase::AXPlatformNodeBase() {
-}
-
-AXPlatformNodeBase::~AXPlatformNodeBase() {
-}
-
// static
AXPlatformNodeBase* AXPlatformNodeBase::FromNativeViewAccessible(
gfx::NativeViewAccessible accessible) {
@@ -343,7 +366,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetSelectionContainer() const {
return nullptr;
AXPlatformNodeBase* container = const_cast<AXPlatformNodeBase*>(this);
while (container &&
- !IsContainerWithSelectableChildrenRole(container->GetData().role)) {
+ !IsContainerWithSelectableChildren(container->GetData().role)) {
gfx::NativeViewAccessible parent_accessible = container->GetParent();
AXPlatformNodeBase* parent = FromNativeViewAccessible(parent_accessible);
@@ -356,7 +379,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetTable() const {
if (!delegate_)
return nullptr;
AXPlatformNodeBase* table = const_cast<AXPlatformNodeBase*>(this);
- while (table && !IsTableLikeRole(table->GetData().role)) {
+ while (table && !IsTableLike(table->GetData().role)) {
gfx::NativeViewAccessible parent_accessible = table->GetParent();
AXPlatformNodeBase* parent = FromNativeViewAccessible(parent_accessible);
@@ -368,8 +391,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetTable() const {
AXPlatformNodeBase* AXPlatformNodeBase::GetTableCell(int index) const {
if (!delegate_)
return nullptr;
- if (!IsTableLikeRole(GetData().role) &&
- !IsCellOrTableHeaderRole(GetData().role))
+ if (!IsTableLike(GetData().role) && !IsCellOrTableHeader(GetData().role))
return nullptr;
AXPlatformNodeBase* table = GetTable();
@@ -382,8 +404,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetTableCell(int index) const {
AXPlatformNodeBase* AXPlatformNodeBase::GetTableCell(int row,
int column) const {
- if (!IsTableLikeRole(GetData().role) &&
- !IsCellOrTableHeaderRole(GetData().role))
+ if (!IsTableLike(GetData().role) && !IsCellOrTableHeader(GetData().role))
return nullptr;
if (row < 0 || row >= GetTableRowCount() || column < 0 ||
@@ -401,14 +422,7 @@ AXPlatformNodeBase* AXPlatformNodeBase::GetTableCell(int row,
}
int AXPlatformNodeBase::GetTableCellIndex() const {
- if (!IsCellOrTableHeaderRole(GetData().role))
- return -1;
-
- AXPlatformNodeBase* table = GetTable();
- if (!table)
- return -1;
-
- return table->delegate_->CellIdToIndex(GetData().id);
+ return delegate_->GetTableCellIndex();
}
int AXPlatformNodeBase::GetTableColumn() const {
@@ -424,7 +438,7 @@ int AXPlatformNodeBase::GetTableColumnCount() const {
}
int AXPlatformNodeBase::GetTableColumnSpan() const {
- if (!IsCellOrTableHeaderRole(GetData().role))
+ if (!IsCellOrTableHeader(GetData().role))
return 0;
int column_span;
@@ -447,7 +461,7 @@ int AXPlatformNodeBase::GetTableRowCount() const {
}
int AXPlatformNodeBase::GetTableRowSpan() const {
- if (!IsCellOrTableHeaderRole(GetData().role))
+ if (!IsCellOrTableHeader(GetData().role))
return 0;
int row_span;
@@ -457,6 +471,9 @@ int AXPlatformNodeBase::GetTableRowSpan() const {
}
bool AXPlatformNodeBase::HasCaret() {
+ if (IsInvisibleOrIgnored())
+ return false;
+
if (IsPlainTextField() &&
HasIntAttribute(ax::mojom::IntAttribute::kTextSelStart) &&
HasIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)) {
@@ -528,6 +545,12 @@ bool AXPlatformNodeBase::IsChildOfLeaf() {
return false;
}
+bool AXPlatformNodeBase::IsInvisibleOrIgnored() const {
+ const AXNodeData& data = GetData();
+ return data.HasState(ax::mojom::State::kInvisible) ||
+ data.role == ax::mojom::Role::kIgnored;
+}
+
bool AXPlatformNodeBase::IsScrollable() const {
return (HasIntAttribute(ax::mojom::IntAttribute::kScrollXMin) &&
HasIntAttribute(ax::mojom::IntAttribute::kScrollXMax) &&
@@ -619,6 +642,9 @@ void AXPlatformNodeBase::ComputeAttributes(PlatformAttributeList* attributes) {
if (HasIntAttribute(ax::mojom::IntAttribute::kCheckedState))
AddAttributeToList("checkable", "true", attributes);
+ if (IsInvisibleOrIgnored()) // Note: NVDA prefers this over INVISIBLE state.
+ AddAttributeToList("hidden", "true", attributes);
+
// Expose live region attributes.
AddAttributeToList(ax::mojom::StringAttribute::kLiveStatus, "live",
attributes);
@@ -717,21 +743,18 @@ void AXPlatformNodeBase::ComputeAttributes(PlatformAttributeList* attributes) {
}
// Expose table cell index.
- if (IsCellOrTableHeaderRole(GetData().role)) {
- AXPlatformNodeBase* table = GetTable();
- if (table) {
- int32_t index = table->delegate_->CellIdToIndex(GetData().id);
- if (index >= 0) {
- std::string str_index(base::IntToString(index));
- AddAttributeToList("table-cell-index", str_index, attributes);
- }
+ if (IsCellOrTableHeader(GetData().role)) {
+ int32_t index = delegate_->GetTableCellIndex();
+ if (index >= 0) {
+ std::string str_index(base::IntToString(index));
+ AddAttributeToList("table-cell-index", str_index, attributes);
}
}
if (GetData().role == ax::mojom::Role::kLayoutTable)
AddAttributeToList("layout-guess", "true", attributes);
// Expose aria-colcount and aria-rowcount in a table, grid or treegrid.
- if (IsTableLikeRole(GetData().role)) {
+ if (IsTableLike(GetData().role)) {
AddAttributeToList(ax::mojom::IntAttribute::kAriaColumnCount, "colcount",
attributes);
AddAttributeToList(ax::mojom::IntAttribute::kAriaRowCount, "rowcount",
@@ -739,7 +762,7 @@ void AXPlatformNodeBase::ComputeAttributes(PlatformAttributeList* attributes) {
}
// Expose aria-colindex and aria-rowindex in a cell or row.
- if (IsCellOrTableHeaderRole(GetData().role) ||
+ if (IsCellOrTableHeader(GetData().role) ||
GetData().role == ax::mojom::Role::kRow) {
if (GetData().role != ax::mojom::Role::kRow)
AddAttributeToList(ax::mojom::IntAttribute::kAriaCellColumnIndex,
@@ -786,7 +809,7 @@ void AXPlatformNodeBase::ComputeAttributes(PlatformAttributeList* attributes) {
}
}
- if (IsCellOrTableHeaderRole(GetData().role)) {
+ if (IsCellOrTableHeader(GetData().role)) {
// Expose colspan attribute.
std::string colspan;
if (GetData().GetHtmlAttribute("aria-colspan", &colspan)) {
@@ -954,6 +977,11 @@ AXHypertext AXPlatformNodeBase::ComputeHypertext() {
return result;
}
+void AXPlatformNodeBase::AddAttributeToList(const char* name,
+ const char* value,
+ PlatformAttributeList* attributes) {
+}
+
// static
void AXPlatformNodeBase::SanitizeStringAttribute(const std::string& input,
std::string* output) {
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_base.h b/chromium/ui/accessibility/platform/ax_platform_node_base.h
index 410f7be2cfd..d080cb1bff9 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_base.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/macros.h"
+#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/base/ui_features.h"
@@ -45,20 +46,30 @@ struct AX_EXPORT AXHypertext {
class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
public:
+ AXPlatformNodeBase();
+ ~AXPlatformNodeBase() override;
+
virtual void Init(AXPlatformNodeDelegate* delegate);
// These are simple wrappers to our delegate.
const AXNodeData& GetData() const;
+ gfx::NativeViewAccessible GetFocus();
gfx::NativeViewAccessible GetParent();
int GetChildCount();
gfx::NativeViewAccessible ChildAtIndex(int index);
// This needs to be implemented for each platform.
- virtual int GetIndexInParent() = 0;
+ virtual int GetIndexInParent();
// AXPlatformNode.
void Destroy() override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;
+
+#if defined(OS_MACOSX)
+ void AnnounceText(base::string16& text) override;
+#endif
+
AXPlatformNodeDelegate* GetDelegate() const override;
// Helpers.
@@ -164,6 +175,8 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
// that might send notifications.
bool IsLeaf();
+ bool IsInvisibleOrIgnored() const;
+
// Returns true if this node can be scrolled either in the horizontal or the
// vertical direction.
bool IsScrollable() const;
@@ -192,9 +205,6 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
AXPlatformNodeDelegate* delegate_;
protected:
- AXPlatformNodeBase();
- ~AXPlatformNodeBase() override;
-
bool IsTextOnlyObject() const;
bool IsPlainTextField() const;
// Is in a focused textfield with a related suggestion popup available,
@@ -258,11 +268,11 @@ class AX_EXPORT AXPlatformNodeBase : public AXPlatformNode {
const std::string& value,
PlatformAttributeList* attributes);
- // A pure virtual method that subclasses use to actually add the attribute to
+ // A virtual method that subclasses use to actually add the attribute to
// |attributes|.
virtual void AddAttributeToList(const char* name,
const char* value,
- PlatformAttributeList* attributes) = 0;
+ PlatformAttributeList* attributes);
// Escapes characters in string attributes as required by the IA2 Spec
// and AT-SPI2. It's okay for input to be the same as output.
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
index c6586ca6088..423ec2eeb92 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -14,6 +14,7 @@
#include "ui/gfx/native_widget_types.h"
namespace gfx {
+
class Rect;
}
@@ -38,7 +39,7 @@ class AXPlatformNode;
// otherwise.
class AX_EXPORT AXPlatformNodeDelegate {
public:
- virtual ~AXPlatformNodeDelegate() {}
+ virtual ~AXPlatformNodeDelegate() = default;
// Get the accessibility data that should be exposed for this node.
// Virtually all of the information is obtained from this structure
@@ -49,8 +50,9 @@ class AX_EXPORT AXPlatformNodeDelegate {
// Get the accessibility tree data for this node.
virtual const AXTreeData& GetTreeData() const = 0;
- // Get the window the node is contained in.
- virtual gfx::NativeWindow GetTopLevelWidget() = 0;
+ // Get the accessibility node for the NSWindow the node is contained in. This
+ // method is only meaningful on macOS.
+ virtual gfx::NativeViewAccessible GetNSWindow() = 0;
// Get the parent of the node, which may be an AXPlatformNode or it may
// be a native accessible object implemented by another class.
@@ -118,12 +120,14 @@ class AX_EXPORT AXPlatformNodeDelegate {
virtual int GetTableRowCount() const = 0;
virtual int GetTableColCount() const = 0;
- virtual std::vector<int32_t> GetColHeaderNodeIds() const = 0;
- virtual std::vector<int32_t> GetColHeaderNodeIds(int32_t col_index) const = 0;
- virtual std::vector<int32_t> GetRowHeaderNodeIds() const = 0;
- virtual std::vector<int32_t> GetRowHeaderNodeIds(int32_t row_index) const = 0;
+ virtual const std::vector<int32_t> GetColHeaderNodeIds() const = 0;
+ virtual const std::vector<int32_t> GetColHeaderNodeIds(
+ int32_t col_index) const = 0;
+ virtual const std::vector<int32_t> GetRowHeaderNodeIds() const = 0;
+ virtual const std::vector<int32_t> GetRowHeaderNodeIds(
+ int32_t row_index) const = 0;
virtual int32_t GetCellId(int32_t row_index, int32_t col_index) const = 0;
- virtual int32_t CellIdToIndex(int32_t cell_id) const = 0;
+ virtual int32_t GetTableCellIndex() const = 0;
virtual int32_t CellIndexToId(int32_t cell_index) const = 0;
//
@@ -153,7 +157,7 @@ class AX_EXPORT AXPlatformNodeDelegate {
virtual bool ShouldIgnoreHoveredStateForTesting() = 0;
protected:
- AXPlatformNodeDelegate() {}
+ AXPlatformNodeDelegate() = default;
private:
DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeDelegate);
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
index f5a77c4e1dd..fbbfed50168 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -10,6 +10,10 @@
namespace ui {
+AXPlatformNodeDelegateBase::AXPlatformNodeDelegateBase() = default;
+
+AXPlatformNodeDelegateBase::~AXPlatformNodeDelegateBase() = default;
+
const AXNodeData& AXPlatformNodeDelegateBase::GetData() const {
static base::NoDestructor<AXNodeData> empty_data;
return *empty_data;
@@ -20,7 +24,7 @@ const AXTreeData& AXPlatformNodeDelegateBase::GetTreeData() const {
return *empty_data;
}
-gfx::NativeWindow AXPlatformNodeDelegateBase::GetTopLevelWidget() {
+gfx::NativeViewAccessible AXPlatformNodeDelegateBase::GetNSWindow() {
return nullptr;
}
@@ -74,20 +78,22 @@ int AXPlatformNodeDelegateBase::GetTableColCount() const {
return 0;
}
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds() const {
+const std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds()
+ const {
return std::vector<int32_t>();
}
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds(
+const std::vector<int32_t> AXPlatformNodeDelegateBase::GetColHeaderNodeIds(
int32_t col_index) const {
return std::vector<int32_t>();
}
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds() const {
+const std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds()
+ const {
return std::vector<int32_t>();
}
-std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds(
+const std::vector<int32_t> AXPlatformNodeDelegateBase::GetRowHeaderNodeIds(
int32_t row_index) const {
return std::vector<int32_t>();
}
@@ -97,8 +103,8 @@ int32_t AXPlatformNodeDelegateBase::GetCellId(int32_t row_index,
return -1;
}
-int32_t AXPlatformNodeDelegateBase::CellIdToIndex(int32_t cell_id) const {
- return 0;
+int32_t AXPlatformNodeDelegateBase::GetTableCellIndex() const {
+ return -1;
}
int32_t AXPlatformNodeDelegateBase::CellIndexToId(int32_t cell_index) const {
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
index 0e271aa0acf..4a7ad1a8e84 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
+++ b/chromium/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -15,8 +15,8 @@ namespace ui {
// behavior.
class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
public:
- AXPlatformNodeDelegateBase() {}
- ~AXPlatformNodeDelegateBase() override {}
+ AXPlatformNodeDelegateBase();
+ ~AXPlatformNodeDelegateBase() override;
// Get the accessibility data that should be exposed for this node.
// Virtually all of the information is obtained from this structure
@@ -27,8 +27,8 @@ class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
// Get the accessibility tree data for this node.
const AXTreeData& GetTreeData() const override;
- // Get the window the node is contained in.
- gfx::NativeWindow GetTopLevelWidget() override;
+ // See comments in AXPlatformNodeDelegate.
+ gfx::NativeViewAccessible GetNSWindow() override;
// Get the parent of the node, which may be an AXPlatformNode or it may
// be a native accessible object implemented by another class.
@@ -95,12 +95,14 @@ class AX_EXPORT AXPlatformNodeDelegateBase : public AXPlatformNodeDelegate {
int GetTableRowCount() const override;
int GetTableColCount() const override;
- std::vector<int32_t> GetColHeaderNodeIds() const override;
- std::vector<int32_t> GetColHeaderNodeIds(int32_t col_index) const override;
- std::vector<int32_t> GetRowHeaderNodeIds() const override;
- std::vector<int32_t> GetRowHeaderNodeIds(int32_t row_index) const override;
+ const std::vector<int32_t> GetColHeaderNodeIds() const override;
+ const std::vector<int32_t> GetColHeaderNodeIds(
+ int32_t col_index) const override;
+ const std::vector<int32_t> GetRowHeaderNodeIds() const override;
+ const std::vector<int32_t> GetRowHeaderNodeIds(
+ int32_t row_index) const override;
int32_t GetCellId(int32_t row_index, int32_t col_index) const override;
- int32_t CellIdToIndex(int32_t cell_id) const override;
+ int32_t GetTableCellIndex() const override;
int32_t CellIndexToId(int32_t cell_index) const override;
//
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
index dc041e0b6ee..f7ec926930b 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/chromium/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -316,8 +316,7 @@ void NotifyMacEvent(AXPlatformNodeCocoa* target, ax::mojom::Event event_type) {
// Returns true if |action| should be added implicitly for |data|.
bool HasImplicitAction(const ui::AXNodeData& data, ax::mojom::Action action) {
- return action == ax::mojom::Action::kDoDefault &&
- ui::IsRoleClickable(data.role);
+ return action == ax::mojom::Action::kDoDefault && ui::IsClickable(data.role);
}
// For roles that show a menu for the default action, ensure "show menu" also
@@ -806,7 +805,7 @@ bool AlsoUseShowMenuActionForDefaultAction(const ui::AXNodeData& data) {
}
- (id)AXWindow {
- return node_->GetDelegate()->GetTopLevelWidget();
+ return node_->GetDelegate()->GetNSWindow();
}
- (id)AXTopLevelUIElement {
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win.cc b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
index 15faebdb9ff..56d59f01608 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win.cc
@@ -44,16 +44,16 @@
//
#define COM_OBJECT_VALIDATE() \
- if (!delegate_) \
- return E_FAIL;
+ if (!GetDelegate()) \
+ return E_FAIL;
#define COM_OBJECT_VALIDATE_1_ARG(arg) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg) \
return E_INVALIDARG; \
*arg = {};
#define COM_OBJECT_VALIDATE_2_ARGS(arg1, arg2) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg1) \
return E_INVALIDARG; \
@@ -62,7 +62,7 @@
return E_INVALIDARG; \
*arg2 = {};
#define COM_OBJECT_VALIDATE_3_ARGS(arg1, arg2, arg3) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg1) \
return E_INVALIDARG; \
@@ -74,7 +74,7 @@
return E_INVALIDARG; \
*arg3 = {};
#define COM_OBJECT_VALIDATE_4_ARGS(arg1, arg2, arg3, arg4) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg1) \
return E_INVALIDARG; \
@@ -89,15 +89,15 @@
return E_INVALIDARG; \
*arg4 = {};
#define COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
target = GetTargetFromChildID(var_id); \
if (!target) \
return E_INVALIDARG; \
- if (!target->delegate_) \
+ if (!target->GetDelegate()) \
return E_INVALIDARG;
#define COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, arg, target) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg) \
return E_INVALIDARG; \
@@ -105,11 +105,11 @@
target = GetTargetFromChildID(var_id); \
if (!target) \
return E_INVALIDARG; \
- if (!target->delegate_) \
+ if (!target->GetDelegate()) \
return E_INVALIDARG;
#define COM_OBJECT_VALIDATE_VAR_ID_2_ARGS_AND_GET_TARGET(var_id, arg1, arg2, \
target) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg1) \
return E_INVALIDARG; \
@@ -120,11 +120,11 @@
target = GetTargetFromChildID(var_id); \
if (!target) \
return E_INVALIDARG; \
- if (!target->delegate_) \
+ if (!target->GetDelegate()) \
return E_INVALIDARG;
#define COM_OBJECT_VALIDATE_VAR_ID_3_ARGS_AND_GET_TARGET(var_id, arg1, arg2, \
arg3, target) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg1) \
return E_INVALIDARG; \
@@ -138,11 +138,11 @@
target = GetTargetFromChildID(var_id); \
if (!target) \
return E_INVALIDARG; \
- if (!target->delegate_) \
+ if (!target->GetDelegate()) \
return E_INVALIDARG;
#define COM_OBJECT_VALIDATE_VAR_ID_4_ARGS_AND_GET_TARGET(var_id, arg1, arg2, \
arg3, arg4, target) \
- if (!delegate_) \
+ if (!GetDelegate()) \
return E_FAIL; \
if (!arg1) \
return E_INVALIDARG; \
@@ -159,7 +159,7 @@
target = GetTargetFromChildID(var_id); \
if (!target) \
return E_INVALIDARG; \
- if (!target->delegate_) \
+ if (!target->GetDelegate()) \
return E_INVALIDARG;
namespace ui {
@@ -378,7 +378,7 @@ SAFEARRAY* AXPlatformNodeWin::CreateUIAElementsArrayFromIdVector(
LONG i = 0;
for (const auto& node_id : ids) {
AXPlatformNodeWin* node_win =
- static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(node_id));
+ static_cast<AXPlatformNodeWin*>(GetDelegate()->GetFromNodeID(node_id));
DCHECK(node_win);
node_win->AddRef();
SafeArrayPutElement(uia_array, &i,
@@ -392,14 +392,14 @@ SAFEARRAY* AXPlatformNodeWin::CreateUIAElementsArrayFromIdVector(
gfx::Vector2d AXPlatformNodeWin::CalculateUIAScrollPoint(
const ScrollAmount horizontal_amount,
const ScrollAmount vertical_amount) const {
- if (!delegate_ || !IsScrollable())
+ if (!GetDelegate() || !IsScrollable())
return {};
- const gfx::Rect bounds = delegate_->GetClippedScreenBoundsRect();
+ const gfx::Rect bounds = GetDelegate()->GetClippedScreenBoundsRect();
const int large_horizontal_change = bounds.width();
const int large_vertical_change = bounds.height();
- const HWND hwnd = delegate_->GetTargetForNativeAccessibilityEvent();
+ const HWND hwnd = GetDelegate()->GetTargetForNativeAccessibilityEvent();
DCHECK(hwnd);
const float scale_factor =
display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
@@ -482,7 +482,7 @@ gfx::NativeViewAccessible AXPlatformNodeWin::GetNativeViewAccessible() {
}
void AXPlatformNodeWin::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
- HWND hwnd = delegate_->GetTargetForNativeAccessibilityEvent();
+ HWND hwnd = GetDelegate()->GetTargetForNativeAccessibilityEvent();
if (!hwnd)
return;
@@ -554,13 +554,14 @@ IFACEMETHODIMP AXPlatformNodeWin::accHitTest(LONG x_left,
COM_OBJECT_VALIDATE_1_ARG(child);
gfx::Point point(x_left, y_top);
- if (!delegate_->GetClippedScreenBoundsRect().Contains(point)) {
+ if (!GetDelegate()->GetClippedScreenBoundsRect().Contains(point)) {
// Return S_FALSE and VT_EMPTY when outside the object's boundaries.
child->vt = VT_EMPTY;
return S_FALSE;
}
- gfx::NativeViewAccessible hit_child = delegate_->HitTestSync(x_left, y_top);
+ gfx::NativeViewAccessible hit_child =
+ GetDelegate()->HitTestSync(x_left, y_top);
if (!hit_child) {
child->vt = VT_EMPTY;
return S_FALSE;
@@ -599,7 +600,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accDoDefaultAction(VARIANT var_id) {
AXActionData data;
data.action = ax::mojom::Action::kDoDefault;
- if (target->delegate_->AccessibilityPerformAction(data))
+ if (target->GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
}
@@ -614,7 +615,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accLocation(LONG* x_left,
COM_OBJECT_VALIDATE_VAR_ID_4_ARGS_AND_GET_TARGET(var_id, x_left, y_top, width,
height, target);
- gfx::Rect bounds = target->delegate_->GetUnclippedScreenBoundsRect();
+ gfx::Rect bounds = target->GetDelegate()->GetUnclippedScreenBoundsRect();
*x_left = bounds.x();
*y_top = bounds.y();
*width = bounds.width();
@@ -642,13 +643,14 @@ IFACEMETHODIMP AXPlatformNodeWin::accNavigate(LONG nav_dir,
IAccessible* result = nullptr;
switch (nav_dir) {
case NAVDIR_FIRSTCHILD:
- if (delegate_->GetChildCount() > 0)
- result = delegate_->ChildAtIndex(0);
+ if (GetDelegate()->GetChildCount() > 0)
+ result = GetDelegate()->ChildAtIndex(0);
break;
case NAVDIR_LASTCHILD:
- if (delegate_->GetChildCount() > 0)
- result = delegate_->ChildAtIndex(delegate_->GetChildCount() - 1);
+ if (GetDelegate()->GetChildCount() > 0)
+ result =
+ GetDelegate()->ChildAtIndex(GetDelegate()->GetChildCount() - 1);
break;
case NAVDIR_NEXT: {
@@ -667,8 +669,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accNavigate(LONG nav_dir,
case NAVDIR_DOWN: {
// This direction is not implemented except in tables.
- if (!IsTableLikeRole(GetData().role) &&
- !IsCellOrTableHeaderRole(GetData().role))
+ if (!IsTableLike(GetData().role) && !IsCellOrTableHeader(GetData().role))
return E_NOTIMPL;
AXPlatformNodeBase* next = target->GetTableCell(
@@ -682,8 +683,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accNavigate(LONG nav_dir,
case NAVDIR_UP: {
// This direction is not implemented except in tables.
- if (!IsTableLikeRole(GetData().role) &&
- !IsCellOrTableHeaderRole(GetData().role))
+ if (!IsTableLike(GetData().role) && !IsCellOrTableHeader(GetData().role))
return E_NOTIMPL;
AXPlatformNodeBase* next =
@@ -697,8 +697,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accNavigate(LONG nav_dir,
case NAVDIR_LEFT: {
// This direction is not implemented except in tables.
- if (!IsTableLikeRole(GetData().role) &&
- !IsCellOrTableHeaderRole(GetData().role))
+ if (!IsTableLike(GetData().role) && !IsCellOrTableHeader(GetData().role))
return E_NOTIMPL;
AXPlatformNodeBase* next =
@@ -713,8 +712,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accNavigate(LONG nav_dir,
case NAVDIR_RIGHT: {
// This direction is not implemented except in tables.
- if (!IsTableLikeRole(GetData().role) &&
- !IsCellOrTableHeaderRole(GetData().role))
+ if (!IsTableLike(GetData().role) && !IsCellOrTableHeader(GetData().role))
return E_NOTIMPL;
AXPlatformNodeBase* next = target->GetTableCell(
@@ -754,7 +752,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accChild(VARIANT var_child,
IFACEMETHODIMP AXPlatformNodeWin::get_accChildCount(LONG* child_count) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ACC_CHILD_COUNT);
COM_OBJECT_VALIDATE_1_ARG(child_count);
- *child_count = delegate_->GetChildCount();
+ *child_count = GetDelegate()->GetChildCount();
return S_OK;
}
@@ -797,7 +795,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accDescription(VARIANT var_id,
IFACEMETHODIMP AXPlatformNodeWin::get_accFocus(VARIANT* focus_child) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ACC_FOCUS);
COM_OBJECT_VALIDATE_1_ARG(focus_child);
- gfx::NativeViewAccessible focus_accessible = delegate_->GetFocus();
+ gfx::NativeViewAccessible focus_accessible = GetDelegate()->GetFocus();
if (focus_accessible == this) {
focus_child->vt = VT_I4;
focus_child->lVal = CHILDID_SELF;
@@ -833,16 +831,6 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accName(VARIANT var_id, BSTR* name) {
observer.OnAccNameCalled();
}
- // Ignored items are also marked invisible, but NVDA was not actually ignoring
- // them.
- // TODO(accessibility) Find a way to not expose ignored items at all, which
- // would be less hacky but more code. Using a nameless object is a workaround,
- // although it does not currently cause any known user-facing issues.
- if (target->GetData().role == ax::mojom::Role::kIgnored) {
- *name = nullptr;
- return S_FALSE;
- }
-
HRESULT result =
target->GetStringAttributeAsBstr(ax::mojom::StringAttribute::kName, name);
if (FAILED(result) && MSAARole() == ROLE_SYSTEM_DOCUMENT && GetParent()) {
@@ -947,7 +935,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) {
//
if (target->GetData().role == ax::mojom::Role::kRootWebArea ||
target->GetData().role == ax::mojom::Role::kWebArea) {
- result = base::UTF8ToUTF16(target->delegate_->GetTreeData().url);
+ result = base::UTF8ToUTF16(target->GetDelegate()->GetTreeData().url);
*value = SysAllocString(result.c_str());
DCHECK(*value);
return S_OK;
@@ -994,7 +982,7 @@ IFACEMETHODIMP AXPlatformNodeWin::put_accValue(VARIANT var_id, BSTR new_value) {
AXActionData data;
data.action = ax::mojom::Action::kSetValue;
data.value = base::WideToUTF8(new_value);
- if (target->delegate_->AccessibilityPerformAction(data))
+ if (target->GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
}
@@ -1003,9 +991,9 @@ IFACEMETHODIMP AXPlatformNodeWin::get_accSelection(VARIANT* selected) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_ACC_SELECTION);
COM_OBJECT_VALIDATE_1_ARG(selected);
std::vector<Microsoft::WRL::ComPtr<IDispatch>> selected_nodes;
- for (int i = 0; i < delegate_->GetChildCount(); ++i) {
+ for (int i = 0; i < GetDelegate()->GetChildCount(); ++i) {
auto* node = static_cast<AXPlatformNodeWin*>(
- FromNativeViewAccessible(delegate_->ChildAtIndex(i)));
+ FromNativeViewAccessible(GetDelegate()->ChildAtIndex(i)));
if (node &&
node->GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
selected_nodes.emplace_back(node);
@@ -1044,7 +1032,7 @@ IFACEMETHODIMP AXPlatformNodeWin::accSelect(LONG flagsSelect, VARIANT var_id) {
if (flagsSelect & SELFLAG_TAKEFOCUS) {
AXActionData action_data;
action_data.action = ax::mojom::Action::kFocus;
- target->delegate_->AccessibilityPerformAction(action_data);
+ target->GetDelegate()->AccessibilityPerformAction(action_data);
return S_OK;
}
@@ -1108,7 +1096,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_uniqueID(LONG* id) {
IFACEMETHODIMP AXPlatformNodeWin::get_windowHandle(HWND* window_handle) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_WINDOW_HANDLE);
COM_OBJECT_VALIDATE_1_ARG(window_handle);
- *window_handle = delegate_->GetTargetForNativeAccessibilityEvent();
+ *window_handle = GetDelegate()->GetTargetForNativeAccessibilityEvent();
return *window_handle ? S_OK : S_FALSE;
}
@@ -1159,7 +1147,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relationTargetsOfType(BSTR type_bstr,
base::string16 relation_type;
std::set<int32_t> target_ids;
int found = AXPlatformRelationWin::EnumerateRelationships(
- GetData(), delegate_, 0, type, &relation_type, &target_ids);
+ GetData(), GetDelegate(), 0, type, &relation_type, &target_ids);
if (found == 0)
return S_FALSE;
@@ -1173,8 +1161,8 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relationTargetsOfType(BSTR type_bstr,
*targets = static_cast<IUnknown**>(CoTaskMemAlloc(count * sizeof(IUnknown*)));
int index = 0;
for (int target_id : target_ids) {
- AXPlatformNodeWin* target =
- static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(target_id));
+ AXPlatformNodeWin* target = static_cast<AXPlatformNodeWin*>(
+ GetDelegate()->GetFromNodeID(target_id));
if (target) {
(*targets)[index] = static_cast<IAccessible*>(target);
(*targets)[index]->AddRef();
@@ -1221,7 +1209,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_nRelations(LONG* n_relations) {
AXPlatformNode::NotifyAddAXModeFlags(kScreenReaderAndHTMLAccessibilityModes);
int count = AXPlatformRelationWin::EnumerateRelationships(
- GetData(), delegate_, -1, base::string16(), nullptr, nullptr);
+ GetData(), GetDelegate(), -1, base::string16(), nullptr, nullptr);
*n_relations = count;
return S_OK;
}
@@ -1235,8 +1223,8 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relation(LONG relation_index,
base::string16 relation_type;
std::set<int32_t> targets;
int found = AXPlatformRelationWin::EnumerateRelationships(
- GetData(), delegate_, relation_index, base::string16(), &relation_type,
- &targets);
+ GetData(), GetDelegate(), relation_index, base::string16(),
+ &relation_type, &targets);
if (found == 0)
return E_INVALIDARG;
@@ -1246,8 +1234,8 @@ IFACEMETHODIMP AXPlatformNodeWin::get_relation(LONG relation_index,
relation_obj->AddRef();
relation_obj->Initialize(relation_type);
for (int target_id : targets) {
- AXPlatformNodeWin* target =
- static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(target_id));
+ AXPlatformNodeWin* target = static_cast<AXPlatformNodeWin*>(
+ GetDelegate()->GetFromNodeID(target_id));
if (!target)
continue;
relation_obj->AddTarget(target);
@@ -1327,7 +1315,7 @@ IFACEMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) {
// ax::mojom::Action::kScrollToMakeVisible wants a target rect in *local*
// coords.
- gfx::Rect r = gfx::ToEnclosingRect(GetData().location);
+ gfx::Rect r = gfx::ToEnclosingRect(GetData().relative_bounds.bounds);
r -= r.OffsetFromOrigin();
switch (scroll_type) {
case IA2_SCROLL_TYPE_TOP_LEFT:
@@ -1356,7 +1344,7 @@ IFACEMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) {
action_data.target_node_id = GetData().id;
action_data.action = ax::mojom::Action::kScrollToMakeVisible;
action_data.target_rect = r;
- delegate_->AccessibilityPerformAction(action_data);
+ GetDelegate()->AccessibilityPerformAction(action_data);
return S_OK;
}
@@ -1372,8 +1360,9 @@ IFACEMETHODIMP AXPlatformNodeWin::scrollToPoint(
if (coordinate_type == IA2_COORDTYPE_PARENT_RELATIVE) {
if (GetParent()) {
AXPlatformNodeBase* base = FromNativeViewAccessible(GetParent());
- scroll_to +=
- base->delegate_->GetUnclippedScreenBoundsRect().OffsetFromOrigin();
+ scroll_to += base->GetDelegate()
+ ->GetUnclippedScreenBoundsRect()
+ .OffsetFromOrigin();
}
} else if (coordinate_type != IA2_COORDTYPE_SCREEN_RELATIVE) {
return E_INVALIDARG;
@@ -1383,7 +1372,7 @@ IFACEMETHODIMP AXPlatformNodeWin::scrollToPoint(
action_data.target_node_id = GetData().id;
action_data.action = ax::mojom::Action::kScrollToPoint;
action_data.target_point = scroll_to;
- delegate_->AccessibilityPerformAction(action_data);
+ GetDelegate()->AccessibilityPerformAction(action_data);
return S_OK;
}
@@ -1449,7 +1438,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Collapse() {
AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
- if (delegate_->AccessibilityPerformAction(action_data))
+ if (GetDelegate()->AccessibilityPerformAction(action_data))
return S_OK;
return E_FAIL;
}
@@ -1458,7 +1447,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Expand() {
AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
- if (delegate_->AccessibilityPerformAction(action_data))
+ if (GetDelegate()->AccessibilityPerformAction(action_data))
return S_OK;
return E_FAIL;
}
@@ -1557,14 +1546,14 @@ IFACEMETHODIMP AXPlatformNodeWin::get_ColumnCount(int* result) {
IFACEMETHODIMP AXPlatformNodeWin::ScrollIntoView() {
COM_OBJECT_VALIDATE();
- gfx::Rect r = gfx::ToEnclosingRect(GetData().location);
+ gfx::Rect r = gfx::ToEnclosingRect(GetData().relative_bounds.bounds);
r -= r.OffsetFromOrigin();
AXActionData action_data;
action_data.target_node_id = GetData().id;
action_data.target_rect = r;
action_data.action = ax::mojom::Action::kScrollToMakeVisible;
- if (delegate_->AccessibilityPerformAction(action_data))
+ if (GetDelegate()->AccessibilityPerformAction(action_data))
return S_OK;
return E_FAIL;
}
@@ -1584,7 +1573,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Scroll(ScrollAmount horizontal_amount,
action_data.action = ax::mojom::Action::kSetScrollOffset;
action_data.target_point = gfx::PointAtOffsetFromOrigin(
CalculateUIAScrollPoint(horizontal_amount, vertical_amount));
- if (delegate_->AccessibilityPerformAction(action_data))
+ if (GetDelegate()->AccessibilityPerformAction(action_data))
return S_OK;
return E_FAIL;
}
@@ -1607,7 +1596,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetScrollPercent(double horizontal_percent,
action_data.target_node_id = GetData().id;
action_data.action = ax::mojom::Action::kSetScrollOffset;
action_data.target_point = scroll_to;
- if (delegate_->AccessibilityPerformAction(action_data))
+ if (GetDelegate()->AccessibilityPerformAction(action_data))
return S_OK;
return E_FAIL;
}
@@ -1641,7 +1630,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_HorizontalViewSize(double* result) {
return S_OK;
}
- gfx::RectF clipped_bounds(delegate_->GetClippedScreenBoundsRect());
+ gfx::RectF clipped_bounds(GetDelegate()->GetClippedScreenBoundsRect());
float x_min = GetIntAttribute(ax::mojom::IntAttribute::kScrollXMin);
float x_max = GetIntAttribute(ax::mojom::IntAttribute::kScrollXMax);
float total_width = clipped_bounds.width() + x_max - x_min;
@@ -1679,7 +1668,7 @@ IFACEMETHODIMP AXPlatformNodeWin::get_VerticalViewSize(double* result) {
return S_OK;
}
- gfx::RectF clipped_bounds(delegate_->GetClippedScreenBoundsRect());
+ gfx::RectF clipped_bounds(GetDelegate()->GetClippedScreenBoundsRect());
float y_min = GetIntAttribute(ax::mojom::IntAttribute::kScrollYMin);
float y_max = GetIntAttribute(ax::mojom::IntAttribute::kScrollYMax);
float total_height = clipped_bounds.height() + y_max - y_min;
@@ -1704,7 +1693,7 @@ IFACEMETHODIMP AXPlatformNodeWin::AddToSelection() {
AXActionData data;
data.action = ax::mojom::Action::kDoDefault;
- if (delegate_->AccessibilityPerformAction(data))
+ if (GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
}
@@ -1725,7 +1714,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Select() {
AXActionData data;
data.action = ax::mojom::Action::kDoDefault;
- if (delegate_->AccessibilityPerformAction(data))
+ if (GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
}
@@ -1763,11 +1752,11 @@ IFACEMETHODIMP AXPlatformNodeWin::get_SelectionContainer(
IFACEMETHODIMP AXPlatformNodeWin::GetSelection(SAFEARRAY** result) {
COM_OBJECT_VALIDATE_1_ARG(result);
- int child_count = delegate_->GetChildCount();
+ int child_count = GetDelegate()->GetChildCount();
*result = SafeArrayCreateVector(VT_UNKNOWN, 0, child_count);
for (LONG i = 0; i < child_count; ++i) {
auto* child = static_cast<AXPlatformNodeWin*>(
- FromNativeViewAccessible(delegate_->ChildAtIndex(i)));
+ FromNativeViewAccessible(GetDelegate()->ChildAtIndex(i)));
DCHECK(child);
child->AddRef();
SafeArrayPutElement(*result, &i,
@@ -1793,11 +1782,11 @@ IFACEMETHODIMP AXPlatformNodeWin::get_IsSelectionRequired(BOOL* result) {
IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaderItems(SAFEARRAY** result) {
COM_OBJECT_VALIDATE_1_ARG(result);
- if (!IsCellOrTableHeaderRole(GetData().role) || !GetTable())
+ if (!IsCellOrTableHeader(GetData().role) || !GetTable())
return E_FAIL;
std::vector<int32_t> column_header_ids =
- delegate_->GetColHeaderNodeIds(GetTableColumn());
+ GetDelegate()->GetColHeaderNodeIds(GetTableColumn());
if (column_header_ids.empty())
return S_FALSE;
*result = CreateUIAElementsArrayFromIdVector(column_header_ids);
@@ -1807,11 +1796,11 @@ IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaderItems(SAFEARRAY** result) {
IFACEMETHODIMP AXPlatformNodeWin::GetRowHeaderItems(SAFEARRAY** result) {
COM_OBJECT_VALIDATE_1_ARG(result);
- if (!IsCellOrTableHeaderRole(GetData().role) || !GetTable())
+ if (!IsCellOrTableHeader(GetData().role) || !GetTable())
return E_FAIL;
std::vector<int32_t> row_header_ids =
- delegate_->GetRowHeaderNodeIds(GetTableRow());
+ GetDelegate()->GetRowHeaderNodeIds(GetTableRow());
if (row_header_ids.empty())
return S_FALSE;
*result = CreateUIAElementsArrayFromIdVector(row_header_ids);
@@ -1828,7 +1817,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetColumnHeaders(SAFEARRAY** result) {
if (!GetTable())
return E_FAIL;
- std::vector<int32_t> column_header_ids = delegate_->GetColHeaderNodeIds();
+ std::vector<int32_t> column_header_ids = GetDelegate()->GetColHeaderNodeIds();
*result = CreateUIAElementsArrayFromIdVector(column_header_ids);
return S_OK;
}
@@ -1839,7 +1828,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetRowHeaders(SAFEARRAY** result) {
if (!GetTable())
return E_FAIL;
- std::vector<int32_t> row_header_ids = delegate_->GetRowHeaderNodeIds();
+ std::vector<int32_t> row_header_ids = GetDelegate()->GetRowHeaderNodeIds();
*result = CreateUIAElementsArrayFromIdVector(row_header_ids);
return S_OK;
}
@@ -1858,7 +1847,7 @@ IFACEMETHODIMP AXPlatformNodeWin::Toggle() {
AXActionData action_data;
action_data.action = ax::mojom::Action::kDoDefault;
- if (delegate_->AccessibilityPerformAction(action_data))
+ if (GetDelegate()->AccessibilityPerformAction(action_data))
return S_OK;
return E_FAIL;
}
@@ -1887,7 +1876,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetValue(LPCWSTR value) {
AXActionData data;
data.action = ax::mojom::Action::kSetValue;
data.value = base::WideToUTF8(value);
- if (delegate_->AccessibilityPerformAction(data))
+ if (GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
}
@@ -1918,7 +1907,7 @@ IFACEMETHODIMP AXPlatformNodeWin::SetValue(double value) {
AXActionData data;
data.action = ax::mojom::Action::kSetValue;
data.value = base::NumberToString(value);
- if (delegate_->AccessibilityPerformAction(data))
+ if (GetDelegate()->AccessibilityPerformAction(data))
return S_OK;
return E_FAIL;
}
@@ -3144,14 +3133,14 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPatternProvider(PATTERNID pattern_id,
break;
case UIA_GridPatternId:
- if (IsTableLikeRole(data.role)) {
+ if (IsTableLike(data.role)) {
AddRef();
*result = static_cast<IGridProvider*>(this);
}
break;
case UIA_GridItemPatternId:
- if (IsCellOrTableHeaderRole(data.role)) {
+ if (IsCellOrTableHeader(data.role)) {
AddRef();
*result = static_cast<IGridItemProvider*>(this);
}
@@ -3177,14 +3166,14 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPatternProvider(PATTERNID pattern_id,
break;
case UIA_TablePatternId:
- if (IsTableLikeRole(data.role)) {
+ if (IsTableLike(data.role)) {
AddRef();
*result = static_cast<ITableProvider*>(this);
}
break;
case UIA_TableItemPatternId:
- if (IsCellOrTableHeaderRole(data.role)) {
+ if (IsCellOrTableHeader(data.role)) {
AddRef();
*result = static_cast<ITableItemProvider*>(this);
}
@@ -3205,7 +3194,7 @@ IFACEMETHODIMP AXPlatformNodeWin::GetPatternProvider(PATTERNID pattern_id,
break;
case UIA_SelectionPatternId:
- if (IsContainerWithSelectableChildrenRole(data.role)) {
+ if (IsContainerWithSelectableChildren(data.role)) {
AddRef();
*result = static_cast<ISelectionProvider*>(this);
}
@@ -3633,7 +3622,7 @@ int AXPlatformNodeWin::MSAARole() {
return ROLE_SYSTEM_DOCUMENT;
case ax::mojom::Role::kEmbeddedObject:
- if (delegate_->GetChildCount()) {
+ if (GetDelegate()->GetChildCount()) {
return ROLE_SYSTEM_GROUPING;
} else {
return ROLE_SYSTEM_CLIENT;
@@ -4032,7 +4021,8 @@ int32_t AXPlatformNodeWin::ComputeIA2State() {
} else {
ia2_state |= IA2_STATE_SINGLE_LINE;
}
- ia2_state |= IA2_STATE_SELECTABLE_TEXT;
+ if (!IsInvisibleOrIgnored())
+ ia2_state |= IA2_STATE_SELECTABLE_TEXT;
}
// TODO(crbug.com/865101) Use
@@ -4154,7 +4144,7 @@ int32_t AXPlatformNodeWin::ComputeIA2Role() {
ia2_role = IA2_ROLE_FOOTNOTE;
break;
case ax::mojom::Role::kEmbeddedObject:
- if (!delegate_->GetChildCount()) {
+ if (!GetDelegate()->GetChildCount()) {
ia2_role = IA2_ROLE_EMBEDDED_OBJECT;
}
break;
@@ -4426,7 +4416,7 @@ base::string16 AXPlatformNodeWin::UIAAriaRole() {
return L"document";
case ax::mojom::Role::kEmbeddedObject:
- if (delegate_->GetChildCount()) {
+ if (GetDelegate()->GetChildCount()) {
return L"group";
} else {
return L"document";
@@ -4811,10 +4801,8 @@ base::string16 AXPlatformNodeWin::ComputeUIAProperties() {
properties.push_back(L"haspopup=true");
}
- if (data.HasState(ax::mojom::State::kInvisible) ||
- GetData().role == ax::mojom::Role::kIgnored) {
+ if (IsInvisibleOrIgnored())
properties.push_back(L"hidden=true");
- }
if (HasIntAttribute(ax::mojom::IntAttribute::kInvalidState) &&
GetIntAttribute(ax::mojom::IntAttribute::kInvalidState) !=
@@ -5049,7 +5037,7 @@ LONG AXPlatformNodeWin::ComputeUIAControlType() { // NOLINT(runtime/int)
return UIA_DocumentControlTypeId;
case ax::mojom::Role::kEmbeddedObject:
- if (delegate_->GetChildCount()) {
+ if (GetDelegate()->GetChildCount()) {
return UIA_GroupControlTypeId;
} else {
return UIA_DocumentControlTypeId;
@@ -5464,16 +5452,15 @@ int AXPlatformNodeWin::MSAAState() {
// Expose whether or not the mouse is over an element, but suppress
// this for tests because it can make the test results flaky depending
// on the position of the mouse.
- if (delegate_->ShouldIgnoreHoveredStateForTesting())
+ if (GetDelegate()->ShouldIgnoreHoveredStateForTesting())
msaa_state |= STATE_SYSTEM_HOTTRACKED;
}
// If the role is IGNORED, we want these elements to be invisible so that
// these nodes are hidden from the screen reader.
- if (data.HasState(ax::mojom::State::kInvisible) ||
- GetData().role == ax::mojom::Role::kIgnored) {
+ if (IsInvisibleOrIgnored())
msaa_state |= STATE_SYSTEM_INVISIBLE;
- }
+
if (data.HasState(ax::mojom::State::kLinked))
msaa_state |= STATE_SYSTEM_LINKED;
@@ -5484,7 +5471,7 @@ int AXPlatformNodeWin::MSAAState() {
msaa_state |= STATE_SYSTEM_MULTISELECTABLE;
}
- if (delegate_->IsOffscreen())
+ if (GetDelegate()->IsOffscreen())
msaa_state |= STATE_SYSTEM_OFFSCREEN;
if (data.HasState(ax::mojom::State::kProtected))
@@ -5552,7 +5539,7 @@ int AXPlatformNodeWin::MSAAState() {
//
// Handle STATE_SYSTEM_FOCUSED
//
- gfx::NativeViewAccessible focus = delegate_->GetFocus();
+ gfx::NativeViewAccessible focus = GetDelegate()->GetFocus();
if (focus == GetNativeViewAccessible())
msaa_state |= STATE_SYSTEM_FOCUSED;
@@ -5718,11 +5705,11 @@ AXPlatformNodeWin* AXPlatformNodeWin::GetTargetFromChildID(
if (child_id == CHILDID_SELF)
return this;
- if (child_id >= 1 && child_id <= delegate_->GetChildCount()) {
+ if (child_id >= 1 && child_id <= GetDelegate()->GetChildCount()) {
// Positive child ids are a 1-based child index, used by clients
// that want to enumerate all immediate children.
AXPlatformNodeBase* base =
- FromNativeViewAccessible(delegate_->ChildAtIndex(child_id - 1));
+ FromNativeViewAccessible(GetDelegate()->ChildAtIndex(child_id - 1));
return static_cast<AXPlatformNodeWin*>(base);
}
@@ -5847,13 +5834,13 @@ int32_t AXPlatformNodeWin::GetHypertextOffsetFromChild(
// cross-tree traversal is necessary.
if (child->IsTextOnlyObject()) {
int32_t hypertext_offset = 0;
- int32_t index_in_parent = child->delegate_->GetIndexInParent();
+ int32_t index_in_parent = child->GetDelegate()->GetIndexInParent();
DCHECK_GE(index_in_parent, 0);
DCHECK_LT(index_in_parent,
- static_cast<int32_t>(delegate_->GetChildCount()));
+ static_cast<int32_t>(GetDelegate()->GetChildCount()));
for (uint32_t i = 0; i < static_cast<uint32_t>(index_in_parent); ++i) {
auto* sibling = static_cast<AXPlatformNodeWin*>(
- FromNativeViewAccessible(delegate_->ChildAtIndex(i)));
+ FromNativeViewAccessible(GetDelegate()->ChildAtIndex(i)));
DCHECK(sibling);
if (sibling->IsTextOnlyObject())
hypertext_offset += (int32_t)sibling->GetTextAsString16().size();
@@ -5873,7 +5860,7 @@ int32_t AXPlatformNodeWin::GetHypertextOffsetFromChild(
int32_t AXPlatformNodeWin::GetHypertextOffsetFromDescendant(
AXPlatformNodeWin* descendant) {
auto* parent_object = static_cast<AXPlatformNodeWin*>(
- FromNativeViewAccessible(descendant->delegate_->GetParent()));
+ FromNativeViewAccessible(descendant->GetDelegate()->GetParent()));
while (parent_object && parent_object != this) {
descendant = parent_object;
parent_object = static_cast<AXPlatformNodeWin*>(
@@ -5905,9 +5892,9 @@ int AXPlatformNodeWin::GetHypertextOffsetFromEndpoint(
return endpoint_offset;
AXPlatformNodeWin* common_parent = this;
- int32_t index_in_common_parent = delegate_->GetIndexInParent();
+ int32_t index_in_common_parent = GetDelegate()->GetIndexInParent();
while (common_parent && !endpoint_object->IsDescendantOf(common_parent)) {
- index_in_common_parent = common_parent->delegate_->GetIndexInParent();
+ index_in_common_parent = common_parent->GetDelegate()->GetIndexInParent();
common_parent = static_cast<AXPlatformNodeWin*>(
FromNativeViewAccessible(common_parent->GetParent()));
}
@@ -5939,12 +5926,13 @@ int AXPlatformNodeWin::GetHypertextOffsetFromEndpoint(
// We can safely assume that the endpoint is in another part of the tree or
// at common parent, and that this object is a descendant of common parent.
int32_t endpoint_index_in_common_parent = -1;
- for (int i = 0; i < common_parent->delegate_->GetChildCount(); ++i) {
+ for (int i = 0; i < common_parent->GetDelegate()->GetChildCount(); ++i) {
auto* child = static_cast<AXPlatformNodeWin*>(
- common_parent->delegate_->ChildAtIndex(i));
+ common_parent->GetDelegate()->ChildAtIndex(i));
DCHECK(child);
if (endpoint_object->IsDescendantOf(child)) {
- endpoint_index_in_common_parent = child->delegate_->GetIndexInParent();
+ endpoint_index_in_common_parent =
+ child->GetDelegate()->GetIndexInParent();
break;
}
}
@@ -6074,24 +6062,24 @@ void AXPlatformNodeWin::ComputeHypertextRemovedAndInserted(size_t* start,
}
int AXPlatformNodeWin::GetSelectionAnchor() {
- int32_t anchor_id = delegate_->GetTreeData().sel_anchor_object_id;
+ int32_t anchor_id = GetDelegate()->GetTreeData().sel_anchor_object_id;
AXPlatformNodeWin* anchor_object =
- static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(anchor_id));
+ static_cast<AXPlatformNodeWin*>(GetDelegate()->GetFromNodeID(anchor_id));
if (!anchor_object)
return -1;
- int anchor_offset = delegate_->GetTreeData().sel_anchor_offset;
+ int anchor_offset = GetDelegate()->GetTreeData().sel_anchor_offset;
return GetHypertextOffsetFromEndpoint(anchor_object, anchor_offset);
}
int AXPlatformNodeWin::GetSelectionFocus() {
- int32_t focus_id = delegate_->GetTreeData().sel_focus_object_id;
+ int32_t focus_id = GetDelegate()->GetTreeData().sel_focus_object_id;
AXPlatformNodeWin* focus_object =
- static_cast<AXPlatformNodeWin*>(delegate_->GetFromNodeID(focus_id));
+ static_cast<AXPlatformNodeWin*>(GetDelegate()->GetFromNodeID(focus_id));
if (!focus_object)
return -1;
- int focus_offset = delegate_->GetTreeData().sel_focus_offset;
+ int focus_offset = GetDelegate()->GetTreeData().sel_focus_offset;
return GetHypertextOffsetFromEndpoint(focus_object, focus_offset);
}
diff --git a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index c47d1f46940..c1e61563ecc 100644
--- a/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -156,16 +156,16 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleHitTest) {
root.id = 0;
root.child_ids.push_back(1);
root.child_ids.push_back(2);
- root.location = gfx::RectF(0, 0, 30, 30);
+ root.relative_bounds.bounds = gfx::RectF(0, 0, 30, 30);
AXNodeData node1;
node1.id = 1;
- node1.location = gfx::RectF(0, 0, 10, 10);
+ node1.relative_bounds.bounds = gfx::RectF(0, 0, 10, 10);
node1.SetName("Name1");
AXNodeData node2;
node2.id = 2;
- node2.location = gfx::RectF(20, 20, 10, 10);
+ node2.relative_bounds.bounds = gfx::RectF(20, 20, 10, 10);
node2.SetName("Name2");
Init(root, node1, node2);
@@ -644,7 +644,7 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessibleRole) {
TEST_F(AXPlatformNodeWinTest, TestIAccessibleLocation) {
AXNodeData root;
root.id = 1;
- root.location = gfx::RectF(10, 40, 800, 600);
+ root.relative_bounds.bounds = gfx::RectF(10, 40, 800, 600);
Init(root);
TestAXNodeWrapper::SetGlobalCoordinateOffset(gfx::Vector2d(100, 200));
@@ -1005,12 +1005,12 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollToPoint) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
- root.location = gfx::RectF(0, 0, 2000, 2000);
+ root.relative_bounds.bounds = gfx::RectF(0, 0, 2000, 2000);
AXNodeData child1;
child1.id = 2;
child1.role = ax::mojom::Role::kStaticText;
- child1.location = gfx::RectF(10, 10, 10, 10);
+ child1.relative_bounds.bounds = gfx::RectF(10, 10, 10, 10);
root.child_ids.push_back(2);
Init(root, child1);
@@ -1057,12 +1057,12 @@ TEST_F(AXPlatformNodeWinTest, TestIAccessible2ScrollTo) {
AXNodeData root;
root.id = 1;
root.role = ax::mojom::Role::kRootWebArea;
- root.location = gfx::RectF(0, 0, 2000, 2000);
+ root.relative_bounds.bounds = gfx::RectF(0, 0, 2000, 2000);
AXNodeData child1;
child1.id = 2;
child1.role = ax::mojom::Role::kStaticText;
- child1.location = gfx::RectF(10, 10, 10, 10);
+ child1.relative_bounds.bounds = gfx::RectF(10, 10, 10, 10);
root.child_ids.push_back(2);
Init(root, child1);
diff --git a/chromium/ui/accessibility/platform/ax_system_caret_win.cc b/chromium/ui/accessibility/platform/ax_system_caret_win.cc
index dd91704c713..e8f28e71443 100644
--- a/chromium/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/chromium/ui/accessibility/platform/ax_system_caret_win.cc
@@ -27,7 +27,7 @@ AXSystemCaretWin::AXSystemCaretWin(gfx::AcceleratedWidget event_target)
data_.AddState(ax::mojom::State::kInvisible);
// According to MSDN, "Edit" should be the name of the caret object.
data_.SetName(L"Edit");
- data_.offset_container_id = -1;
+ data_.relative_bounds.offset_container_id = -1;
if (event_target_) {
::NotifyWinEvent(EVENT_OBJECT_CREATE, event_target_, OBJID_CARET,
@@ -74,8 +74,8 @@ void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds) {
gfx::RectF new_location(bounds);
// Avoid redundant caret move events (if the location stays the same), but
// always fire when it's made visible again.
- if (data_.location != new_location || newly_visible) {
- data_.location = new_location;
+ if (data_.relative_bounds.bounds != new_location || newly_visible) {
+ data_.relative_bounds.bounds = new_location;
::NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
}
@@ -84,7 +84,7 @@ void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds) {
void AXSystemCaretWin::Hide() {
if (!data_.HasState(ax::mojom::State::kInvisible)) {
data_.AddState(ax::mojom::State::kInvisible);
- data_.location.set_width(0);
+ data_.relative_bounds.bounds.set_width(0);
if (event_target_) {
::NotifyWinEvent(EVENT_OBJECT_HIDE, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
@@ -111,11 +111,11 @@ gfx::NativeViewAccessible AXSystemCaretWin::GetParent() {
gfx::Rect AXSystemCaretWin::GetClippedScreenBoundsRect() const {
// We could optionally add clipping here if ever needed.
- return ToEnclosingRect(data_.location);
+ return ToEnclosingRect(data_.relative_bounds.bounds);
}
gfx::Rect AXSystemCaretWin::GetUnclippedScreenBoundsRect() const {
- return ToEnclosingRect(data_.location);
+ return ToEnclosingRect(data_.relative_bounds.bounds);
}
gfx::AcceleratedWidget
diff --git a/chromium/ui/accessibility/platform/ax_unique_id.cc b/chromium/ui/accessibility/platform/ax_unique_id.cc
index 06282f6d3ba..852371c160e 100644
--- a/chromium/ui/accessibility/platform/ax_unique_id.cc
+++ b/chromium/ui/accessibility/platform/ax_unique_id.cc
@@ -8,6 +8,7 @@
#include <unordered_set>
#include "base/lazy_instance.h"
+#include "base/stl_util.h"
namespace ui {
@@ -18,6 +19,8 @@ base::LazyInstance<std::unordered_set<int32_t>>::Leaky g_assigned_ids =
} // namespace
+AXUniqueId::AXUniqueId() : AXUniqueId(INT32_MAX) {}
+
AXUniqueId::AXUniqueId(const int32_t max_id) : id_(GetNextAXUniqueId(max_id)) {}
AXUniqueId::~AXUniqueId() {
@@ -32,9 +35,8 @@ bool AXUniqueId::operator!=(const AXUniqueId& other) const {
return !(*this == other);
}
-bool AXUniqueId::IsAssigned(int32_t id) const {
- auto id_map = g_assigned_ids.Get();
- return id_map.find(id) != id_map.end();
+bool AXUniqueId::IsAssigned(const int32_t id) const {
+ return base::ContainsKey(g_assigned_ids.Get(), id);
}
int32_t AXUniqueId::GetNextAXUniqueId(const int32_t max_id) {
@@ -42,22 +44,23 @@ int32_t AXUniqueId::GetNextAXUniqueId(const int32_t max_id) {
static bool has_wrapped = false;
const int32_t prev_id = current_id;
-
- while (true) {
+ do {
if (current_id == max_id) {
current_id = 1;
has_wrapped = true;
} else {
- current_id++;
+ ++current_id;
}
- if (current_id == prev_id)
- LOG(FATAL) << "Over 2 billion active ids, something is wrong.";
- if (!has_wrapped || !IsAssigned(current_id))
- break;
- }
+ if (current_id == prev_id) {
+ LOG(FATAL) << "There are over 2 billion available IDs, so the newly "
+ "created ID cannot be equal to the most recently created "
+ "ID.";
+ }
+ // If it |has_wrapped| then we need to continue until we find the first
+ // unassigned ID.
+ } while (has_wrapped && IsAssigned(current_id));
g_assigned_ids.Get().insert(current_id);
-
return current_id;
}
diff --git a/chromium/ui/accessibility/platform/ax_unique_id.h b/chromium/ui/accessibility/platform/ax_unique_id.h
index f0c20fcba0c..0f3853fe104 100644
--- a/chromium/ui/accessibility/platform/ax_unique_id.h
+++ b/chromium/ui/accessibility/platform/ax_unique_id.h
@@ -17,17 +17,18 @@ namespace ui {
// is required to generate the ID, and the ID is freed when the AXUniqueID is
// destroyed.
//
-// The unique id that's guaranteed to be a positive number. Becase some
+// The unique id that's guaranteed to be a positive number. Because some
// platforms want to negate it, we ensure the range is below the signed int max.
//
// These ids must not be conflated with the int id, that comes with web node
// data, which are only unique within their source frame.
class AX_EXPORT AXUniqueId {
public:
- AXUniqueId() : AXUniqueId(INT32_MAX) {}
- ~AXUniqueId();
+ AXUniqueId();
+ virtual ~AXUniqueId();
int32_t Get() const { return id_; }
+ operator int32_t() const { return id_; }
bool operator==(const AXUniqueId& other) const;
bool operator!=(const AXUniqueId& other) const;
diff --git a/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc b/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc
index 4baafaefa15..d6fdb5886ed 100644
--- a/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc
+++ b/chromium/ui/accessibility/platform/ax_unique_id_unittest.cc
@@ -21,11 +21,15 @@ static const int32_t kMaxId = 100;
class AXTestSmallBankUniqueId : public AXUniqueId {
public:
AXTestSmallBankUniqueId();
+ ~AXTestSmallBankUniqueId() override;
+ private:
friend class AXUniqueId;
+ DISALLOW_COPY_AND_ASSIGN(AXTestSmallBankUniqueId);
};
AXTestSmallBankUniqueId::AXTestSmallBankUniqueId() : AXUniqueId(kMaxId) {}
+AXTestSmallBankUniqueId::~AXTestSmallBankUniqueId() = default;
TEST(AXPlatformUniqueIdTest, UnassignedIdsAreReused) {
// Create a bank of ids that uses up all available ids.
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
index 9f7c731a40c..c8481e78cf7 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -106,13 +106,13 @@ gfx::NativeViewAccessible TestAXNodeWrapper::ChildAtIndex(int index) {
gfx::Rect TestAXNodeWrapper::GetClippedScreenBoundsRect() const {
// We could add clipping here if needed.
- gfx::RectF bounds = GetData().location;
+ gfx::RectF bounds = GetData().relative_bounds.bounds;
bounds.Offset(g_offset);
return gfx::ToEnclosingRect(bounds);
}
gfx::Rect TestAXNodeWrapper::GetUnclippedScreenBoundsRect() const {
- gfx::RectF bounds = GetData().location;
+ gfx::RectF bounds = GetData().relative_bounds.bounds;
bounds.Offset(g_offset);
return gfx::ToEnclosingRect(bounds);
}
@@ -195,108 +195,57 @@ void TestAXNodeWrapper::ReplaceIntAttribute(int32_t node_id,
}
int TestAXNodeWrapper::GetTableRowCount() const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return 0;
-
- return table_info->row_count;
+ return node_->GetTableRowCount();
}
int TestAXNodeWrapper::GetTableColCount() const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return 0;
-
- return table_info->col_count;
+ return node_->GetTableColCount();
}
-std::vector<int32_t> TestAXNodeWrapper::GetColHeaderNodeIds() const {
- ui::AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return std::vector<int32_t>();
-
- std::vector<std::vector<int32_t>> headers = table_info->col_headers;
- std::vector<int32_t> all_ids;
- for (const auto col_ids : headers) {
- all_ids.insert(all_ids.end(), col_ids.begin(), col_ids.end());
- }
-
- return all_ids;
+const std::vector<int32_t> TestAXNodeWrapper::GetColHeaderNodeIds() const {
+ std::vector<int32_t> header_ids;
+ node_->GetTableCellColHeaderNodeIds(&header_ids);
+ return header_ids;
}
-std::vector<int32_t> TestAXNodeWrapper::GetColHeaderNodeIds(
+const std::vector<int32_t> TestAXNodeWrapper::GetColHeaderNodeIds(
int32_t col_index) const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return std::vector<int32_t>();
-
- if (col_index < 0 || col_index >= table_info->col_count)
- return std::vector<int32_t>();
-
- return table_info->col_headers[col_index];
+ std::vector<int32_t> header_ids;
+ node_->GetTableColHeaderNodeIds(col_index, &header_ids);
+ return header_ids;
}
-std::vector<int32_t> TestAXNodeWrapper::GetRowHeaderNodeIds() const {
- ui::AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return std::vector<int32_t>();
-
- std::vector<std::vector<int32_t>> headers = table_info->row_headers;
- std::vector<int32_t> all_ids;
- for (const auto col_ids : headers) {
- all_ids.insert(all_ids.end(), col_ids.begin(), col_ids.end());
- }
-
- return all_ids;
+const std::vector<int32_t> TestAXNodeWrapper::GetRowHeaderNodeIds() const {
+ std::vector<int32_t> header_ids;
+ node_->GetTableCellRowHeaderNodeIds(&header_ids);
+ return header_ids;
}
-std::vector<int32_t> TestAXNodeWrapper::GetRowHeaderNodeIds(
+const std::vector<int32_t> TestAXNodeWrapper::GetRowHeaderNodeIds(
int32_t row_index) const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return std::vector<int32_t>();
-
- if (row_index < 0 || row_index >= table_info->row_count)
- return std::vector<int32_t>();
-
- return table_info->row_headers[row_index];
+ std::vector<int32_t> header_ids;
+ node_->GetTableRowHeaderNodeIds(row_index, &header_ids);
+ return header_ids;
}
int32_t TestAXNodeWrapper::GetCellId(int32_t row_index,
int32_t col_index) const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return -1;
-
- if (row_index < 0 || row_index >= table_info->row_count || col_index < 0 ||
- col_index >= table_info->col_count)
- return -1;
+ ui::AXNode* cell = node_->GetTableCellFromCoords(row_index, col_index);
+ if (cell)
+ return cell->id();
- return table_info->cell_ids[row_index][col_index];
+ return -1;
}
-int32_t TestAXNodeWrapper::CellIdToIndex(int32_t cell_id) const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return 0;
-
- const auto& iter = table_info->cell_id_to_index.find(cell_id);
- if (iter != table_info->cell_id_to_index.end())
- return iter->second;
-
- return -1;
+int32_t TestAXNodeWrapper::GetTableCellIndex() const {
+ return node_->GetTableCellIndex();
}
int32_t TestAXNodeWrapper::CellIndexToId(int32_t cell_index) const {
- AXTableInfo* table_info = tree_->GetTableInfo(node_);
- if (!table_info)
- return -1;
-
- if (cell_index < 0 ||
- cell_index >= static_cast<int32_t>(table_info->unique_cell_ids.size()))
- return -1;
-
- return table_info->unique_cell_ids[cell_index];
+ ui::AXNode* cell = node_->GetTableCellFromIndex(cell_index);
+ if (cell)
+ return cell->id();
+ return -1;
}
bool TestAXNodeWrapper::AccessibilityPerformAction(
@@ -307,7 +256,7 @@ bool TestAXNodeWrapper::AccessibilityPerformAction(
}
if (data.action == ax::mojom::Action::kScrollToMakeVisible) {
- auto offset = node_->data().location.OffsetFromOrigin();
+ auto offset = node_->data().relative_bounds.bounds.OffsetFromOrigin();
g_offset = gfx::Vector2d(-offset.x(), -offset.y());
return true;
}
diff --git a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
index 8ca26aa733a..7ac7d2fcf37 100644
--- a/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
+++ b/chromium/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -43,12 +43,14 @@ class TestAXNodeWrapper : public AXPlatformNodeDelegateBase {
int GetIndexInParent() const override;
int GetTableRowCount() const override;
int GetTableColCount() const override;
- std::vector<int32_t> GetColHeaderNodeIds() const override;
- std::vector<int32_t> GetColHeaderNodeIds(int32_t col_index) const override;
- std::vector<int32_t> GetRowHeaderNodeIds() const override;
- std::vector<int32_t> GetRowHeaderNodeIds(int32_t row_index) const override;
+ const std::vector<int32_t> GetColHeaderNodeIds() const override;
+ const std::vector<int32_t> GetColHeaderNodeIds(
+ int32_t col_index) const override;
+ const std::vector<int32_t> GetRowHeaderNodeIds() const override;
+ const std::vector<int32_t> GetRowHeaderNodeIds(
+ int32_t row_index) const override;
int32_t GetCellId(int32_t row_index, int32_t col_index) const override;
- int32_t CellIdToIndex(int32_t cell_id) const override;
+ int32_t GetTableCellIndex() const override;
int32_t CellIndexToId(int32_t cell_index) const override;
bool AccessibilityPerformAction(const AXActionData& data) override;
bool ShouldIgnoreHoveredStateForTesting() override;
diff --git a/chromium/ui/android/BUILD.gn b/chromium/ui/android/BUILD.gn
index b641523e27c..aedd969fc22 100644
--- a/chromium/ui/android/BUILD.gn
+++ b/chromium/ui/android/BUILD.gn
@@ -109,7 +109,7 @@ java_cpp_enum("java_enums_srcjar") {
sources = [
"../base/ime/text_input_type.h",
"../base/page_transition_types.h",
- "../base/touch/touch_device.h",
+ "../base/pointer/pointer_device.h",
"../base/ui_base_types.h",
"../events/android/gesture_event_type.h",
"../gfx/android/java_bitmap.h",
@@ -260,6 +260,7 @@ android_library("ui_full_java") {
"java/src/org/chromium/ui/ViewProvider.java",
"java/src/org/chromium/ui/VSyncMonitor.java",
"java/src/org/chromium/ui/base/ActivityAndroidPermissionDelegate.java",
+ "java/src/org/chromium/ui/base/ActivityKeyboardVisibilityDelegate.java",
"java/src/org/chromium/ui/base/ActivityWindowAndroid.java",
"java/src/org/chromium/ui/base/AndroidPermissionDelegate.java",
"java/src/org/chromium/ui/base/Clipboard.java",
@@ -311,8 +312,11 @@ android_library("ui_full_java") {
"java/src/org/chromium/ui/widget/ButtonCompat.java",
"java/src/org/chromium/ui/widget/CheckableImageView.java",
"java/src/org/chromium/ui/widget/ChromeBulletSpan.java",
+ "java/src/org/chromium/ui/widget/ChromeImageView.java",
+ "java/src/org/chromium/ui/widget/ChromeImageButton.java",
"java/src/org/chromium/ui/widget/OptimizedFrameLayout.java",
"java/src/org/chromium/ui/widget/RectProvider.java",
+ "java/src/org/chromium/ui/widget/RippleBackgroundHelper.java",
"java/src/org/chromium/ui/widget/RoundedCornerImageView.java",
"java/src/org/chromium/ui/widget/TextViewWithClickableSpans.java",
"java/src/org/chromium/ui/widget/TextViewWithLeading.java",
@@ -359,6 +363,7 @@ junit_binary("ui_junit_tests") {
"junit/src/org/chromium/ui/AsyncViewStubTest.java",
"junit/src/org/chromium/ui/AsyncViewProviderTest.java",
"junit/src/org/chromium/ui/base/ClipboardTest.java",
+ "junit/src/org/chromium/ui/base/LocalizationUtilsTest.java",
"junit/src/org/chromium/ui/base/SelectFileDialogTest.java",
"junit/src/org/chromium/ui/drawable/StateListDrawableBuilderTest.java",
"junit/src/org/chromium/ui/text/SpanApplierTest.java",
diff --git a/chromium/ui/android/delegated_frame_host_android.cc b/chromium/ui/android/delegated_frame_host_android.cc
index ec85b8eedbe..78c270fb4b0 100644
--- a/chromium/ui/android/delegated_frame_host_android.cc
+++ b/chromium/ui/android/delegated_frame_host_android.cc
@@ -35,8 +35,8 @@ scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer(
bool surface_opaque) {
// manager must outlive compositors using it.
auto layer = cc::SurfaceLayer::Create();
- layer->SetPrimarySurfaceId(primary_surface_id, deadline_policy);
- layer->SetFallbackSurfaceId(fallback_surface_id);
+ layer->SetSurfaceId(primary_surface_id, deadline_policy);
+ layer->SetOldestAcceptableFallback(fallback_surface_id);
layer->SetBounds(size_in_pixels);
layer->SetIsDrawable(true);
layer->SetContentsOpaque(surface_opaque);
@@ -73,7 +73,8 @@ DelegatedFrameHostAndroid::DelegatedFrameHostAndroid(
view_->GetLayer()->AddChild(content_layer_);
}
- host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
+ host_frame_sink_manager_->RegisterFrameSinkId(
+ frame_sink_id_, this, viz::ReportFirstSurfaceActivation::kNo);
host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_,
"DelegatedFrameHostAndroid");
CreateCompositorFrameSinkSupport();
@@ -92,14 +93,14 @@ void DelegatedFrameHostAndroid::SubmitCompositorFrame(
base::Optional<viz::HitTestRegionList> hit_test_region_list) {
DCHECK(!enable_viz_);
+ bool id_changed = (local_surface_id_ != local_surface_id);
viz::RenderPass* root_pass = frame.render_pass_list.back().get();
const bool has_transparent_background = root_pass->has_transparent_background;
- const gfx::Size pending_surface_size_in_pixels = frame.size_in_pixels();
+ const gfx::Size surface_size_in_pixels = frame.size_in_pixels();
// Reset |content_layer_| only if surface-sync is not used. When surface-sync
// is turned on, |content_layer_| is updated with the appropriate states (see
// in EmbedSurface()) instead of being recreated.
- if (!enable_surface_synchronization_ && content_layer_ &&
- active_local_surface_id_ != local_surface_id) {
+ if (!enable_surface_synchronization_ && content_layer_ && id_changed) {
EvictDelegatedFrame();
}
support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
@@ -110,15 +111,14 @@ void DelegatedFrameHostAndroid::SubmitCompositorFrame(
}
if (!content_layer_) {
- active_local_surface_id_ = local_surface_id;
- pending_local_surface_id_ = active_local_surface_id_;
- pending_surface_size_in_pixels_ = pending_surface_size_in_pixels;
+ local_surface_id_ = local_surface_id;
+ surface_size_in_pixels_ = surface_size_in_pixels;
has_transparent_background_ = has_transparent_background;
content_layer_ = CreateSurfaceLayer(
- viz::SurfaceId(frame_sink_id_, active_local_surface_id_),
- viz::SurfaceId(frame_sink_id_, active_local_surface_id_),
- pending_surface_size_in_pixels_,
- cc::DeadlinePolicy::UseDefaultDeadline(), !has_transparent_background_);
+ viz::SurfaceId(frame_sink_id_, local_surface_id_),
+ viz::SurfaceId(frame_sink_id_, local_surface_id_),
+ surface_size_in_pixels_, cc::DeadlinePolicy::UseDefaultDeadline(),
+ !has_transparent_background_);
view_->GetLayer()->AddChild(content_layer_);
}
content_layer_->SetContentsOpaque(!has_transparent_background_);
@@ -131,7 +131,8 @@ void DelegatedFrameHostAndroid::SubmitCompositorFrame(
if (content_layer_->bounds() == expected_pixel_size_)
compositor_pending_resize_lock_.reset();
- frame_evictor_->SwappedFrame(frame_evictor_->visible());
+ if (id_changed)
+ frame_evictor_->OnNewSurfaceEmbedded();
}
void DelegatedFrameHostAndroid::DidNotProduceFrame(
@@ -162,41 +163,37 @@ void DelegatedFrameHostAndroid::CopyFromCompositingSurface(
if (!src_subrect.IsEmpty())
request->set_area(src_subrect);
- if (!output_size.IsEmpty())
+ if (!output_size.IsEmpty()) {
+ // The CopyOutputRequest API does not allow fixing the output size. Instead
+ // we have the set area and scale in such a way that it would result in the
+ // desired output size.
+ if (!request->has_area())
+ request->set_area(gfx::Rect(surface_size_in_pixels_));
request->set_result_selection(gfx::Rect(output_size));
-
- if (!request->has_area())
- request->set_area(gfx::Rect(pending_surface_size_in_pixels_));
-
- if (request->has_result_selection()) {
const gfx::Rect& area = request->area();
- const gfx::Rect& result_selection = request->result_selection();
- if (area.IsEmpty() || result_selection.IsEmpty()) {
- // Viz would normally return an empty result for an empty selection.
- // However, this guard here is still necessary to protect against setting
- // an illegal scaling ratio.
+ // Viz would normally return an empty result for an empty area.
+ // However, this guard here is still necessary to protect against setting
+ // an illegal scaling ratio.
+ if (area.IsEmpty())
return;
- }
request->SetScaleRatio(
gfx::Vector2d(area.width(), area.height()),
- gfx::Vector2d(result_selection.width(), result_selection.height()));
+ gfx::Vector2d(output_size.width(), output_size.height()));
}
host_frame_sink_manager_->RequestCopyOfOutput(
- viz::SurfaceId(frame_sink_id_, pending_local_surface_id_),
- std::move(request));
+ viz::SurfaceId(frame_sink_id_, local_surface_id_), std::move(request));
}
bool DelegatedFrameHostAndroid::CanCopyFromCompositingSurface() const {
- return pending_local_surface_id_.is_valid() && view_->GetWindowAndroid() &&
- view_->GetWindowAndroid()->GetCompositor();
+ return local_surface_id_.is_valid();
}
void DelegatedFrameHostAndroid::EvictDelegatedFrame() {
if (!content_layer_)
return;
- content_layer_->SetPrimarySurfaceId(viz::SurfaceId(),
- cc::DeadlinePolicy::UseDefaultDeadline());
+ content_layer_->SetSurfaceId(viz::SurfaceId(),
+ cc::DeadlinePolicy::UseDefaultDeadline());
if (!enable_surface_synchronization_) {
content_layer_->RemoveFromParent();
content_layer_ = nullptr;
@@ -204,11 +201,15 @@ void DelegatedFrameHostAndroid::EvictDelegatedFrame() {
if (!HasSavedFrame())
return;
std::vector<viz::SurfaceId> surface_ids = {
- viz::SurfaceId(frame_sink_id_, active_local_surface_id_)};
- // Reset information about the active surface because it will get destroyed.
- active_local_surface_id_ = viz::LocalSurfaceId();
+ viz::SurfaceId(frame_sink_id_, local_surface_id_)};
host_frame_sink_manager_->EvictSurfaces(surface_ids);
- frame_evictor_->DiscardedFrame();
+ frame_evictor_->OnSurfaceDiscarded();
+ // When surface sync is on, this call will force |client_| to allocate a new
+ // LocalSurfaceId which will be embedded the next time the tab is shown. When
+ // surface sync is off, the renderer will always allocate a new LocalSurfaceId
+ // when it becomes visible just in case the previous LocalSurfaceId is evicted
+ // by the browser.
+ client_->WasEvicted();
}
void DelegatedFrameHostAndroid::ResetFallbackToFirstNavigationSurface() {
@@ -216,20 +217,20 @@ void DelegatedFrameHostAndroid::ResetFallbackToFirstNavigationSurface() {
return;
// Don't update the fallback if it's already newer than the first id after
// navigation.
- if (content_layer_->fallback_surface_id() &&
- content_layer_->fallback_surface_id()->frame_sink_id() ==
+ if (content_layer_->oldest_acceptable_fallback() &&
+ content_layer_->oldest_acceptable_fallback()->frame_sink_id() ==
frame_sink_id_ &&
- content_layer_->fallback_surface_id()
+ content_layer_->oldest_acceptable_fallback()
->local_surface_id()
.IsSameOrNewerThan(first_local_surface_id_after_navigation_)) {
return;
}
- content_layer_->SetFallbackSurfaceId(
+ content_layer_->SetOldestAcceptableFallback(
viz::SurfaceId(frame_sink_id_, first_local_surface_id_after_navigation_));
}
bool DelegatedFrameHostAndroid::HasDelegatedContent() const {
- return content_layer_ && content_layer_->primary_surface_id().is_valid();
+ return content_layer_ && content_layer_->surface_id().is_valid();
}
void DelegatedFrameHostAndroid::CompositorFrameSinkChanged() {
@@ -277,11 +278,11 @@ void DelegatedFrameHostAndroid::DetachFromCompositor() {
}
bool DelegatedFrameHostAndroid::IsPrimarySurfaceEvicted() const {
- return !content_layer_ || !content_layer_->primary_surface_id().is_valid();
+ return !content_layer_ || !content_layer_->surface_id().is_valid();
}
bool DelegatedFrameHostAndroid::HasSavedFrame() const {
- return frame_evictor_->HasFrame();
+ return frame_evictor_->has_surface();
}
void DelegatedFrameHostAndroid::WasHidden() {
@@ -289,51 +290,51 @@ void DelegatedFrameHostAndroid::WasHidden() {
}
void DelegatedFrameHostAndroid::WasShown(
- const viz::LocalSurfaceId& new_pending_local_surface_id,
- const gfx::Size& new_pending_size_in_pixels) {
+ const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Size& new_size_in_pixels) {
frame_evictor_->SetVisible(true);
if (!enable_surface_synchronization_)
return;
EmbedSurface(
- new_pending_local_surface_id, new_pending_size_in_pixels,
+ new_local_surface_id, new_size_in_pixels,
cc::DeadlinePolicy::UseSpecifiedDeadline(FirstFrameTimeoutFrames()));
}
void DelegatedFrameHostAndroid::EmbedSurface(
- const viz::LocalSurfaceId& new_pending_local_surface_id,
- const gfx::Size& new_pending_size_in_pixels,
+ const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Size& new_size_in_pixels,
cc::DeadlinePolicy deadline_policy) {
if (!enable_surface_synchronization_)
return;
- pending_local_surface_id_ = new_pending_local_surface_id;
- pending_surface_size_in_pixels_ = new_pending_size_in_pixels;
+ local_surface_id_ = new_local_surface_id;
+ surface_size_in_pixels_ = new_size_in_pixels;
- viz::SurfaceId current_primary_surface_id =
- content_layer_->primary_surface_id();
- viz::SurfaceId new_primary_surface_id(frame_sink_id_,
- pending_local_surface_id_);
+ viz::SurfaceId current_primary_surface_id = content_layer_->surface_id();
+ viz::SurfaceId new_primary_surface_id(frame_sink_id_, local_surface_id_);
if (!frame_evictor_->visible()) {
// If the tab is resized while hidden, advance the fallback so that the next
// time user switches back to it the page is blank. This is preferred to
// showing contents of old size. Don't call EvictDelegatedFrame to avoid
// races when dragging tabs across displays. See https://crbug.com/813157.
- if (pending_surface_size_in_pixels_ != content_layer_->bounds() &&
- content_layer_->fallback_surface_id() &&
- content_layer_->fallback_surface_id()->is_valid()) {
- content_layer_->SetFallbackSurfaceId(new_primary_surface_id);
+ if (surface_size_in_pixels_ != content_layer_->bounds() &&
+ content_layer_->oldest_acceptable_fallback() &&
+ content_layer_->oldest_acceptable_fallback()->is_valid()) {
+ content_layer_->SetOldestAcceptableFallback(new_primary_surface_id);
}
// Don't update the SurfaceLayer when invisible to avoid blocking on
// renderers that do not submit CompositorFrames. Next time the renderer
// is visible, EmbedSurface will be called again. See WasShown.
return;
}
+
+ frame_evictor_->OnNewSurfaceEmbedded();
+
if (!current_primary_surface_id.is_valid() ||
- current_primary_surface_id.local_surface_id() !=
- pending_local_surface_id_) {
+ current_primary_surface_id.local_surface_id() != local_surface_id_) {
if (base::android::BuildInfo::GetInstance()->sdk_int() <
base::android::SDK_VERSION_OREO) {
// On version of Android earlier than Oreo, we would like to produce new
@@ -344,13 +345,12 @@ void DelegatedFrameHostAndroid::EmbedSurface(
if (deadline_policy.policy_type() !=
cc::DeadlinePolicy::kUseInfiniteDeadline &&
(content_layer_->bounds().IsEmpty() ||
- content_layer_->bounds() != pending_surface_size_in_pixels_)) {
+ content_layer_->bounds() != surface_size_in_pixels_)) {
deadline_policy = cc::DeadlinePolicy::UseSpecifiedDeadline(0u);
}
}
- content_layer_->SetPrimarySurfaceId(new_primary_surface_id,
- deadline_policy);
- content_layer_->SetBounds(new_pending_size_in_pixels);
+ content_layer_->SetSurfaceId(new_primary_surface_id, deadline_policy);
+ content_layer_->SetBounds(new_size_in_pixels);
}
}
@@ -382,13 +382,10 @@ void DelegatedFrameHostAndroid::DidReceiveCompositorFrameAck(
client_->DidReceiveCompositorFrameAck(resources);
}
-void DelegatedFrameHostAndroid::DidPresentCompositorFrame(
- uint32_t presentation_token,
- const gfx::PresentationFeedback& feedback) {
- client_->DidPresentCompositorFrame(presentation_token, feedback);
-}
-
-void DelegatedFrameHostAndroid::OnBeginFrame(const viz::BeginFrameArgs& args) {
+void DelegatedFrameHostAndroid::OnBeginFrame(
+ const viz::BeginFrameArgs& args,
+ const base::flat_map<uint32_t, gfx::PresentationFeedback>& feedbacks) {
+ client_->DidPresentCompositorFrames(feedbacks);
if (enable_viz_) {
NOTREACHED();
return;
@@ -412,16 +409,7 @@ void DelegatedFrameHostAndroid::OnNeedsBeginFrames(bool needs_begin_frames) {
void DelegatedFrameHostAndroid::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
- if (!enable_surface_synchronization_)
- return;
-
- active_local_surface_id_ = surface_info.id().local_surface_id();
-
- // TODO(fsamuel): "SwappedFrame" is a bad name. Also, this method doesn't
- // really need to take in visiblity. FrameEvictor already has the latest
- // visibility state.
- frame_evictor_->SwappedFrame(frame_evictor_->visible());
- // Note: the frame may have been evicted immediately.
+ NOTREACHED();
}
void DelegatedFrameHostAndroid::OnFrameTokenChanged(uint32_t frame_token) {
@@ -442,16 +430,16 @@ void DelegatedFrameHostAndroid::CreateCompositorFrameSinkSupport() {
}
viz::SurfaceId DelegatedFrameHostAndroid::SurfaceId() const {
- return viz::SurfaceId(frame_sink_id_, active_local_surface_id_);
+ return viz::SurfaceId(frame_sink_id_, local_surface_id_);
}
bool DelegatedFrameHostAndroid::HasPrimarySurface() const {
- return content_layer_ && content_layer_->primary_surface_id().is_valid();
+ return content_layer_ && content_layer_->surface_id().is_valid();
}
bool DelegatedFrameHostAndroid::HasFallbackSurface() const {
- return content_layer_ && content_layer_->fallback_surface_id() &&
- content_layer_->fallback_surface_id()->is_valid();
+ return content_layer_ && content_layer_->oldest_acceptable_fallback() &&
+ content_layer_->oldest_acceptable_fallback()->is_valid();
}
void DelegatedFrameHostAndroid::TakeFallbackContentFrom(
@@ -460,10 +448,9 @@ void DelegatedFrameHostAndroid::TakeFallbackContentFrom(
return;
if (enable_surface_synchronization_) {
- const viz::SurfaceId& other_primary =
- other->content_layer_->primary_surface_id();
+ const viz::SurfaceId& other_primary = other->content_layer_->surface_id();
const base::Optional<viz::SurfaceId>& other_fallback =
- other->content_layer_->fallback_surface_id();
+ other->content_layer_->oldest_acceptable_fallback();
viz::SurfaceId desired_fallback;
if (!other->HasFallbackSurface() ||
!other_primary.IsSameOrNewerThan(*other_fallback)) {
@@ -471,20 +458,19 @@ void DelegatedFrameHostAndroid::TakeFallbackContentFrom(
} else {
desired_fallback = *other_fallback;
}
- content_layer_->SetFallbackSurfaceId(
- other->content_layer_->primary_surface_id().ToSmallestId());
+ content_layer_->SetOldestAcceptableFallback(
+ other->content_layer_->surface_id().ToSmallestId());
return;
}
if (content_layer_) {
- content_layer_->SetPrimarySurfaceId(
- *other->content_layer_->fallback_surface_id(),
+ content_layer_->SetSurfaceId(
+ *other->content_layer_->oldest_acceptable_fallback(),
cc::DeadlinePolicy::UseDefaultDeadline());
} else {
const auto& surface_id = other->SurfaceId();
- active_local_surface_id_ = surface_id.local_surface_id();
- pending_local_surface_id_ = active_local_surface_id_;
- pending_surface_size_in_pixels_ = other->pending_surface_size_in_pixels_;
+ local_surface_id_ = surface_id.local_surface_id();
+ surface_size_in_pixels_ = other->surface_size_in_pixels_;
has_transparent_background_ = other->has_transparent_background_;
content_layer_ = CreateSurfaceLayer(
surface_id, surface_id, other->content_layer_->bounds(),
@@ -492,15 +478,15 @@ void DelegatedFrameHostAndroid::TakeFallbackContentFrom(
other->content_layer_->contents_opaque());
view_->GetLayer()->AddChild(content_layer_);
}
- content_layer_->SetFallbackSurfaceId(
- *other->content_layer_->fallback_surface_id());
+ content_layer_->SetOldestAcceptableFallback(
+ *other->content_layer_->oldest_acceptable_fallback());
}
void DelegatedFrameHostAndroid::DidNavigate() {
if (!enable_surface_synchronization_)
return;
- first_local_surface_id_after_navigation_ = pending_local_surface_id_;
+ first_local_surface_id_after_navigation_ = local_surface_id_;
}
} // namespace ui
diff --git a/chromium/ui/android/delegated_frame_host_android.h b/chromium/ui/android/delegated_frame_host_android.h
index eef5417b4eb..348bb62c698 100644
--- a/chromium/ui/android/delegated_frame_host_android.h
+++ b/chromium/ui/android/delegated_frame_host_android.h
@@ -44,14 +44,15 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
virtual ~Client() {}
virtual void SetBeginFrameSource(
viz::BeginFrameSource* begin_frame_source) = 0;
- virtual void DidPresentCompositorFrame(
- uint32_t presentation_token,
- const gfx::PresentationFeedback& feedback) = 0;
+ virtual void DidPresentCompositorFrames(
+ const base::flat_map<uint32_t, gfx::PresentationFeedback>&
+ feedbacks) = 0;
virtual void DidReceiveCompositorFrameAck(
const std::vector<viz::ReturnedResource>& resources) = 0;
virtual void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) = 0;
virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
+ virtual void WasEvicted() = 0;
};
DelegatedFrameHostAndroid(ViewAndroid* view,
@@ -123,8 +124,8 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
void WasHidden();
void WasShown(const viz::LocalSurfaceId& local_surface_id,
const gfx::Size& size_in_pixels);
- void EmbedSurface(const viz::LocalSurfaceId& new_pending_local_surface_id,
- const gfx::Size& new_pending_size_in_pixels,
+ void EmbedSurface(const viz::LocalSurfaceId& new_local_surface_id,
+ const gfx::Size& new_size_in_pixels,
cc::DeadlinePolicy deadline_policy);
// Called when we begin a resize operation. Takes the compositor lock until we
@@ -134,6 +135,7 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
// Returns the ID for the current Surface. Returns an invalid ID if no
// surface exists (!HasDelegatedContent()).
viz::SurfaceId SurfaceId() const;
+
bool HasPrimarySurface() const;
bool HasFallbackSurface() const;
@@ -145,10 +147,9 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
// viz::mojom::CompositorFrameSinkClient implementation.
void DidReceiveCompositorFrameAck(
const std::vector<viz::ReturnedResource>& resources) override;
- void DidPresentCompositorFrame(
- uint32_t presentation_token,
- const gfx::PresentationFeedback& feedback) override;
- void OnBeginFrame(const viz::BeginFrameArgs& args) override;
+ void OnBeginFrame(const viz::BeginFrameArgs& args,
+ const base::flat_map<uint32_t, gfx::PresentationFeedback>&
+ feedbacks) override;
void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override;
void OnBeginFramePausedChanged(bool paused) override;
@@ -203,17 +204,12 @@ class UI_ANDROID_EXPORT DelegatedFrameHostAndroid
// Only used when surface synchronization is on.
viz::LocalSurfaceId first_local_surface_id_after_navigation_;
- // The surface id that was most recently activated by
- // OnFirstSurfaceActivation.
- viz::LocalSurfaceId active_local_surface_id_;
-
- // The local surface id as of the most recent call to
- // EmbedSurface. This is the surface that we expect future frames to
- // reference. This will eventually equal the active surface.
- viz::LocalSurfaceId pending_local_surface_id_;
+ // The LocalSurfaceId of the currently embedded surface. If surface sync is
+ // on, this surface is not necessarily active.
+ viz::LocalSurfaceId local_surface_id_;
// The size of the above surface (updated at the same time).
- gfx::Size pending_surface_size_in_pixels_;
+ gfx::Size surface_size_in_pixels_;
std::unique_ptr<viz::FrameEvictor> frame_evictor_;
diff --git a/chromium/ui/android/delegated_frame_host_android_unittest.cc b/chromium/ui/android/delegated_frame_host_android_unittest.cc
index 9248c71eb4d..2a52e65add4 100644
--- a/chromium/ui/android/delegated_frame_host_android_unittest.cc
+++ b/chromium/ui/android/delegated_frame_host_android_unittest.cc
@@ -37,9 +37,11 @@ class MockDelegatedFrameHostAndroidClient
void(const std::vector<viz::ReturnedResource>&));
MOCK_METHOD1(ReclaimResources,
void(const std::vector<viz::ReturnedResource>&));
- MOCK_METHOD2(DidPresentCompositorFrame,
- void(uint32_t, const gfx::PresentationFeedback&));
+ MOCK_METHOD1(
+ DidPresentCompositorFrames,
+ void(const base::flat_map<uint32_t, gfx::PresentationFeedback>&));
MOCK_METHOD1(OnFrameTokenChanged, void(uint32_t));
+ MOCK_METHOD0(WasEvicted, void());
};
class MockWindowAndroidCompositor : public WindowAndroidCompositor {
@@ -105,8 +107,10 @@ class DelegatedFrameHostAndroidTest : public testing::Test {
viz::CompositorFrameBuilder()
.AddRenderPass(gfx::Rect(frame_size), gfx::Rect(frame_size))
.Build();
- frame_host_->SubmitCompositorFrame(allocator_.GenerateId(),
- std::move(frame), base::nullopt);
+ allocator_.GenerateId();
+ frame_host_->SubmitCompositorFrame(
+ allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+ std::move(frame), base::nullopt);
}
void SetUpValidFrame(const gfx::Size& frame_size) {
@@ -178,9 +182,9 @@ TEST_F(DelegatedFrameHostAndroidTest, TakeFallbackContentFromUpdatesPrimary) {
other_frame_host->TakeFallbackContentFrom(frame_host_.get());
EXPECT_TRUE(other_frame_host->SurfaceId().is_valid());
- EXPECT_EQ(
- other_frame_host->content_layer_for_testing()->primary_surface_id(),
- other_frame_host->content_layer_for_testing()->fallback_surface_id());
+ EXPECT_EQ(other_frame_host->content_layer_for_testing()->surface_id(),
+ other_frame_host->content_layer_for_testing()
+ ->oldest_acceptable_fallback());
}
TEST_F(DelegatedFrameHostAndroidTest, CompositorLockDuringFirstFrame) {
@@ -303,5 +307,52 @@ TEST_F(DelegatedFrameHostAndroidTest, TestBothCompositorLocks) {
EXPECT_FALSE(IsLocked());
}
+// Make sure frame evictor is notified of the newly embedded surface after
+// WasShown.
+TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationTest, EmbedWhileHidden) {
+ {
+ EXPECT_CALL(client_, WasEvicted());
+ frame_host_->EvictDelegatedFrame();
+ }
+ EXPECT_FALSE(frame_host_->HasSavedFrame());
+ allocator_.GenerateId();
+ viz::LocalSurfaceId id =
+ allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ gfx::Size size(100, 100);
+ frame_host_->WasHidden();
+ frame_host_->EmbedSurface(id, size, cc::DeadlinePolicy::UseDefaultDeadline());
+ EXPECT_FALSE(frame_host_->HasSavedFrame());
+ frame_host_->WasShown(id, size);
+ EXPECT_TRUE(frame_host_->HasSavedFrame());
+}
+
+// Verify that when a source rect or output size is not provided to
+// CopyFromCompositingSurface, the corresponding values in CopyOutputRequest
+// are also not initialized.
+TEST_F(DelegatedFrameHostAndroidSurfaceSynchronizationTest,
+ FullSurfaceCapture) {
+ // First embed a surface to make sure we have something to copy from.
+ allocator_.GenerateId();
+ viz::LocalSurfaceId id =
+ allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ gfx::Size size(100, 100);
+ frame_host_->EmbedSurface(id, size, cc::DeadlinePolicy::UseDefaultDeadline());
+
+ // Request readback without source rect or output size specified.
+ frame_host_->CopyFromCompositingSurface(gfx::Rect(), gfx::Size(),
+ base::DoNothing());
+
+ // Make sure the resulting CopyOutputRequest does not have its area or result
+ // selection set.
+ const std::vector<
+ std::pair<viz::LocalSurfaceId, std::unique_ptr<viz::CopyOutputRequest>>>&
+ requests = frame_sink_manager_impl_.GetFrameSinkForId(frame_sink_id_)
+ ->copy_output_requests_for_testing();
+ ASSERT_EQ(1u, requests.size());
+ viz::CopyOutputRequest* request = requests[0].second.get();
+ EXPECT_FALSE(request->has_area());
+ EXPECT_FALSE(request->has_result_selection());
+}
+
} // namespace
} // namespace ui
diff --git a/chromium/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java b/chromium/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java
new file mode 100644
index 00000000000..d06138160cb
--- /dev/null
+++ b/chromium/ui/android/junit/src/org/chromium/ui/base/LocalizationUtilsTest.java
@@ -0,0 +1,64 @@
+// 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.
+
+package org.chromium.ui.base;
+
+import android.support.test.filters.SmallTest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+/**
+ * Tests for LocalizationUtils class.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class LocalizationUtilsTest {
+ @Test
+ @SmallTest
+ public void testGetDefaultCompressedPakLocaleForLanguage() {
+ assertEquals("fr", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("fr"));
+ assertEquals("es", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("es"));
+ assertEquals("en-US", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("en"));
+ assertEquals("pt-PT", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("pt"));
+ assertEquals("zh-CN", LocalizationUtils.getDefaultCompressedPakLocaleForLanguage("zh"));
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSplitLanguageForAndroid() {
+ assertEquals("en", LocalizationUtils.getSplitLanguageForAndroid("en"));
+ assertEquals("es", LocalizationUtils.getSplitLanguageForAndroid("es"));
+ assertEquals("fr", LocalizationUtils.getSplitLanguageForAndroid("fr"));
+ assertEquals("iw", LocalizationUtils.getSplitLanguageForAndroid("he"));
+ assertEquals("ji", LocalizationUtils.getSplitLanguageForAndroid("yi"));
+ assertEquals("tl", LocalizationUtils.getSplitLanguageForAndroid("fil"));
+ }
+
+ @Test
+ @SmallTest
+ public void testChromiumLocaleMatchesLanguage() {
+ assertTrue(LocalizationUtils.chromiumLocaleMatchesLanguage("en-US", "en"));
+ assertTrue(LocalizationUtils.chromiumLocaleMatchesLanguage("en-GB", "en"));
+ assertFalse(LocalizationUtils.chromiumLocaleMatchesLanguage("en-US", "es"));
+ assertTrue(LocalizationUtils.chromiumLocaleMatchesLanguage("es", "es"));
+ assertTrue(LocalizationUtils.chromiumLocaleMatchesLanguage("fi", "fi"));
+
+ // Filipino locale should *not* match Finish language.
+ // See http://crbug.com/901837
+ assertFalse(LocalizationUtils.chromiumLocaleMatchesLanguage("fil", "fi"));
+
+ // "tl" is the Android locale name for Filipines, due to historical
+ // reasons. The corresponding Chromium locale name is "fil".
+ // Check that the method only deals with Chromium locale names.
+ assertFalse(LocalizationUtils.chromiumLocaleMatchesLanguage("fil", "tl"));
+ }
+}
diff --git a/chromium/ui/android/resources/resource_manager_impl.cc b/chromium/ui/android/resources/resource_manager_impl.cc
index 24ac7b3661a..c7d48bd5220 100644
--- a/chromium/ui/android/resources/resource_manager_impl.cc
+++ b/chromium/ui/android/resources/resource_manager_impl.cc
@@ -159,9 +159,14 @@ Resource* ResourceManagerImpl::GetStaticResourceWithTint(int res_id,
// Build a color filter to use on the base resource. This filter multiplies
// the RGB components by the components of the new color but retains the
// alpha of the original image.
+ SkScalar color_matrix[20] = {
+ 0, 0, 0, 0, SkColorGetR(tint_color),
+ 0, 0, 0, 0, SkColorGetG(tint_color),
+ 0, 0, 0, 0, SkColorGetB(tint_color),
+ 0, 0, 0, 1, 0};
SkPaint color_filter;
color_filter.setColorFilter(
- SkColorFilter::MakeModeFilter(tint_color, SkBlendMode::kModulate));
+ SkColorFilter::MakeMatrixFilterRowMajor255(color_matrix));
// Draw the resource and make it immutable.
base_image->ui_resource()
diff --git a/chromium/ui/android/resources/resource_manager_impl_unittest.cc b/chromium/ui/android/resources/resource_manager_impl_unittest.cc
index e9850b56c15..0d3a3f753ea 100644
--- a/chromium/ui/android/resources/resource_manager_impl_unittest.cc
+++ b/chromium/ui/android/resources/resource_manager_impl_unittest.cc
@@ -48,9 +48,9 @@ class TestResourceManagerImpl : public ResourceManagerImpl {
void SetResourceAsLoaded(AndroidResourceType res_type, int res_id) {
SkBitmap small_bitmap;
- SkCanvas canvas(small_bitmap);
small_bitmap.allocPixels(
SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kOpaque_SkAlphaType));
+ SkCanvas canvas(small_bitmap);
canvas.drawColor(SK_ColorWHITE);
small_bitmap.setImmutable();
diff --git a/chromium/ui/android/window_android.cc b/chromium/ui/android/window_android.cc
index b4089b74478..aed6c8e4f61 100644
--- a/chromium/ui/android/window_android.cc
+++ b/chromium/ui/android/window_android.cc
@@ -4,6 +4,9 @@
#include "ui/android/window_android.h"
+#include <utility>
+#include <vector>
+
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
@@ -42,17 +45,34 @@ class WindowAndroid::WindowBeginFrameSource : public viz::BeginFrameSource {
void RemoveObserver(viz::BeginFrameObserver* obs) override;
void DidFinishFrame(viz::BeginFrameObserver* obs) override {}
bool IsThrottled() const override { return true; }
+ void OnGpuNoLongerBusy() override;
void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period);
void OnPauseChanged(bool paused);
+ void AddBeginFrameCompletionCallback(base::OnceClosure callback);
private:
+ friend class WindowAndroid::ScopedOnBeginFrame;
+
WindowAndroid* const window_;
base::ObserverList<viz::BeginFrameObserver>::Unchecked observers_;
int observer_count_;
viz::BeginFrameArgs last_begin_frame_args_;
uint64_t next_sequence_number_;
bool paused_;
+
+ // Set by ScopedOnBeginFrame.
+ std::vector<base::OnceClosure>* vsync_complete_callbacks_ptr_ = nullptr;
+};
+
+class WindowAndroid::ScopedOnBeginFrame {
+ public:
+ explicit ScopedOnBeginFrame(WindowAndroid::WindowBeginFrameSource* bfs);
+ ~ScopedOnBeginFrame();
+
+ private:
+ WindowAndroid::WindowBeginFrameSource* const begin_frame_source_;
+ std::vector<base::OnceClosure> vsync_complete_callbacks_;
};
void WindowAndroid::WindowBeginFrameSource::AddObserver(
@@ -80,6 +100,7 @@ void WindowAndroid::WindowBeginFrameSource::AddObserver(
// BeginFrames.
last_begin_frame_args_.deadline =
base::TimeTicks::Now() + last_begin_frame_args_.interval;
+ ScopedOnBeginFrame scope(this);
obs->OnBeginFrame(last_begin_frame_args_);
}
}
@@ -96,6 +117,12 @@ void WindowAndroid::WindowBeginFrameSource::RemoveObserver(
window_->SetNeedsBeginFrames(false);
}
+void WindowAndroid::WindowBeginFrameSource::OnGpuNoLongerBusy() {
+ ScopedOnBeginFrame scope(this);
+ for (auto& obs : observers_)
+ obs.OnBeginFrame(last_begin_frame_args_);
+}
+
void WindowAndroid::WindowBeginFrameSource::OnVSync(
base::TimeTicks frame_time,
base::TimeDelta vsync_period) {
@@ -106,9 +133,9 @@ void WindowAndroid::WindowBeginFrameSource::OnVSync(
deadline, vsync_period, viz::BeginFrameArgs::NORMAL);
DCHECK(last_begin_frame_args_.IsValid());
next_sequence_number_++;
-
- for (auto& obs : observers_)
- obs.OnBeginFrame(last_begin_frame_args_);
+ if (RequestCallbackOnGpuAvailable())
+ return;
+ OnGpuNoLongerBusy();
}
void WindowAndroid::WindowBeginFrameSource::OnPauseChanged(bool paused) {
@@ -117,6 +144,28 @@ void WindowAndroid::WindowBeginFrameSource::OnPauseChanged(bool paused) {
obs.OnBeginFrameSourcePausedChanged(paused_);
}
+void WindowAndroid::WindowBeginFrameSource::AddBeginFrameCompletionCallback(
+ base::OnceClosure callback) {
+ CHECK(vsync_complete_callbacks_ptr_);
+ vsync_complete_callbacks_ptr_->emplace_back(std::move(callback));
+}
+
+WindowAndroid::ScopedOnBeginFrame::ScopedOnBeginFrame(
+ WindowAndroid::WindowBeginFrameSource* bfs)
+ : begin_frame_source_(bfs) {
+ DCHECK(!begin_frame_source_->vsync_complete_callbacks_ptr_);
+ begin_frame_source_->vsync_complete_callbacks_ptr_ =
+ &vsync_complete_callbacks_;
+}
+
+WindowAndroid::ScopedOnBeginFrame::~ScopedOnBeginFrame() {
+ DCHECK_EQ(&vsync_complete_callbacks_,
+ begin_frame_source_->vsync_complete_callbacks_ptr_);
+ begin_frame_source_->vsync_complete_callbacks_ptr_ = nullptr;
+ for (base::OnceClosure& callback : vsync_complete_callbacks_)
+ std::move(callback).Run();
+}
+
// static
WindowAndroid* WindowAndroid::FromJavaWindowAndroid(
const JavaParamRef<jobject>& jwindow_android) {
@@ -172,8 +221,9 @@ void WindowAndroid::AddObserver(WindowAndroidObserver* observer) {
observer_list_.AddObserver(observer);
}
-void WindowAndroid::AddVSyncCompleteCallback(const base::Closure& callback) {
- vsync_complete_callbacks_.push_back(callback);
+void WindowAndroid::AddBeginFrameCompletionCallback(
+ base::OnceClosure callback) {
+ begin_frame_source_->AddBeginFrameCompletionCallback(std::move(callback));
}
void WindowAndroid::RemoveObserver(WindowAndroidObserver* observer) {
@@ -243,10 +293,6 @@ void WindowAndroid::OnVSync(JNIEnv* env,
begin_frame_source_->OnVSync(frame_time, vsync_period);
- for (const base::Closure& callback : vsync_complete_callbacks_)
- callback.Run();
- vsync_complete_callbacks_.clear();
-
if (needs_begin_frames_)
RequestVSyncUpdate();
}
diff --git a/chromium/ui/android/window_android.h b/chromium/ui/android/window_android.h
index 29aff9f2624..62e7f5ff292 100644
--- a/chromium/ui/android/window_android.h
+++ b/chromium/ui/android/window_android.h
@@ -6,10 +6,8 @@
#define UI_ANDROID_WINDOW_ANDROID_H_
#include <jni.h>
-#include <list>
#include <memory>
#include <string>
-#include <vector>
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
@@ -64,7 +62,9 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
viz::BeginFrameSource* GetBeginFrameSource();
// Runs the provided callback as soon as the current vsync was handled.
- void AddVSyncCompleteCallback(const base::Closure& callback);
+ // This call is only allowed from inside the OnBeginFrame call from the
+ // BeginFrameSource of this window.
+ void AddBeginFrameCompletionCallback(base::OnceClosure callback);
void SetNeedsAnimate();
void Animate(base::TimeTicks begin_frame_time);
@@ -97,6 +97,7 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
private:
class WindowBeginFrameSource;
+ class ScopedOnBeginFrame;
friend class DisplayAndroidManager;
friend class WindowBeginFrameSource;
@@ -117,7 +118,6 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
std::unique_ptr<WindowBeginFrameSource> begin_frame_source_;
bool needs_begin_frames_;
- std::list<base::Closure> vsync_complete_callbacks_;
float mouse_wheel_scroll_factor_;
bool vsync_paused_ = false;
diff --git a/chromium/ui/aura/BUILD.gn b/chromium/ui/aura/BUILD.gn
index cba785ad544..b02ca41ac97 100644
--- a/chromium/ui/aura/BUILD.gn
+++ b/chromium/ui/aura/BUILD.gn
@@ -32,7 +32,6 @@ jumbo_component("aura") {
"env_input_state_controller.h",
"env_observer.h",
"event_injector.h",
- "hit_test_data_provider_aura.h",
"input_state_lookup.h",
"input_state_lookup_win.h",
"layout_manager.h",
@@ -47,6 +46,7 @@ jumbo_component("aura") {
"mus/focus_synchronizer.h",
"mus/focus_synchronizer_delegate.h",
"mus/focus_synchronizer_observer.h",
+ "mus/gesture_recognizer_impl_mus.h",
"mus/gesture_synchronizer.h",
"mus/in_flight_change.h",
"mus/input_method_mus.h",
@@ -107,7 +107,6 @@ jumbo_component("aura") {
"env.cc",
"env_input_state_controller.cc",
"event_injector.cc",
- "hit_test_data_provider_aura.cc",
"input_state_lookup.cc",
"input_state_lookup_win.cc",
"layout_manager.cc",
@@ -119,6 +118,7 @@ jumbo_component("aura") {
"mus/drag_drop_controller_mus.cc",
"mus/embed_root.cc",
"mus/focus_synchronizer.cc",
+ "mus/gesture_recognizer_impl_mus.cc",
"mus/gesture_synchronizer.cc",
"mus/in_flight_change.cc",
"mus/input_method_mus.cc",
@@ -136,6 +136,8 @@ jumbo_component("aura") {
"mus/window_tree_client_delegate.cc",
"mus/window_tree_host_mus.cc",
"mus/window_tree_host_mus_init_params.cc",
+ "native_window_occlusion_tracker_win.cc",
+ "native_window_occlusion_tracker_win.h",
"null_window_targeter.cc",
"scoped_keyboard_hook.cc",
"scoped_simple_keyboard_hook.cc",
@@ -153,6 +155,12 @@ jumbo_component("aura") {
"window_tree_host_platform.cc",
]
+ # aura_interactive_ui_tests needs access to native_window_occlusion_tracker.h.
+ friend = [
+ ":aura_interactive_ui_tests",
+ ":aura_unittests",
+ ]
+
defines = [ "AURA_IMPLEMENTATION" ]
deps = [
@@ -239,6 +247,8 @@ jumbo_static_library("test_support") {
"test/aura_test_suite_setup.h",
"test/aura_test_utils.cc",
"test/aura_test_utils.h",
+ "test/default_event_generator_delegate.cc",
+ "test/default_event_generator_delegate.h",
"test/env_test_helper.cc",
"test/env_test_helper.h",
"test/event_generator_delegate_aura.cc",
@@ -252,10 +262,11 @@ jumbo_static_library("test_support") {
"test/mus/test_window_tree_client_delegate.h",
"test/mus/test_window_tree_client_setup.cc",
"test/mus/test_window_tree_client_setup.h",
+ "test/mus/test_window_tree_delegate.h",
"test/mus/window_port_mus_test_helper.cc",
"test/mus/window_port_mus_test_helper.h",
- "test/mus/window_tree_client_private.cc",
- "test/mus/window_tree_client_private.h",
+ "test/mus/window_tree_client_test_api.cc",
+ "test/mus/window_tree_client_test_api.h",
"test/test_cursor_client.cc",
"test/test_cursor_client.h",
"test/test_focus_client.cc",
@@ -370,7 +381,6 @@ test("aura_unittests") {
"../compositor_extra/shadow_unittest.cc",
"//ui/aura_extra/window_occlusion_impl_unittest_win.cc",
"gestures/gesture_recognizer_unittest.cc",
- "hit_test_data_provider_aura_unittest.cc",
"mouse_location_manager_unittest.cc",
"mus/drag_drop_controller_mus_unittest.cc",
"mus/focus_synchronizer_unittest.cc",
@@ -391,6 +401,10 @@ test("aura_unittests") {
"window_unittest.cc",
]
+ if (is_win) {
+ sources += [ "native_window_occlusion_tracker_unittest.cc" ]
+ }
+
deps = [
":test_support",
"//base/test:test_support",
@@ -421,3 +435,29 @@ test("aura_unittests") {
"//third_party/mesa_headers",
]
}
+
+# This target is added as a dependency of browser interactive_ui_tests. It must
+# be source_set, otherwise the linker will drop the tests as dead code.
+source_set("aura_interactive_ui_tests") {
+ testonly = true
+ if (is_win) {
+ sources = [
+ "native_window_occlusion_tracker_win_interactive_test.cc",
+ ]
+
+ deps = [
+ ":aura",
+ ":test_support",
+ "//base/test:test_support",
+ "//net",
+ "//testing/gtest",
+ "//ui/base/ime:ime",
+ "//ui/display:display",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gl:test_support",
+ "//ui/gl/init",
+ "//ui/views:views",
+ ]
+ }
+}
diff --git a/chromium/ui/aura/DEPS b/chromium/ui/aura/DEPS
index 263ea23c37f..b2ad0cd29e4 100644
--- a/chromium/ui/aura/DEPS
+++ b/chromium/ui/aura/DEPS
@@ -20,6 +20,7 @@ include_rules = [
"+ui/display",
"+ui/events",
"+ui/gfx",
+ "+ui/gl/test",
"+ui/metro_viewer", # TODO(beng): investigate moving remote_root_window_host
# to ui/metro_viewer.
"+ui/ozone/public",
diff --git a/chromium/ui/aura/client/aura_constants.cc b/chromium/ui/aura/client/aura_constants.cc
index 1ed7c6e50d9..eaa411d6119 100644
--- a/chromium/ui/aura/client/aura_constants.cc
+++ b/chromium/ui/aura/client/aura_constants.cc
@@ -44,12 +44,12 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAppIconKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(int, kAppType, 0);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::SizeF, kAspectRatio, nullptr);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAvatarIconKey, nullptr);
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kClientWindowHasContent, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kConstrainedWindowKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kCreatedByUserGesture, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(FocusClient*, kFocusClientKey, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr);
-DEFINE_UI_CLASS_PROPERTY_KEY(bool, kImmersiveFullscreenKey, false);
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMinimumSize, nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kMirroringEnabledKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kChildModalParentKey, nullptr);
diff --git a/chromium/ui/aura/client/aura_constants.h b/chromium/ui/aura/client/aura_constants.h
index 65dc33a5477..8692e29d58d 100644
--- a/chromium/ui/aura/client/aura_constants.h
+++ b/chromium/ui/aura/client/aura_constants.h
@@ -61,6 +61,13 @@ AURA_EXPORT extern const WindowProperty<gfx::SizeF*>* const kAspectRatio;
// frame to indicate the owner of the window when needed.
AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kAvatarIconKey;
+// A property key to indicate if a client window has content. The value is
+// based on whether the window has a drawn layer (i.e. layer type !=
+// LAYER_NOT_DRAWN) and is opaque. It is passed to the Window Service side for
+// the occlusion tracker to process since the info is only available at the
+// client side.
+AURA_EXPORT extern const WindowProperty<bool>* const kClientWindowHasContent;
+
// A property key to store if a window is a constrained window or not.
AURA_EXPORT extern const WindowProperty<bool>* const kConstrainedWindowKey;
@@ -78,12 +85,6 @@ AURA_EXPORT extern const WindowProperty<FocusClient*>* const kFocusClientKey;
// WebContentsViews find the windows that should constrain NPAPI plugins.
AURA_EXPORT extern const WindowProperty<Window*>* const kHostWindowKey;
-// A property key to indicate that a window should be in immersive mode when the
-// window enters the fullscreen mode. The immersive fullscreen mode is slightly
-// different from the normal fullscreen mode by allowing the user to reveal the
-// top portion of the window through a touch / mouse gesture.
-AURA_EXPORT extern const WindowProperty<bool>* const kImmersiveFullscreenKey;
-
// A property key to store the minimum size of the window.
AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kMinimumSize;
diff --git a/chromium/ui/aura/env.cc b/chromium/ui/aura/env.cc
index bbd91404c0f..c6775642f0f 100644
--- a/chromium/ui/aura/env.cc
+++ b/chromium/ui/aura/env.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
+#include "base/observer_list_types.h"
#include "services/ws/public/mojom/window_tree.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env_input_state_controller.h"
@@ -24,6 +25,7 @@
#include "ui/aura/window_occlusion_tracker.h"
#include "ui/aura/window_port_for_shutdown.h"
#include "ui/base/ui_base_features.h"
+#include "ui/events/event_observer.h"
#include "ui/events/event_target_iterator.h"
#include "ui/events/gestures/gesture_recognizer_impl.h"
#include "ui/events/platform/platform_event_source.h"
@@ -42,6 +44,47 @@ Env* g_primary_instance = nullptr;
} // namespace
+// EventObserverAdapter is an aura::Env pre-target handler that forwards
+// read-only events to its observer when they match the requested types.
+class EventObserverAdapter : public ui::EventHandler,
+ public base::CheckedObserver {
+ public:
+ EventObserverAdapter(ui::EventObserver* observer,
+ ui::EventTarget* target,
+ const std::set<ui::EventType>& types)
+ : observer_(observer), target_(target), types_(types) {
+ target_->AddPreTargetHandler(this);
+ }
+
+ ~EventObserverAdapter() override { target_->RemovePreTargetHandler(this); }
+
+ ui::EventObserver* observer() { return observer_; }
+ ui::EventTarget* target() { return target_; }
+ const std::set<ui::EventType>& types() const { return types_; }
+
+ // ui::EventHandler:
+ void OnEvent(ui::Event* event) override {
+ if (types_.count(event->type()) > 0) {
+ std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(*event);
+ ui::Event::DispatcherApi(cloned_event.get()).set_target(event->target());
+ // The root location of located events should be in screen coordinates.
+ if (cloned_event->IsLocatedEvent() && cloned_event->target()) {
+ ui::LocatedEvent* located_event = cloned_event->AsLocatedEvent();
+ auto root = located_event->target()->GetScreenLocationF(*located_event);
+ located_event->set_root_location_f(root);
+ }
+ observer_->OnEvent(*cloned_event);
+ }
+ }
+
+ private:
+ ui::EventObserver* observer_;
+ ui::EventTarget* target_;
+ const std::set<ui::EventType> types_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventObserverAdapter);
+};
+
////////////////////////////////////////////////////////////////////////////////
// Env, public:
@@ -172,6 +215,11 @@ mojo::ScopedSharedBufferHandle Env::GetLastMouseLocationMemory() {
return mouse_location_manager_->GetMouseLocationMemory();
}
+void Env::SetGestureRecognizer(
+ std::unique_ptr<ui::GestureRecognizer> gesture_recognizer) {
+ gesture_recognizer_ = std::move(gesture_recognizer);
+}
+
void Env::SetWindowTreeClient(WindowTreeClient* window_tree_client) {
// The WindowTreeClient should only be set once. Test code may need to change
// the value after the fact, to do that use EnvTestHelper.
@@ -188,8 +236,7 @@ void Env::ScheduleEmbed(
}
WindowOcclusionTracker* Env::GetWindowOcclusionTracker() {
- // TODO(https://crbug.com/867150): DCHECK to ensure LOCAL aura after mus
- // code path is wired up.
+ DCHECK_EQ(Mode::LOCAL, mode_);
if (!window_occlusion_tracker_) {
// Use base::WrapUnique + new because of the constructor is private.
window_occlusion_tracker_ = base::WrapUnique(new WindowOcclusionTracker());
@@ -198,6 +245,66 @@ WindowOcclusionTracker* Env::GetWindowOcclusionTracker() {
return window_occlusion_tracker_.get();
}
+void Env::PauseWindowOcclusionTracking() {
+ switch (mode_) {
+ case Mode::LOCAL:
+ GetWindowOcclusionTracker()->Pause();
+ break;
+ case Mode::MUS:
+ // |window_tree_client_| could be null in tests.
+ // e.g. WindowTreeClientDestructionTest.*
+ if (window_tree_client_)
+ window_tree_client_->PauseWindowOcclusionTracking();
+ break;
+ }
+}
+
+void Env::UnpauseWindowOcclusionTracking() {
+ switch (mode_) {
+ case Mode::LOCAL:
+ GetWindowOcclusionTracker()->Unpause();
+ break;
+ case Mode::MUS:
+ // |window_tree_client_| could be null in tests.
+ // e.g. WindowTreeClientDestructionTest.*
+ if (window_tree_client_)
+ window_tree_client_->UnpauseWindowOcclusionTracking();
+ break;
+ }
+}
+
+void Env::AddEventObserver(ui::EventObserver* observer,
+ ui::EventTarget* target,
+ const std::set<ui::EventType>& types) {
+ DCHECK(!types.empty()) << "Observers must observe at least one event type";
+ auto adapter(std::make_unique<EventObserverAdapter>(observer, target, types));
+ event_observer_adapter_list_.AddObserver(adapter.get());
+ event_observer_adapters_.insert(std::move(adapter));
+ if (window_tree_client_ && target == this)
+ window_tree_client_->OnEventObserverAdded(observer, types);
+}
+
+void Env::RemoveEventObserver(ui::EventObserver* observer) {
+ for (auto& adapter : event_observer_adapters_) {
+ if (adapter->observer() == observer) {
+ if (window_tree_client_ && adapter->target() == this)
+ window_tree_client_->OnEventObserverRemoved(observer, adapter->types());
+ event_observer_adapter_list_.RemoveObserver(adapter.get());
+ event_observer_adapters_.erase(adapter);
+ return;
+ }
+ }
+}
+
+void Env::NotifyEventObservers(const ui::Event& event) {
+ for (auto& adapter : event_observer_adapter_list_) {
+ if (adapter.types().count(event.type()) > 0 &&
+ (adapter.target() == event.target() || adapter.target() == this)) {
+ adapter.observer()->OnEvent(event);
+ }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Env, private:
@@ -208,7 +315,6 @@ Env::Env(Mode mode)
: mode_(mode),
env_controller_(std::make_unique<EnvInputStateController>(this)),
mouse_button_flags_(0),
- is_touch_down_(false),
get_last_mouse_location_from_mus_(mode_ == Mode::MUS),
gesture_recognizer_(std::make_unique<ui::GestureRecognizerImpl>()),
input_state_lookup_(InputStateLookup::Create()),
@@ -272,11 +378,6 @@ void Env::NotifyHostInitialized(WindowTreeHost* host) {
observer.OnHostInitialized(host);
}
-void Env::NotifyHostActivated(WindowTreeHost* host) {
- for (EnvObserver& observer : observers_)
- observer.OnHostActivated(host);
-}
-
void Env::WindowTreeClientDestroyed(aura::WindowTreeClient* client) {
DCHECK_EQ(Mode::MUS, mode_);
@@ -295,7 +396,7 @@ bool Env::CanAcceptEvent(const ui::Event& event) {
}
ui::EventTarget* Env::GetParentTarget() {
- return NULL;
+ return nullptr;
}
std::unique_ptr<ui::EventTargetIterator> Env::GetChildIterator() const {
@@ -304,7 +405,7 @@ std::unique_ptr<ui::EventTargetIterator> Env::GetChildIterator() const {
ui::EventTargeter* Env::GetEventTargeter() {
NOTREACHED();
- return NULL;
+ return nullptr;
}
std::unique_ptr<ui::OSExchangeData::Provider> Env::BuildProvider() {
diff --git a/chromium/ui/aura/env.h b/chromium/ui/aura/env.h
index 3738281bedd..bf5499700d8 100644
--- a/chromium/ui/aura/env.h
+++ b/chromium/ui/aura/env.h
@@ -6,6 +6,7 @@
#define UI_AURA_ENV_H_
#include <memory>
+#include <set>
#include "base/callback_forward.h"
#include "base/macros.h"
@@ -15,7 +16,6 @@
#include "mojo/public/cpp/system/buffer.h"
#include "ui/aura/aura_export.h"
#include "ui/base/dragdrop/os_exchange_data_provider_factory.h"
-#include "ui/events/event_handler.h"
#include "ui/events/event_target.h"
#include "ui/events/system_input_injector.h"
#include "ui/gfx/geometry/point.h"
@@ -36,6 +36,7 @@ class Connector;
namespace ui {
class ContextFactory;
class ContextFactoryPrivate;
+class EventObserver;
class GestureRecognizer;
class PlatformEventSource;
} // namespace ui
@@ -54,6 +55,7 @@ class EnvWindowTreeClientSetter;
class EnvInputStateController;
class EnvObserver;
+class EventObserverAdapter;
class InputStateLookup;
class MouseLocationManager;
class MusMouseLocationUpdater;
@@ -182,6 +184,9 @@ class AURA_EXPORT Env : public ui::EventTarget,
return gesture_recognizer_.get();
}
+ void SetGestureRecognizer(
+ std::unique_ptr<ui::GestureRecognizer> gesture_recognizer);
+
// See CreateInstance() for description.
void SetWindowTreeClient(WindowTreeClient* window_tree_client);
bool HasWindowTreeClient() const { return window_tree_client_ != nullptr; }
@@ -192,9 +197,26 @@ class AURA_EXPORT Env : public ui::EventTarget,
mojo::InterfacePtr<ws::mojom::WindowTreeClient> client,
base::OnceCallback<void(const base::UnguessableToken&)> callback);
- // Get WindowOcclusionTracker instance. Create it if it is not yet created.
+ // Get WindowOcclusionTracker instance. Create one if not yet created.
WindowOcclusionTracker* GetWindowOcclusionTracker();
+ // Pause/unpause window occlusion tracking. It hides the detail of where
+ // WindowOcclusionTracker lives. It calls the tracker for LOCAL aura and calls
+ // Window Service to access the tracker there for MUS aura.
+ void PauseWindowOcclusionTracking();
+ void UnpauseWindowOcclusionTracking();
+
+ // Add, remove, or notify EventObservers. EventObservers are essentially
+ // pre-target EventHandlers that can not modify the events nor alter dispatch.
+ // On Chrome OS, observers receive system-wide events if |target| is this Env.
+ // On desktop platforms, observers may only receive events targeting Chrome.
+ // Observers must be removed before their target is destroyed.
+ void AddEventObserver(ui::EventObserver* observer,
+ ui::EventTarget* target,
+ const std::set<ui::EventType>& types);
+ void RemoveEventObserver(ui::EventObserver* observer);
+ void NotifyEventObservers(const ui::Event& event);
+
private:
friend class test::EnvTestHelper;
friend class test::EnvWindowTreeClientSetter;
@@ -223,9 +245,6 @@ class AURA_EXPORT Env : public ui::EventTarget,
// Called by the WindowTreeHost when it is initialized. Notifies observers.
void NotifyHostInitialized(WindowTreeHost* host);
- // Invoked by WindowTreeHost when it is activated. Notifies observers.
- void NotifyHostActivated(WindowTreeHost* host);
-
void WindowTreeClientDestroyed(WindowTreeClient* client);
// Overridden from ui::EventTarget:
@@ -257,11 +276,15 @@ class AURA_EXPORT Env : public ui::EventTarget,
base::ObserverList<WindowEventDispatcherObserver>::Unchecked
window_event_dispatcher_observers_;
+ // The ObserverList and set of owned EventObserver adapters.
+ base::ObserverList<EventObserverAdapter> event_observer_adapter_list_;
+ std::set<std::unique_ptr<EventObserverAdapter>> event_observer_adapters_;
+
std::unique_ptr<EnvInputStateController> env_controller_;
int mouse_button_flags_;
// Location of last mouse event, in screen coordinates.
mutable gfx::Point last_mouse_location_;
- bool is_touch_down_;
+ bool is_touch_down_ = false;
bool get_last_mouse_location_from_mus_;
// This may be set to true in tests to force using |last_mouse_location_|
// rather than querying WindowTreeClient.
diff --git a/chromium/ui/aura/env_observer.h b/chromium/ui/aura/env_observer.h
index 03fcf3bd171..79c21d9dd36 100644
--- a/chromium/ui/aura/env_observer.h
+++ b/chromium/ui/aura/env_observer.h
@@ -20,9 +20,6 @@ class AURA_EXPORT EnvObserver {
// Called when a WindowTreeHost is initialized.
virtual void OnHostInitialized(WindowTreeHost* host) {}
- // Called when a WindowTreeHost is activated.
- virtual void OnHostActivated(WindowTreeHost* host) {}
-
// Called right before Env is destroyed.
virtual void OnWillDestroyEnv() {}
diff --git a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
index ee72e003826..29df0158055 100644
--- a/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/chromium/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -696,6 +696,7 @@ TEST_F(GestureRecognizerTest, TouchCancelCanDestroyWindow) {
EXPECT_EQ(1, handler->touch_cancelled_count());
EXPECT_EQ(nullptr, window->parent());
+ window->RemovePreTargetHandler(handler.get());
}
// Check that appropriate touch events generate tap gesture events.
@@ -3814,6 +3815,7 @@ TEST_F(GestureRecognizerTest, CancelAllActiveTouches) {
EXPECT_EQ(2U, points.size());
EXPECT_EQ(gfx::PointF(101.f, 201.f), points[0]);
EXPECT_EQ(gfx::PointF(350.f, 300.f), points[1]);
+ window->RemovePreTargetHandler(handler.get());
}
// Check that appropriate touch events generate show press events
diff --git a/chromium/ui/aura/hit_test_data_provider_aura.cc b/chromium/ui/aura/hit_test_data_provider_aura.cc
deleted file mode 100644
index 3feb9b89427..00000000000
--- a/chromium/ui/aura/hit_test_data_provider_aura.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2017 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/aura/hit_test_data_provider_aura.h"
-
-#include "base/containers/adapters.h"
-#include "components/viz/common/hit_test/hit_test_region_list.h"
-#include "services/ws/public/mojom/window_tree_constants.mojom.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_targeter.h"
-
-namespace {
-
-void PopulateHitTestRegion(viz::HitTestRegion* hit_test_region,
- const aura::Window* window,
- uint32_t flags,
- const gfx::Rect& rect) {
- const ui::Layer* layer = window->layer();
- DCHECK(layer);
-
- DCHECK(window->GetFrameSinkId().is_valid());
- hit_test_region->frame_sink_id = window->GetFrameSinkId();
- // Checking |layer| may not be correct, since the actual layer that embeds
- // the surface may be a descendent of |layer|, instead of |layer| itself.
- if (window->IsEmbeddingClient())
- hit_test_region->flags =
- flags | viz::HitTestRegionFlags::kHitTestChildSurface;
- else
- hit_test_region->flags = flags | viz::HitTestRegionFlags::kHitTestMine;
- hit_test_region->rect = rect;
- hit_test_region->transform = layer->transform();
-}
-
-} // namespace
-
-namespace aura {
-
-HitTestDataProviderAura::HitTestDataProviderAura(aura::Window* window)
- : window_(window) {}
-
-HitTestDataProviderAura::~HitTestDataProviderAura() {}
-
-base::Optional<viz::HitTestRegionList> HitTestDataProviderAura::GetHitTestData(
- const viz::CompositorFrame& compositor_frame) const {
- const ws::mojom::EventTargetingPolicy event_targeting_policy =
- window_->event_targeting_policy();
- if (!window_->IsVisible() ||
- event_targeting_policy == ws::mojom::EventTargetingPolicy::NONE)
- return base::nullopt;
-
- base::Optional<viz::HitTestRegionList> hit_test_region_list(base::in_place);
- hit_test_region_list->flags =
- event_targeting_policy ==
- ws::mojom::EventTargetingPolicy::DESCENDANTS_ONLY
- ? viz::HitTestRegionFlags::kHitTestIgnore
- : viz::HitTestRegionFlags::kHitTestMine;
- // TODO(crbug.com/805416): Use pixels instead of DIP units for bounds.
- hit_test_region_list->bounds = window_->bounds();
-
- GetHitTestDataRecursively(window_, &*hit_test_region_list);
- return hit_test_region_list;
-}
-
-void HitTestDataProviderAura::GetHitTestDataRecursively(
- aura::Window* window,
- viz::HitTestRegionList* hit_test_region_list) const {
- if (window->IsEmbeddingClient())
- return;
-
- WindowTargeter* parent_targeter = window->targeter();
-
- // TODO(varkha): Figure out if we need to add hit-test regions for |window|.
- // Walk the children in Z-order (reversed order of children()) to produce
- // the hit-test data. Each child's hit test data is added before the hit-test
- // data from the child's descendants because the child could clip its
- // descendants for the purpose of event handling.
- for (aura::Window* child : base::Reversed(window->children())) {
- const ws::mojom::EventTargetingPolicy event_targeting_policy =
- child->event_targeting_policy();
- if (!child->IsVisible() ||
- event_targeting_policy == ws::mojom::EventTargetingPolicy::NONE)
- continue;
- if (event_targeting_policy !=
- ws::mojom::EventTargetingPolicy::DESCENDANTS_ONLY) {
- gfx::Rect rect_mouse(child->bounds());
- gfx::Rect rect_touch;
- bool touch_and_mouse_are_same = true;
- WindowTargeter* targeter = child->targeter();
- if (!targeter)
- targeter = parent_targeter;
- // Use the |child|'s (when set) or the |window|'s |targeter| to query for
- // possibly expanded hit-test area. Use the |child| bounds with mouse and
- // touch flags when there is no |targeter|.
- if (targeter &&
- targeter->GetHitTestRects(child, &rect_mouse, &rect_touch)) {
- touch_and_mouse_are_same = rect_mouse == rect_touch;
- }
-
- auto shape_rects =
- targeter ? targeter->GetExtraHitTestShapeRects(child) : nullptr;
- if (shape_rects) {
- // The |child| has a complex shape. Clip it to |rect_mouse|.
- const gfx::Vector2d offset = child->bounds().OffsetFromOrigin();
- for (const gfx::Rect& shape_rect : *shape_rects) {
- gfx::Rect rect = shape_rect;
- rect.Offset(offset);
- rect.Intersect(rect_mouse);
- if (rect.IsEmpty())
- continue;
- hit_test_region_list->regions.emplace_back();
- PopulateHitTestRegion(&hit_test_region_list->regions.back(), child,
- viz::HitTestRegionFlags::kHitTestMouse |
- viz::HitTestRegionFlags::kHitTestTouch,
- rect);
- }
- } else {
- // The |child| has possibly same mouse and touch hit-test areas.
- if (!rect_mouse.IsEmpty()) {
- hit_test_region_list->regions.emplace_back();
- PopulateHitTestRegion(&hit_test_region_list->regions.back(), child,
- touch_and_mouse_are_same
- ? (viz::HitTestRegionFlags::kHitTestMouse |
- viz::HitTestRegionFlags::kHitTestTouch)
- : viz::HitTestRegionFlags::kHitTestMouse,
- rect_mouse);
- }
- if (!touch_and_mouse_are_same && !rect_touch.IsEmpty()) {
- hit_test_region_list->regions.emplace_back();
- PopulateHitTestRegion(&hit_test_region_list->regions.back(), child,
- viz::HitTestRegionFlags::kHitTestTouch,
- rect_touch);
- }
- }
- }
- if (event_targeting_policy != ws::mojom::EventTargetingPolicy::TARGET_ONLY)
- GetHitTestDataRecursively(child, hit_test_region_list);
- }
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/hit_test_data_provider_aura.h b/chromium/ui/aura/hit_test_data_provider_aura.h
deleted file mode 100644
index 88419d214cf..00000000000
--- a/chromium/ui/aura/hit_test_data_provider_aura.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 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_AURA_HIT_TEST_DATA_PROVIDER_AURA_H_
-#define UI_AURA_HIT_TEST_DATA_PROVIDER_AURA_H_
-
-#include "base/macros.h"
-#include "components/viz/client/hit_test_data_provider.h"
-#include "ui/aura/aura_export.h"
-
-namespace aura {
-
-class Window;
-
-// A HitTestDataProvider that captures hit-test areas from a aura::Window tree
-// and packages it to be submitted to compositor frame sink. The |window| used
-// when creating the HitTestDataProviderAura should outlive the data provider.
-class AURA_EXPORT HitTestDataProviderAura : public viz::HitTestDataProvider {
- public:
- explicit HitTestDataProviderAura(Window* window);
- ~HitTestDataProviderAura() override;
-
- // HitTestDataProvider:
- base::Optional<viz::HitTestRegionList> GetHitTestData(
- const viz::CompositorFrame& compositor_frame) const override;
-
- private:
- // Recursively walks the children of |window| and uses |window|'s
- // EventTargeter to generate hit-test data for the |window|'s descendants.
- // Populates |hit_test_region_list|.
- void GetHitTestDataRecursively(
- aura::Window* window,
- viz::HitTestRegionList* hit_test_region_list) const;
-
- aura::Window* const window_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(HitTestDataProviderAura);
-};
-
-} // namespace aura
-
-#endif // UI_AURA_HIT_TEST_DATA_PROVIDER_AURA_H_
diff --git a/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc b/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc
deleted file mode 100644
index 79f73481cad..00000000000
--- a/chromium/ui/aura/hit_test_data_provider_aura_unittest.cc
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright 2017 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/aura/hit_test_data_provider_aura.h"
-
-#include "components/viz/client/hit_test_data_provider.h"
-#include "components/viz/common/hit_test/hit_test_region_list.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/mus/window_port_mus_test_helper.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_targeter.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace aura {
-
-namespace {
-
-// Custom WindowTargeter that replaces hit-test area on a window with a frame
-// rectangle and a hole in the middle 1/3.
-// ----------------------
-// | hit hit |
-// | ---------- |
-// | | | |
-// | | No hit | hit |
-// | | | |
-// | hit | | |
-// | ---------- |
-// | hit hit |
-// ----------------------
-class TestHoleWindowTargeter : public WindowTargeter {
- public:
- TestHoleWindowTargeter() = default;
- ~TestHoleWindowTargeter() override {}
-
- private:
- // WindowTargeter:
- std::unique_ptr<WindowTargeter::HitTestRects> GetExtraHitTestShapeRects(
- Window* target) const override {
- gfx::Rect bounds = target->bounds();
- int x0 = 0;
- int x1 = bounds.width() / 3;
- int x2 = bounds.width() - bounds.width() / 3;
- int x3 = bounds.width();
- int y0 = 0;
- int y1 = bounds.height() / 3;
- int y2 = bounds.height() - bounds.height() / 3;
- int y3 = bounds.height();
- auto shape_rects = std::make_unique<WindowTargeter::HitTestRects>();
- shape_rects->emplace_back(x0, y0, bounds.width(), y1 - y0);
- shape_rects->emplace_back(x0, y1, x1 - x0, y2 - y1);
- shape_rects->emplace_back(x2, y1, x3 - x2, y2 - y1);
- shape_rects->emplace_back(x0, y2, bounds.width(), y3 - y2);
- return shape_rects;
- }
-
- DISALLOW_COPY_AND_ASSIGN(TestHoleWindowTargeter);
-};
-
-} // namespace
-
-// Creates a root window, child windows and a viz::HitTestDataProvider.
-// root
-// +- window2
-// |_ window3
-// |_ window4
-class HitTestDataProviderAuraTest : public test::AuraTestBaseMus {
- public:
- HitTestDataProviderAuraTest() {}
- ~HitTestDataProviderAuraTest() override {}
-
- void SetUp() override {
- test::AuraTestBaseMus::SetUp();
-
- root_ = std::make_unique<Window>(nullptr);
- root_->Init(ui::LAYER_NOT_DRAWN);
- root_->SetEventTargeter(std::make_unique<WindowTargeter>());
- root_->SetBounds(gfx::Rect(0, 0, 300, 200));
- root_->Show();
-
- window2_ = new Window(nullptr);
- window2_->Init(ui::LAYER_TEXTURED);
- window2_->SetBounds(gfx::Rect(20, 30, 40, 60));
- window2_->Show();
-
- window3_ = new Window(nullptr);
- window3_->Init(ui::LAYER_TEXTURED);
- window3_->SetEventTargeter(std::make_unique<WindowTargeter>());
- window3_->SetBounds(gfx::Rect(50, 60, 100, 40));
- window3_->Show();
-
- window4_ = new Window(nullptr);
- window4_->Init(ui::LAYER_TEXTURED);
- window4_->SetBounds(gfx::Rect(20, 10, 60, 30));
- window4_->Show();
-
- window3_->AddChild(window4_);
- root_->AddChild(window2_);
- root_->AddChild(window3_);
-
- compositor_frame_ = viz::CompositorFrame();
- hit_test_data_provider_ = std::make_unique<HitTestDataProviderAura>(root());
- }
-
- protected:
- const viz::HitTestDataProvider* hit_test_data_provider() const {
- return hit_test_data_provider_.get();
- }
-
- Window* root() { return root_.get(); }
- Window* window2() { return window2_; }
- Window* window3() { return window3_; }
- Window* window4() { return window4_; }
- viz::CompositorFrame compositor_frame_;
-
- private:
- std::unique_ptr<Window> root_;
- Window* window2_;
- Window* window3_;
- Window* window4_;
- std::unique_ptr<viz::HitTestDataProvider> hit_test_data_provider_;
-
- DISALLOW_COPY_AND_ASSIGN(HitTestDataProviderAuraTest);
-};
-
-// TODO(riajiang): Add test cases for kHitTestChildSurface to ensure
-// that local_surface_id is set and used correctly.
-
-// Tests that the order of reported hit-test regions matches windows Z-order.
-TEST_F(HitTestDataProviderAuraTest, Stacking) {
- const base::Optional<viz::HitTestRegionList> hit_test_data_1 =
- hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data_1);
- EXPECT_EQ(hit_test_data_1->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data_1->bounds, root()->bounds());
- Window* expected_order_1[] = {window3(), window4(), window2()};
- EXPECT_EQ(hit_test_data_1->regions.size(), arraysize(expected_order_1));
- int i = 0;
- for (const auto& region : hit_test_data_1->regions) {
- EXPECT_EQ(region.flags, viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestMouse |
- viz::HitTestRegionFlags::kHitTestTouch);
- EXPECT_EQ(region.frame_sink_id, expected_order_1[i]->GetFrameSinkId());
- EXPECT_EQ(region.rect.ToString(), expected_order_1[i]->bounds().ToString());
- i++;
- }
-
- root()->StackChildAbove(window2(), window3());
- const base::Optional<viz::HitTestRegionList> hit_test_data_2 =
- hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data_2);
- EXPECT_EQ(hit_test_data_2->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data_2->bounds, root()->bounds());
-
- Window* expected_order_2[] = {window2(), window3(), window4()};
- EXPECT_EQ(hit_test_data_2->regions.size(), arraysize(expected_order_2));
- i = 0;
- for (const auto& region : hit_test_data_2->regions) {
- EXPECT_EQ(region.flags, viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestMouse |
- viz::HitTestRegionFlags::kHitTestTouch);
- EXPECT_EQ(region.frame_sink_id, expected_order_2[i]->GetFrameSinkId());
- EXPECT_EQ(region.rect.ToString(), expected_order_2[i]->bounds().ToString());
- i++;
- }
-}
-
-// Tests that the hit-test regions get expanded with a custom event targeter.
-TEST_F(HitTestDataProviderAuraTest, CustomTargeter) {
- constexpr int kMouseInset = -5;
- constexpr int kTouchInset = -10;
- auto targeter = std::make_unique<WindowTargeter>();
- targeter->SetInsets(gfx::Insets(kMouseInset), gfx::Insets(kTouchInset));
- window3()->SetEventTargeter(std::move(targeter));
-
- targeter = std::make_unique<WindowTargeter>();
- targeter->SetInsets(gfx::Insets(kMouseInset), gfx::Insets(kTouchInset));
- window4()->SetEventTargeter(std::move(targeter));
-
- window2()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 2));
- const base::Optional<viz::HitTestRegionList> hit_test_data =
- hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data->bounds, root()->bounds());
-
- // Children of a window that has the custom targeter installed as well as that
- // window will get reported twice, once with hit-test bounds optimized for
- // mouse events and another time with bounds expanded more for touch input.
- struct {
- Window* window;
- uint32_t flags;
- int insets;
- } expected[] = {{window3(),
- viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestMouse,
- kMouseInset},
- {window3(),
- viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestTouch,
- kTouchInset},
- {window4(),
- viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestMouse,
- kMouseInset},
- {window4(),
- viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestTouch,
- kTouchInset},
- {window2(),
- viz::HitTestRegionFlags::kHitTestChildSurface |
- viz::HitTestRegionFlags::kHitTestMouse |
- viz::HitTestRegionFlags::kHitTestTouch,
- 0}};
- ASSERT_EQ(hit_test_data->regions.size(), arraysize(expected));
- ASSERT_EQ(hit_test_data->regions.size(), arraysize(expected));
- ASSERT_EQ(hit_test_data->regions.size(), arraysize(expected));
- int i = 0;
- for (const auto& region : hit_test_data->regions) {
- EXPECT_EQ(region.frame_sink_id, expected[i].window->GetFrameSinkId());
- EXPECT_EQ(region.flags, expected[i].flags);
- gfx::Rect expected_bounds = expected[i].window->bounds();
- expected_bounds.Inset(gfx::Insets(expected[i].insets));
- EXPECT_EQ(region.rect.ToString(), expected_bounds.ToString());
- i++;
- }
-}
-
-// Tests that the complex hit-test shape can be set with a custom targeter.
-TEST_F(HitTestDataProviderAuraTest, HoleTargeter) {
- window3()->SetEventTargeter(std::make_unique<TestHoleWindowTargeter>());
- const base::Optional<viz::HitTestRegionList> hit_test_data =
- hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data->bounds, root()->bounds());
-
- // Children of a container that has the custom targeter installed as well as
- // that container will get reported 4 times for each of the hit test regions
- // defined by the custom targeter.
- // original window3 is at gfx::Rect(50, 60, 100, 40).
- // original window4 is at gfx::Rect(20, 10, 60, 30).
- struct {
- Window* window;
- gfx::Rect bounds;
- } expected[] = {
- {window3(), {50, 60, 100, 13}}, {window3(), {50, 73, 33, 14}},
- {window3(), {117, 73, 33, 14}}, {window3(), {50, 87, 100, 13}},
- {window4(), {20, 10, 60, 10}}, {window4(), {20, 20, 20, 10}},
- {window4(), {60, 20, 20, 10}}, {window4(), {20, 30, 60, 10}},
- {window2(), window2()->bounds()}};
- constexpr uint32_t expected_flags = viz::HitTestRegionFlags::kHitTestMine |
- viz::HitTestRegionFlags::kHitTestMouse |
- viz::HitTestRegionFlags::kHitTestTouch;
- ASSERT_EQ(hit_test_data->regions.size(), arraysize(expected));
- int i = 0;
- for (const auto& region : hit_test_data->regions) {
- EXPECT_EQ(region.frame_sink_id, expected[i].window->GetFrameSinkId());
- EXPECT_EQ(region.flags, expected_flags);
- EXPECT_EQ(region.rect.ToString(), expected[i].bounds.ToString());
- i++;
- }
-}
-
-TEST_F(HitTestDataProviderAuraTest, TargetingPolicies) {
- root()->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::NONE);
- base::Optional<viz::HitTestRegionList> hit_test_data =
- hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_FALSE(hit_test_data);
-
- root()->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::TARGET_ONLY);
- window3()->SetEventTargetingPolicy(
- ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data->regions.size(), 3u);
-
- root()->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::TARGET_ONLY);
- window3()->SetEventTargetingPolicy(
- ws::mojom::EventTargetingPolicy::TARGET_ONLY);
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data->regions.size(), 2u);
-
- root()->SetEventTargetingPolicy(
- ws::mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- window3()->SetEventTargetingPolicy(
- ws::mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->flags, viz::HitTestRegionFlags::kHitTestIgnore);
- EXPECT_EQ(hit_test_data->regions.size(), 2u);
-
- root()->SetEventTargetingPolicy(
- ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
- window3()->SetEventTargetingPolicy(
- ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->flags, viz::HitTestRegionFlags::kHitTestMine);
- EXPECT_EQ(hit_test_data->regions.size(), 3u);
-}
-
-// Tests that we do not submit hit-test data for invisible windows and for
-// children of a child surface.
-TEST_F(HitTestDataProviderAuraTest, DoNotSubmit) {
- base::Optional<viz::HitTestRegionList> hit_test_data =
- hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->regions.size(), 3u);
-
- window2()->Hide();
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->regions.size(), 2u);
-
- window3()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 3));
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->regions.size(), 1u);
-
- root()->Hide();
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_FALSE(hit_test_data);
-
- root()->Show();
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->regions.size(), 1u);
- root()->SetEmbedFrameSinkId(viz::FrameSinkId(1, 1));
- hit_test_data = hit_test_data_provider()->GetHitTestData(compositor_frame_);
- ASSERT_TRUE(hit_test_data);
- EXPECT_EQ(hit_test_data->regions.size(), 0u);
-}
-
-} // namespace aura
diff --git a/chromium/ui/aura/local/window_port_local.cc b/chromium/ui/aura/local/window_port_local.cc
index 454a3dea5b2..e11dbb65e4b 100644
--- a/chromium/ui/aura/local/window_port_local.cc
+++ b/chromium/ui/aura/local/window_port_local.cc
@@ -8,13 +8,14 @@
#include "components/viz/client/hit_test_data_provider_draw_quad.h"
#include "components/viz/client/local_surface_id_provider.h"
#include "components/viz/common/features.h"
+#include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
-#include "ui/aura/hit_test_data_provider_aura.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
+#include "ui/aura/window_occlusion_tracker.h"
#include "ui/base/layout.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
@@ -89,8 +90,10 @@ void WindowPortLocal::OnDeviceScaleFactorChanged(
IsEmbeddingExternalContent()) {
last_device_scale_factor_ = new_device_scale_factor;
parent_local_surface_id_allocator_->GenerateId();
- if (frame_sink_)
- frame_sink_->SetLocalSurfaceId(GetCurrentLocalSurfaceId());
+ if (frame_sink_) {
+ frame_sink_->SetLocalSurfaceId(
+ GetCurrentLocalSurfaceIdAllocation().local_surface_id());
+ }
}
ScopedCursorHider hider(window_);
@@ -115,8 +118,10 @@ void WindowPortLocal::OnDidChangeBounds(const gfx::Rect& old_bounds,
IsEmbeddingExternalContent()) {
last_size_ = new_bounds.size();
parent_local_surface_id_allocator_->GenerateId();
- if (frame_sink_)
- frame_sink_->SetLocalSurfaceId(GetCurrentLocalSurfaceId());
+ if (frame_sink_) {
+ frame_sink_->SetLocalSurfaceId(
+ GetCurrentLocalSurfaceIdAllocation().local_surface_id());
+ }
}
}
@@ -150,7 +155,8 @@ WindowPortLocal::CreateLayerTreeFrameSink() {
viz::mojom::CompositorFrameSinkClientPtr client;
viz::mojom::CompositorFrameSinkClientRequest client_request =
mojo::MakeRequest(&client);
- host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
+ host_frame_sink_manager->RegisterFrameSinkId(
+ frame_sink_id_, this, viz::ReportFirstSurfaceActivation::kYes);
window_->SetEmbedFrameSinkId(frame_sink_id_);
host_frame_sink_manager->CreateCompositorFrameSink(
frame_sink_id_, std::move(sink_request), std::move(client));
@@ -162,18 +168,15 @@ WindowPortLocal::CreateLayerTreeFrameSink() {
params.pipes.client_request = std::move(client_request);
params.enable_surface_synchronization = true;
params.client_name = kExo;
+ bool root_accepts_events =
+ (window_->event_targeting_policy() ==
+ ws::mojom::EventTargetingPolicy::TARGET_ONLY) ||
+ (window_->event_targeting_policy() ==
+ ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
if (features::IsVizHitTestingDrawQuadEnabled()) {
- bool root_accepts_events =
- (window_->event_targeting_policy() ==
- ws::mojom::EventTargetingPolicy::TARGET_ONLY) ||
- (window_->event_targeting_policy() ==
- ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
params.hit_test_data_provider =
std::make_unique<viz::HitTestDataProviderDrawQuad>(
true /* should_ask_for_child_region */, root_accepts_events);
- } else {
- params.hit_test_data_provider =
- std::make_unique<HitTestDataProviderAura>(window_);
}
auto frame_sink =
std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>(
@@ -187,14 +190,14 @@ WindowPortLocal::CreateLayerTreeFrameSink() {
void WindowPortLocal::AllocateLocalSurfaceId() {
if (!parent_local_surface_id_allocator_)
parent_local_surface_id_allocator_.emplace();
- else
- parent_local_surface_id_allocator_->GenerateId();
+ parent_local_surface_id_allocator_->GenerateId();
UpdateLocalSurfaceId();
}
-bool WindowPortLocal::IsLocalSurfaceIdAllocationSuppressed() const {
- return parent_local_surface_id_allocator_ &&
- parent_local_surface_id_allocator_->is_allocation_suppressed();
+void WindowPortLocal::InvalidateLocalSurfaceId() {
+ if (!parent_local_surface_id_allocator_)
+ return;
+ parent_local_surface_id_allocator_->Invalidate();
}
viz::ScopedSurfaceIdAllocator WindowPortLocal::GetSurfaceIdAllocator(
@@ -204,16 +207,18 @@ viz::ScopedSurfaceIdAllocator WindowPortLocal::GetSurfaceIdAllocator(
}
void WindowPortLocal::UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) {
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) {
parent_local_surface_id_allocator_->UpdateFromChild(
- embedded_client_local_surface_id);
+ embedded_client_local_surface_id_allocation);
UpdateLocalSurfaceId();
}
-const viz::LocalSurfaceId& WindowPortLocal::GetLocalSurfaceId() {
+const viz::LocalSurfaceIdAllocation&
+WindowPortLocal::GetLocalSurfaceIdAllocation() {
if (!parent_local_surface_id_allocator_)
AllocateLocalSurfaceId();
- return GetCurrentLocalSurfaceId();
+ return GetCurrentLocalSurfaceIdAllocation();
}
void WindowPortLocal::OnEventTargetingPolicyChanged() {}
@@ -222,14 +227,17 @@ bool WindowPortLocal::ShouldRestackTransientChildren() {
return true;
}
+void WindowPortLocal::TrackOcclusionState() {
+ window_->env()->GetWindowOcclusionTracker()->Track(window_);
+}
+
void WindowPortLocal::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
DCHECK_EQ(surface_info.id().frame_sink_id(), window_->GetFrameSinkId());
- window_->layer()->SetShowPrimarySurface(
- surface_info.id(), window_->bounds().size(), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(),
- false /* stretch_content_to_fill_bounds */);
- window_->layer()->SetFallbackSurfaceId(surface_info.id());
+ window_->layer()->SetShowSurface(surface_info.id(), window_->bounds().size(),
+ SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(),
+ false /* stretch_content_to_fill_bounds */);
}
void WindowPortLocal::OnFrameTokenChanged(uint32_t frame_token) {}
@@ -237,12 +245,16 @@ void WindowPortLocal::OnFrameTokenChanged(uint32_t frame_token) {}
void WindowPortLocal::UpdateLocalSurfaceId() {
last_device_scale_factor_ = ui::GetScaleFactorForNativeView(window_);
last_size_ = window_->bounds().size();
- if (frame_sink_)
- frame_sink_->SetLocalSurfaceId(GetCurrentLocalSurfaceId());
+ if (frame_sink_) {
+ frame_sink_->SetLocalSurfaceId(
+ GetCurrentLocalSurfaceIdAllocation().local_surface_id());
+ }
}
-const viz::LocalSurfaceId& WindowPortLocal::GetCurrentLocalSurfaceId() const {
- return parent_local_surface_id_allocator_->GetCurrentLocalSurfaceId();
+const viz::LocalSurfaceIdAllocation&
+WindowPortLocal::GetCurrentLocalSurfaceIdAllocation() const {
+ return parent_local_surface_id_allocator_
+ ->GetCurrentLocalSurfaceIdAllocation();
}
bool WindowPortLocal::IsEmbeddingExternalContent() const {
diff --git a/chromium/ui/aura/local/window_port_local.h b/chromium/ui/aura/local/window_port_local.h
index 732845039f0..d0744d6bdfe 100644
--- a/chromium/ui/aura/local/window_port_local.h
+++ b/chromium/ui/aura/local/window_port_local.h
@@ -49,14 +49,16 @@ class AURA_EXPORT WindowPortLocal : public WindowPort,
std::unique_ptr<ui::PropertyData> data) override;
std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override;
void AllocateLocalSurfaceId() override;
- bool IsLocalSurfaceIdAllocationSuppressed() const override;
viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) override;
+ void InvalidateLocalSurfaceId() override;
void UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) override;
- const viz::LocalSurfaceId& GetLocalSurfaceId() override;
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) override;
+ const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() override;
void OnEventTargetingPolicyChanged() override;
bool ShouldRestackTransientChildren() override;
+ void TrackOcclusionState() override;
// viz::HostFrameSinkClient:
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
@@ -64,7 +66,8 @@ class AURA_EXPORT WindowPortLocal : public WindowPort,
private:
void UpdateLocalSurfaceId();
- const viz::LocalSurfaceId& GetCurrentLocalSurfaceId() const;
+ const viz::LocalSurfaceIdAllocation& GetCurrentLocalSurfaceIdAllocation()
+ const;
bool IsEmbeddingExternalContent() const;
Window* const window_;
diff --git a/chromium/ui/aura/mus/DEPS b/chromium/ui/aura/mus/DEPS
index 1b310c00168..5971c424da8 100644
--- a/chromium/ui/aura/mus/DEPS
+++ b/chromium/ui/aura/mus/DEPS
@@ -9,6 +9,7 @@ include_rules = [
"+components/viz/common",
"+components/viz/service/frame_sinks/frame_sink_manager_impl.h",
"+gpu/command_buffer/client/gpu_memory_buffer_manager.h",
+ "+gpu/command_buffer/common",
"+gpu/ipc/client/gpu_channel_host.h",
"+mojo/public/cpp/system/buffer.h",
"+mojo/public/cpp/system/platform_handle.h",
diff --git a/chromium/ui/aura/mus/client_surface_embedder.cc b/chromium/ui/aura/mus/client_surface_embedder.cc
index 340eef15b1f..5c33f34c7fa 100644
--- a/chromium/ui/aura/mus/client_surface_embedder.cc
+++ b/chromium/ui/aura/mus/client_surface_embedder.cc
@@ -35,22 +35,20 @@ ClientSurfaceEmbedder::ClientSurfaceEmbedder(
ClientSurfaceEmbedder::~ClientSurfaceEmbedder() = default;
-void ClientSurfaceEmbedder::SetPrimarySurfaceId(
- const viz::SurfaceId& surface_id) {
- surface_layer_owner_->layer()->SetShowPrimarySurface(
+void ClientSurfaceEmbedder::SetSurfaceId(const viz::SurfaceId& surface_id) {
+ surface_layer_owner_->layer()->SetShowSurface(
surface_id, window_->bounds().size(), SK_ColorWHITE,
cc::DeadlinePolicy::UseDefaultDeadline(),
false /* stretch_content_to_fill_bounds */);
}
bool ClientSurfaceEmbedder::HasPrimarySurfaceId() const {
- return surface_layer_owner_->layer()->GetPrimarySurfaceId() != nullptr;
+ return surface_layer_owner_->layer()->GetSurfaceId() != nullptr;
}
void ClientSurfaceEmbedder::SetFallbackSurfaceInfo(
const viz::SurfaceInfo& surface_info) {
fallback_surface_info_ = surface_info;
- surface_layer_owner_->layer()->SetFallbackSurfaceId(surface_info.id());
UpdateSizeAndGutters();
}
@@ -121,9 +119,8 @@ ui::Layer* ClientSurfaceEmbedder::BottomGutterForTesting() {
return bottom_gutter_owner_ ? bottom_gutter_owner_->layer() : nullptr;
}
-const viz::SurfaceId& ClientSurfaceEmbedder::GetPrimarySurfaceIdForTesting()
- const {
- return *surface_layer_owner_->layer()->GetPrimarySurfaceId();
+const viz::SurfaceId& ClientSurfaceEmbedder::GetSurfaceIdForTesting() const {
+ return *surface_layer_owner_->layer()->GetSurfaceId();
}
} // namespace aura
diff --git a/chromium/ui/aura/mus/client_surface_embedder.h b/chromium/ui/aura/mus/client_surface_embedder.h
index bcf1ce1bace..c1940e98f65 100644
--- a/chromium/ui/aura/mus/client_surface_embedder.h
+++ b/chromium/ui/aura/mus/client_surface_embedder.h
@@ -35,7 +35,7 @@ class AURA_EXPORT ClientSurfaceEmbedder {
// Updates the clip layer and primary SurfaceId of the surface layer based
// on the provided |surface_id|.
- void SetPrimarySurfaceId(const viz::SurfaceId& surface_id);
+ void SetSurfaceId(const viz::SurfaceId& surface_id);
bool HasPrimarySurfaceId() const;
@@ -54,7 +54,7 @@ class AURA_EXPORT ClientSurfaceEmbedder {
ui::Layer* BottomGutterForTesting();
- const viz::SurfaceId& GetPrimarySurfaceIdForTesting() const;
+ const viz::SurfaceId& GetSurfaceIdForTesting() const;
private:
// The window which embeds the client.
diff --git a/chromium/ui/aura/mus/embed_root.h b/chromium/ui/aura/mus/embed_root.h
index 46293ee61fc..90bd23aa7df 100644
--- a/chromium/ui/aura/mus/embed_root.h
+++ b/chromium/ui/aura/mus/embed_root.h
@@ -45,7 +45,7 @@ class AURA_EXPORT EmbedRoot {
private:
friend class WindowTreeClient;
- friend class WindowTreeClientPrivate;
+ friend class WindowTreeClientTestApi;
EmbedRoot(WindowTreeClient* window_tree_client,
EmbedRootDelegate* delegate,
diff --git a/chromium/ui/aura/mus/focus_synchronizer.cc b/chromium/ui/aura/mus/focus_synchronizer.cc
index e70c82509da..c7970243e3e 100644
--- a/chromium/ui/aura/mus/focus_synchronizer.cc
+++ b/chromium/ui/aura/mus/focus_synchronizer.cc
@@ -90,10 +90,17 @@ void FocusSynchronizer::SetActiveFocusClientInternal(
}
void FocusSynchronizer::SetFocusedWindow(WindowMus* window) {
- const uint32_t change_id = delegate_->CreateChangeIdForFocus(focused_window_);
+ WindowMus* prev_focused_window = focused_window_;
focused_window_ = window;
- window_tree_->SetFocus(change_id,
- window ? window->server_id() : kInvalidServerId);
+ // Do not call SetFocus() for resetting the focus. It'll be simply ignored on
+ // the server anyway, but the client can't set the new focused window when the
+ // server picks up a new focused window during SetFocus() and its reply.
+ // See https://crbug.com/897875
+ if (!window)
+ return;
+ const uint32_t change_id =
+ delegate_->CreateChangeIdForFocus(prev_focused_window);
+ window_tree_->SetFocus(change_id, window->server_id());
}
void FocusSynchronizer::OnActiveFocusClientChanged(
diff --git a/chromium/ui/aura/mus/gesture_recognizer_impl_mus.cc b/chromium/ui/aura/mus/gesture_recognizer_impl_mus.cc
new file mode 100644
index 00000000000..4de552212d8
--- /dev/null
+++ b/chromium/ui/aura/mus/gesture_recognizer_impl_mus.cc
@@ -0,0 +1,73 @@
+// 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/aura/mus/gesture_recognizer_impl_mus.h"
+
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+
+namespace aura {
+
+GestureRecognizerImplMus::GestureRecognizerImplMus(
+ aura::WindowTreeClient* client)
+ : client_(client) {
+ client->AddObserver(this);
+}
+
+GestureRecognizerImplMus::~GestureRecognizerImplMus() {
+ OnWindowMoveEnded(false);
+ if (client_)
+ client_->RemoveObserver(this);
+}
+
+void GestureRecognizerImplMus::OnWillDestroyClient(
+ aura::WindowTreeClient* client) {
+ DCHECK_EQ(client_, client);
+ OnWindowMoveEnded(false);
+ client_->RemoveObserver(this);
+ client_ = nullptr;
+}
+
+void GestureRecognizerImplMus::OnWindowMoveStarted(
+ aura::Window* window,
+ const gfx::Point& cursor_location,
+ ws::mojom::MoveLoopSource source) {
+ DCHECK(!moving_window_);
+ if (source != ws::mojom::MoveLoopSource::TOUCH)
+ return;
+ moving_window_ = window;
+ cursor_offset_ = cursor_location - window->GetBoundsInScreen().origin();
+}
+
+void GestureRecognizerImplMus::OnWindowMoveEnded(bool success) {
+ moving_window_ = nullptr;
+}
+
+bool GestureRecognizerImplMus::GetLastTouchPointForTarget(
+ ui::GestureConsumer* consumer,
+ gfx::PointF* point) {
+ // When a window is moving, the touch events are handled completely within the
+ // shell and do not come to the client and so the default
+ // GetLastTouchPointForTarget won't work. Instead, this reports the last
+ // location through PointerWatcher. See also
+ // https://docs.google.com/document/d/1AKeK8IuF-j2TJ-2sPsewORXdjnr6oAzy5nnR1zwrsfc/edit#
+ aura::Window* target_window = static_cast<aura::Window*>(consumer);
+ if (moving_window_ && moving_window_->Contains(target_window)) {
+ aura::client::ScreenPositionClient* client =
+ aura::client::GetScreenPositionClient(target_window->GetRootWindow());
+ if (client) {
+ // Use the original offset when the window move started. ui::EventObserver
+ // isn't used since its OnEvent may be called slightly later than window
+ // move (bounds change) is conducted. See crbug.com/901540.
+ point->set_x(cursor_offset_.x());
+ point->set_y(cursor_offset_.y());
+ return true;
+ }
+ }
+ return GestureRecognizerImpl::GetLastTouchPointForTarget(consumer, point);
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/mus/gesture_recognizer_impl_mus.h b/chromium/ui/aura/mus/gesture_recognizer_impl_mus.h
new file mode 100644
index 00000000000..4c46d3e6931
--- /dev/null
+++ b/chromium/ui/aura/mus/gesture_recognizer_impl_mus.h
@@ -0,0 +1,51 @@
+// 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_AURA_MUS_GESTURE_RECOGNIZER_IMPL_MUS_H_
+#define UI_AURA_MUS_GESTURE_RECOGNIZER_IMPL_MUS_H_
+
+#include "base/macros.h"
+#include "ui/aura/mus/window_tree_client_observer.h"
+#include "ui/events/gestures/gesture_recognizer_impl.h"
+
+namespace ui {
+class PointF;
+}
+
+namespace aura {
+
+class Window;
+class WindowTreeClient;
+
+// GestureRecognizer implementation for Mus. This is mostly identical to
+// GestureRecognizerImpl, but it handles keeping GetLastTouchPointForTarget in
+// sync with the server when the touch events are handled within the server.
+class GestureRecognizerImplMus : public ui::GestureRecognizerImpl,
+ public aura::WindowTreeClientObserver {
+ public:
+ explicit GestureRecognizerImplMus(aura::WindowTreeClient* client);
+ ~GestureRecognizerImplMus() override;
+
+ private:
+ // ui::GestureRecognizerImpl:
+ bool GetLastTouchPointForTarget(ui::GestureConsumer* consumer,
+ gfx::PointF* point) override;
+
+ // aura::WindowTreeClientObserver:
+ void OnWillDestroyClient(aura::WindowTreeClient* client) override;
+ void OnWindowMoveStarted(aura::Window* window,
+ const gfx::Point& cursor_location,
+ ws::mojom::MoveLoopSource source) override;
+ void OnWindowMoveEnded(bool success) override;
+
+ aura::WindowTreeClient* client_;
+ aura::Window* moving_window_ = nullptr;
+ gfx::Vector2d cursor_offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureRecognizerImplMus);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_MUS_GESTURE_RECOGNIZER_IMPL_MUS_H_
diff --git a/chromium/ui/aura/mus/gesture_synchronizer_unittest.cc b/chromium/ui/aura/mus/gesture_synchronizer_unittest.cc
index cd1e7e0dee8..81b75132a55 100644
--- a/chromium/ui/aura/mus/gesture_synchronizer_unittest.cc
+++ b/chromium/ui/aura/mus/gesture_synchronizer_unittest.cc
@@ -12,6 +12,9 @@
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/test/aura_mus_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/events/test/event_generator.h"
namespace aura {
@@ -20,31 +23,17 @@ class GestureSynchronizerTest : public test::AuraMusClientTestBase {
GestureSynchronizerTest() = default;
~GestureSynchronizerTest() override = default;
- void SetUp() override {
- test::AuraMusClientTestBase::SetUp();
-
- window_tree_host_ = std::make_unique<WindowTreeHostMus>(
- CreateInitParamsForTopLevel(window_tree_client_impl()));
- window_tree_host_->InitHost();
- window_tree_host_->Show();
- }
-
protected:
ui::GestureRecognizer* gesture_recognizer() {
return Env::GetInstance()->gesture_recognizer();
}
- std::unique_ptr<Window> NewWindow() {
- auto window = std::make_unique<Window>(nullptr);
- window->Init(ui::LAYER_NOT_DRAWN);
- window_tree_host_->window()->AddChild(window.get());
- window->Show();
- return window;
+ std::unique_ptr<Window> NewWindow(aura::WindowDelegate* delegate = nullptr) {
+ return std::unique_ptr<Window>(aura::test::CreateTestWindowWithDelegate(
+ delegate, 0, gfx::Rect(0, 0, 100, 100), root_window()));
}
private:
- std::unique_ptr<WindowTreeHostMus> window_tree_host_;
-
DISALLOW_COPY_AND_ASSIGN(GestureSynchronizerTest);
};
@@ -61,12 +50,23 @@ TEST_F(GestureSynchronizerTest, CancelActiveTouchesExceptForNullptr) {
}
TEST_F(GestureSynchronizerTest, CancelActiveTouches) {
- std::unique_ptr<Window> window = NewWindow();
+ aura::test::TestWindowDelegate delegate;
+ std::unique_ptr<Window> window = NewWindow(&delegate);
+ ui::test::EventGenerator event_generator(root_window());
+ event_generator.MoveTouch(window->GetBoundsInScreen().CenterPoint());
+ event_generator.PressTouch();
gesture_recognizer()->CancelActiveTouches(window.get());
EXPECT_EQ(window_tree()->last_cancelled_window_id(),
WindowMus::Get(window.get())->server_id());
}
+TEST_F(GestureSynchronizerTest, CancelActiveTouchesNotSentWithoutTouches) {
+ aura::test::TestWindowDelegate delegate;
+ std::unique_ptr<Window> window = NewWindow(&delegate);
+ gesture_recognizer()->CancelActiveTouches(window.get());
+ EXPECT_EQ(window_tree()->last_cancelled_window_id(), 0u);
+}
+
TEST_F(GestureSynchronizerTest, TransferGestureEventsTo) {
std::unique_ptr<Window> window1 = NewWindow();
std::unique_ptr<Window> window2 = NewWindow();
diff --git a/chromium/ui/aura/mus/input_method_mus.cc b/chromium/ui/aura/mus/input_method_mus.cc
index cf1328a6e05..9a1d3c19ebe 100644
--- a/chromium/ui/aura/mus/input_method_mus.cc
+++ b/chromium/ui/aura/mus/input_method_mus.cc
@@ -112,6 +112,8 @@ void InputMethodMus::OnCaretBoundsChanged(const ui::TextInputClient* client) {
if (input_method_)
input_method_->OnCaretBoundsChanged(client->GetCaretBounds());
+
+ NotifyTextInputCaretBoundsChanged(client);
}
void InputMethodMus::CancelComposition(const ui::TextInputClient* client) {
@@ -136,6 +138,7 @@ bool InputMethodMus::IsCandidatePopupOpen() const {
}
void InputMethodMus::ShowVirtualKeyboardIfEnabled() {
+ InputMethodBase::ShowVirtualKeyboardIfEnabled();
if (input_method_)
input_method_->ShowVirtualKeyboardIfEnabled();
}
diff --git a/chromium/ui/aura/mus/mus_context_factory.cc b/chromium/ui/aura/mus/mus_context_factory.cc
index 7b25807bf1c..eef0df5d05a 100644
--- a/chromium/ui/aura/mus/mus_context_factory.cc
+++ b/chromium/ui/aura/mus/mus_context_factory.cc
@@ -9,7 +9,10 @@
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/host/renderer_settings_creation.h"
+#include "gpu/command_buffer/common/scheduling_priority.h"
+#include "services/ws/public/cpp/gpu/command_buffer_metrics.h"
#include "services/ws/public/cpp/gpu/gpu.h"
+#include "services/ws/public/cpp/gpu/shared_worker_context_provider_factory.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor_switches.h"
@@ -24,6 +27,10 @@ MusContextFactory::MusContextFactory(ws::Gpu* gpu)
MusContextFactory::~MusContextFactory() {}
+void MusContextFactory::ResetSharedWorkerContextProvider() {
+ shared_worker_context_provider_factory_.reset();
+}
+
void MusContextFactory::OnEstablishedGpuChannel(
base::WeakPtr<ui::Compositor> compositor,
scoped_refptr<gpu::GpuChannelHost> gpu_channel) {
@@ -35,16 +42,42 @@ void MusContextFactory::OnEstablishedGpuChannel(
DCHECK(window_port);
scoped_refptr<viz::ContextProvider> context_provider =
- gpu_->CreateContextProvider(std::move(gpu_channel));
+ gpu_->CreateContextProvider(gpu_channel);
// If the binding fails, then we need to return early since the compositor
// expects a successfully initialized/bound provider.
if (context_provider->BindToCurrentThread() != gpu::ContextResult::kSuccess) {
// TODO(danakj): We should retry if the result was not kFatalFailure.
return;
}
+
+ if (!shared_worker_context_provider_factory_) {
+ // TODO(sky): unify these with values from ws::Gpu.
+ const int32_t stream_id = 0;
+ const gpu::SchedulingPriority stream_priority =
+ gpu::SchedulingPriority::kNormal;
+ const GURL identity_url("chrome://gpu/MusContextFactory");
+ shared_worker_context_provider_factory_ =
+ std::make_unique<ws::SharedWorkerContextProviderFactory>(
+ stream_id, stream_priority, identity_url,
+ ws::command_buffer_metrics::ContextType::MUS_CLIENT);
+ }
+ scoped_refptr<viz::RasterContextProvider> shared_worker_context_provider;
+
+ auto shared_worker_validate_result =
+ shared_worker_context_provider_factory_->Validate(
+ gpu_channel, GetGpuMemoryBufferManager());
+ if (shared_worker_validate_result == gpu::ContextResult::kSuccess) {
+ shared_worker_context_provider =
+ shared_worker_context_provider_factory_->provider();
+ } else {
+ shared_worker_context_provider_factory_.reset();
+ }
+
std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink =
- window_port->RequestLayerTreeFrameSink(std::move(context_provider),
- gpu_->gpu_memory_buffer_manager());
+ window_port->RequestLayerTreeFrameSink(
+ std::move(context_provider),
+ std::move(shared_worker_context_provider),
+ gpu_->gpu_memory_buffer_manager());
compositor->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
}
@@ -73,10 +106,6 @@ void MusContextFactory::RemoveCompositor(ui::Compositor* compositor) {
// NOTIMPLEMENTED();
}
-double MusContextFactory::GetRefreshRate() const {
- return 60.0;
-}
-
gpu::GpuMemoryBufferManager* MusContextFactory::GetGpuMemoryBufferManager() {
return gpu_->gpu_memory_buffer_manager();
}
diff --git a/chromium/ui/aura/mus/mus_context_factory.h b/chromium/ui/aura/mus/mus_context_factory.h
index 25e0c0d09af..84ecc52f3aa 100644
--- a/chromium/ui/aura/mus/mus_context_factory.h
+++ b/chromium/ui/aura/mus/mus_context_factory.h
@@ -23,6 +23,7 @@ class GpuChannelHost;
namespace ws {
class Gpu;
+class SharedWorkerContextProviderFactory;
}
namespace aura {
@@ -33,6 +34,10 @@ class AURA_EXPORT MusContextFactory : public ui::ContextFactory {
explicit MusContextFactory(ws::Gpu* gpu);
~MusContextFactory() override;
+ // Drops the references to the RasterContextProvider. This may be called to
+ // ensure a particular shutdown ordering.
+ void ResetSharedWorkerContextProvider();
+
private:
// Callback function for Gpu::EstablishGpuChannel().
void OnEstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor,
@@ -44,7 +49,6 @@ class AURA_EXPORT MusContextFactory : public ui::ContextFactory {
scoped_refptr<viz::ContextProvider> SharedMainThreadContextProvider()
override;
void RemoveCompositor(ui::Compositor* compositor) override;
- double GetRefreshRate() const override;
gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
cc::TaskGraphRunner* GetTaskGraphRunner() override;
void AddObserver(ui::ContextFactoryObserver* observer) override {}
@@ -54,6 +58,8 @@ class AURA_EXPORT MusContextFactory : public ui::ContextFactory {
ws::RasterThreadHelper raster_thread_helper_;
ws::Gpu* gpu_;
scoped_refptr<viz::ContextProvider> shared_main_thread_context_provider_;
+ std::unique_ptr<ws::SharedWorkerContextProviderFactory>
+ shared_worker_context_provider_factory_;
base::WeakPtrFactory<MusContextFactory> weak_ptr_factory_;
diff --git a/chromium/ui/aura/mus/property_converter.cc b/chromium/ui/aura/mus/property_converter.cc
index 0d0e345318e..86b43b087af 100644
--- a/chromium/ui/aura/mus/property_converter.cc
+++ b/chromium/ui/aura/mus/property_converter.cc
@@ -81,10 +81,6 @@ PropertyConverter::PropertyConverter() {
RegisterPrimitiveProperty(client::kDrawAttentionKey,
ws::mojom::WindowManager::kDrawAttention_Property,
CreateAcceptAnyValueCallback());
- RegisterPrimitiveProperty(
- client::kImmersiveFullscreenKey,
- ws::mojom::WindowManager::kImmersiveFullscreen_Property,
- CreateAcceptAnyValueCallback());
RegisterPrimitiveProperty(client::kResizeBehaviorKey,
ws::mojom::WindowManager::kResizeBehavior_Property,
base::Bind(&ValidateResizeBehaviour));
@@ -112,6 +108,10 @@ PropertyConverter::PropertyConverter() {
RegisterWindowPtrProperty(
client::kChildModalParentKey,
ws::mojom::WindowManager::kChildModalParent_Property);
+ RegisterPrimitiveProperty(
+ client::kClientWindowHasContent,
+ ws::mojom::WindowManager::kClientWindowHasContent_Property,
+ CreateAcceptAnyValueCallback());
}
PropertyConverter::~PropertyConverter() {}
diff --git a/chromium/ui/aura/mus/property_utils.cc b/chromium/ui/aura/mus/property_utils.cc
index 94546d1f2ec..d261320a22c 100644
--- a/chromium/ui/aura/mus/property_utils.cc
+++ b/chromium/ui/aura/mus/property_utils.cc
@@ -4,12 +4,12 @@
#include "ui/aura/mus/property_utils.h"
+#include "base/logging.h"
#include "services/ws/public/cpp/property_type_converters.h"
#include "services/ws/public/mojom/window_manager.mojom.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/window_types.h"
-#include "ui/aura/window.h"
namespace aura {
namespace {
@@ -57,4 +57,36 @@ ws::mojom::WindowType GetWindowTypeFromProperties(
mojo::ConvertTo<int32_t>(iter->second));
}
+ws::mojom::OcclusionState WindowOcclusionStateToMojom(
+ Window::OcclusionState input) {
+ switch (input) {
+ case Window::OcclusionState::UNKNOWN:
+ return ws::mojom::OcclusionState::kUnknown;
+ case Window::OcclusionState::VISIBLE:
+ return ws::mojom::OcclusionState::kVisible;
+ case Window::OcclusionState::OCCLUDED:
+ return ws::mojom::OcclusionState::kOccluded;
+ case Window::OcclusionState::HIDDEN:
+ return ws::mojom::OcclusionState::kHidden;
+ }
+ NOTREACHED();
+ return ws::mojom::OcclusionState::kUnknown;
+}
+
+Window::OcclusionState WindowOcclusionStateFromMojom(
+ ws::mojom::OcclusionState input) {
+ switch (input) {
+ case ws::mojom::OcclusionState::kUnknown:
+ return Window::OcclusionState::UNKNOWN;
+ case ws::mojom::OcclusionState::kVisible:
+ return aura::Window::OcclusionState::VISIBLE;
+ case ws::mojom::OcclusionState::kOccluded:
+ return Window::OcclusionState::OCCLUDED;
+ case ws::mojom::OcclusionState::kHidden:
+ return Window::OcclusionState::HIDDEN;
+ }
+ NOTREACHED();
+ return Window::OcclusionState::UNKNOWN;
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/property_utils.h b/chromium/ui/aura/mus/property_utils.h
index eb16e2ef075..0416f1893b7 100644
--- a/chromium/ui/aura/mus/property_utils.h
+++ b/chromium/ui/aura/mus/property_utils.h
@@ -11,17 +11,17 @@
#include <vector>
#include "ui/aura/aura_export.h"
+#include "ui/aura/window.h"
namespace ws {
namespace mojom {
+enum class OcclusionState;
enum class WindowType;
}
}
namespace aura {
-class Window;
-
// Configures the two window type properties on |window|. Specifically this
// sets the property client::kWindowTypeKey as well as calling SetType().
// This *must* be called before Init(). No-op for WindowType::UNKNOWN.
@@ -32,6 +32,12 @@ AURA_EXPORT void SetWindowType(Window* window,
AURA_EXPORT ws::mojom::WindowType GetWindowTypeFromProperties(
const std::map<std::string, std::vector<uint8_t>>& properties);
+// Helpers to map Window::OcclusionState to/from its ws::mojom equivalent.
+AURA_EXPORT ws::mojom::OcclusionState WindowOcclusionStateToMojom(
+ Window::OcclusionState input);
+AURA_EXPORT Window::OcclusionState WindowOcclusionStateFromMojom(
+ ws::mojom::OcclusionState input);
+
} // namespace aura
#endif // UI_AURA_MUS_PROPERTY_UTILS_H_
diff --git a/chromium/ui/aura/mus/text_input_client_impl.cc b/chromium/ui/aura/mus/text_input_client_impl.cc
index 29121c53a7e..3d8a041f2ee 100644
--- a/chromium/ui/aura/mus/text_input_client_impl.cc
+++ b/chromium/ui/aura/mus/text_input_client_impl.cc
@@ -4,12 +4,28 @@
#include "ui/aura/mus/text_input_client_impl.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "services/ws/public/mojom/ime/ime.mojom.h"
#include "ui/aura/mus/input_method_mus.h"
#include "ui/base/ime/text_input_client.h"
+#include "ui/events/event_utils.h"
namespace aura {
+namespace {
+
+// Called when event processing processes an event. |callback| is the callback
+// supplied to DispatchKeyEventPostIMECallback() and |handled| is true if the
+// event was handled.
+void OnKeyEventProcessed(
+ ws::mojom::TextInputClient::DispatchKeyEventPostIMECallback callback,
+ bool handled) {
+ if (callback)
+ std::move(callback).Run(handled);
+}
+
+} // namespace
TextInputClientImpl::TextInputClientImpl(
ui::TextInputClient* text_input_client,
@@ -18,7 +34,7 @@ TextInputClientImpl::TextInputClientImpl(
binding_(this),
delegate_(delegate) {}
-TextInputClientImpl::~TextInputClientImpl() {}
+TextInputClientImpl::~TextInputClientImpl() = default;
ws::mojom::TextInputClientPtr TextInputClientImpl::CreateInterfacePtrAndBind() {
ws::mojom::TextInputClientPtr ptr;
@@ -51,10 +67,27 @@ void TextInputClientImpl::InsertChar(std::unique_ptr<ui::Event> event) {
void TextInputClientImpl::DispatchKeyEventPostIME(
std::unique_ptr<ui::Event> event,
DispatchKeyEventPostIMECallback callback) {
- if (delegate_) {
- delegate_->DispatchKeyEventPostIME(event->AsKeyEvent(),
- std::move(callback));
+ if (!delegate_) {
+ if (callback)
+ std::move(callback).Run(false);
+ return;
}
+ ui::KeyEvent* key_event = event->AsKeyEvent();
+
+ // Install a callback on the event. This way if async processing happens,
+ // |callback| is notified appropriately.
+ ui::KeyEvent::KeyDispatcherApi(key_event).set_async_callback(
+ base::BindOnce(&OnKeyEventProcessed, std::move(callback)));
+ // Use a null callback as the async_callback previously set takes care of
+ // notifying |callback|.
+ delegate_->DispatchKeyEventPostIME(event->AsKeyEvent(), base::NullCallback());
+
+ if (!key_event->HasAsyncCallback())
+ return; // Event is being processed async.
+
+ // The delegate finished processing the event. Run the ack now.
+ const bool handled = key_event->handled();
+ key_event->WillHandleAsync().Run(handled);
}
} // namespace aura
diff --git a/chromium/ui/aura/mus/window_mus.h b/chromium/ui/aura/mus/window_mus.h
index 3ee4b65d25a..11ca0ae9419 100644
--- a/chromium/ui/aura/mus/window_mus.h
+++ b/chromium/ui/aura/mus/window_mus.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "services/ws/public/mojom/cursor/cursor.mojom.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/mus/mus_types.h"
@@ -103,10 +104,11 @@ class AURA_EXPORT WindowMus {
virtual ChangeSource OnTransientChildAdded(WindowMus* child) = 0;
virtual ChangeSource OnTransientChildRemoved(WindowMus* child) = 0;
- // Returns the currently used viz::LocalSurfaceId to embed this Window. Local
- // windows or windows that have not been embedded yet will have an invalid
- // viz::LocalSurfaceId.
- virtual const viz::LocalSurfaceId& GetLocalSurfaceId() = 0;
+ // Returns the currently used viz::LocalSurfaceIdAllocation to embed this
+ // Window. Local windows or windows that have not been embedded yet will have
+ // an invalid viz::LocalSurfaceIdAllocaton.
+ virtual const viz::LocalSurfaceIdAllocation&
+ GetLocalSurfaceIdAllocation() = 0;
// Called in the rare case when WindowTreeClient needs to change state and
// can't go through one of the SetFooFromServer() functions above. Generally
diff --git a/chromium/ui/aura/mus/window_port_mus.cc b/chromium/ui/aura/mus/window_port_mus.cc
index 2eb6ad5647c..e970a5d30dc 100644
--- a/chromium/ui/aura/mus/window_port_mus.cc
+++ b/chromium/ui/aura/mus/window_port_mus.cc
@@ -4,10 +4,16 @@
#include "ui/aura/mus/window_port_mus.h"
+#include <utility>
+
#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/callback.h"
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "components/viz/client/hit_test_data_provider_draw_quad.h"
#include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/features.h"
+#include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
@@ -15,9 +21,9 @@
#include "ui/aura/env.h"
#include "ui/aura/mus/client_surface_embedder.h"
#include "ui/aura/mus/property_converter.h"
+#include "ui/aura/mus/property_utils.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_client_delegate.h"
-#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/aura/window_observer.h"
#include "ui/base/class_property.h"
@@ -37,6 +43,46 @@ WindowPortMus::WindowMusChangeDataImpl::WindowMusChangeDataImpl() = default;
WindowPortMus::WindowMusChangeDataImpl::~WindowMusChangeDataImpl() = default;
+class WindowPortMus::VisibilityTracker : public WindowObserver {
+ public:
+ using Callback = base::RepeatingCallback<void(bool visible)>;
+ VisibilityTracker(Window* target, Callback callback)
+ : target_(target),
+ callback_(std::move(callback)),
+ last_visible_(target->IsVisible()) {
+ target_->AddObserver(this);
+ }
+
+ ~VisibilityTracker() override {
+ if (target_)
+ target_->RemoveObserver(this);
+ }
+
+ private:
+ // WindowObserver:
+ void OnWindowVisibilityChanged(Window* window, bool visible) override {
+ // Checking visibility change here instead of in OnVisibilityChanged to
+ // capture the change from window ancestors in addition to the window
+ // itself.
+ bool new_visible = target_->IsVisible();
+ if (new_visible == last_visible_)
+ return;
+
+ last_visible_ = new_visible;
+ callback_.Run(new_visible);
+ }
+ void OnWindowDestroyed(Window* window) override {
+ DCHECK_EQ(target_, window);
+ target_ = nullptr;
+ }
+
+ Window* target_;
+ Callback callback_;
+ bool last_visible_;
+
+ DISALLOW_COPY_AND_ASSIGN(VisibilityTracker);
+};
+
// static
WindowMus* WindowMus::Get(Window* window) {
return WindowPortMus::Get(window);
@@ -130,6 +176,7 @@ void WindowPortMus::EmbedUsingToken(
std::unique_ptr<cc::mojo_embedder::AsyncLayerTreeFrameSink>
WindowPortMus::RequestLayerTreeFrameSink(
scoped_refptr<viz::ContextProvider> context_provider,
+ scoped_refptr<viz::RasterContextProvider> raster_context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
viz::mojom::CompositorFrameSinkPtrInfo sink_info;
viz::mojom::CompositorFrameSinkRequest sink_request =
@@ -139,6 +186,9 @@ WindowPortMus::RequestLayerTreeFrameSink(
mojo::MakeRequest(&client);
cc::mojo_embedder::AsyncLayerTreeFrameSink::InitParams params;
+ ui::Compositor* compositor = window_->layer()->GetCompositor();
+ DCHECK(compositor);
+ params.compositor_task_runner = compositor->task_runner();
params.gpu_memory_buffer_manager = gpu_memory_buffer_manager;
params.pipes.compositor_frame_sink_info = std::move(sink_info);
params.pipes.client_request = std::move(client_request);
@@ -147,9 +197,11 @@ WindowPortMus::RequestLayerTreeFrameSink(
ws::mojom::EventTargetingPolicy::TARGET_ONLY) ||
(window_->event_targeting_policy() ==
ws::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
- params.hit_test_data_provider =
- std::make_unique<viz::HitTestDataProviderDrawQuad>(
- true /* should_ask_for_child_region */, root_accepts_events);
+ if (features::IsVizHitTestingDrawQuadEnabled()) {
+ params.hit_test_data_provider =
+ std::make_unique<viz::HitTestDataProviderDrawQuad>(
+ /* should_ask_for_child_regions */ false, root_accepts_events);
+ }
params.local_surface_id_provider =
std::make_unique<viz::DefaultLocalSurfaceIdProvider>();
params.enable_surface_synchronization = true;
@@ -157,7 +209,7 @@ WindowPortMus::RequestLayerTreeFrameSink(
auto layer_tree_frame_sink =
std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>(
- std::move(context_provider), nullptr /* worker_context_provider */,
+ std::move(context_provider), std::move(raster_context_provider),
&params);
window_tree_client_->AttachCompositorFrameSink(
server_id(), std::move(sink_request), std::move(client));
@@ -327,9 +379,9 @@ void WindowPortMus::SetBoundsFromServer(
last_surface_size_in_pixels_ =
gfx::ConvertSizeToPixel(GetDeviceScaleFactor(), bounds.size());
if (local_surface_id)
- local_surface_id_ = *local_surface_id;
+ parent_local_surface_id_allocator_.Reset(*local_surface_id);
else
- local_surface_id_ = viz::LocalSurfaceId();
+ parent_local_surface_id_allocator_.Invalidate();
window_->SetBounds(bounds);
}
@@ -383,11 +435,15 @@ void WindowPortMus::SetFrameSinkIdFromServer(
const viz::LocalSurfaceId& WindowPortMus::GetOrAllocateLocalSurfaceId(
const gfx::Size& surface_size_in_pixels) {
if (last_surface_size_in_pixels_ != surface_size_in_pixels ||
- !local_surface_id_.is_valid()) {
- local_surface_id_ = parent_local_surface_id_allocator_.GenerateId();
+ !GetLocalSurfaceIdAllocation().IsValid()) {
+ parent_local_surface_id_allocator_.GenerateId();
last_surface_size_in_pixels_ = surface_size_in_pixels;
}
+ const viz::LocalSurfaceId& current_local_surface_id =
+ parent_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id();
+
// If the FrameSinkId is available, then immediately embed the SurfaceId.
// The newly generated frame by the embedder will block in the display
// compositor until the child submits a corresponding CompositorFrame or a
@@ -396,9 +452,9 @@ const viz::LocalSurfaceId& WindowPortMus::GetOrAllocateLocalSurfaceId(
UpdatePrimarySurfaceId();
if (local_layer_tree_frame_sink_)
- local_layer_tree_frame_sink_->SetLocalSurfaceId(local_surface_id_);
+ local_layer_tree_frame_sink_->SetLocalSurfaceId(current_local_surface_id);
- return local_surface_id_;
+ return current_local_surface_id;
}
void WindowPortMus::DestroyFromServer() {
@@ -457,14 +513,12 @@ WindowPortMus::ChangeSource WindowPortMus::OnTransientChildRemoved(
}
void WindowPortMus::AllocateLocalSurfaceId() {
- local_surface_id_ = parent_local_surface_id_allocator_.GenerateId();
+ parent_local_surface_id_allocator_.GenerateId();
UpdatePrimarySurfaceId();
- if (local_layer_tree_frame_sink_)
- local_layer_tree_frame_sink_->SetLocalSurfaceId(local_surface_id_);
-}
-
-bool WindowPortMus::IsLocalSurfaceIdAllocationSuppressed() const {
- return parent_local_surface_id_allocator_.is_allocation_suppressed();
+ if (local_layer_tree_frame_sink_) {
+ local_layer_tree_frame_sink_->SetLocalSurfaceId(
+ GetLocalSurfaceIdAllocation().local_surface_id());
+ }
}
viz::ScopedSurfaceIdAllocator WindowPortMus::GetSurfaceIdAllocator(
@@ -473,12 +527,15 @@ viz::ScopedSurfaceIdAllocator WindowPortMus::GetSurfaceIdAllocator(
std::move(allocation_task));
}
+void WindowPortMus::InvalidateLocalSurfaceId() {
+ parent_local_surface_id_allocator_.Invalidate();
+}
+
void WindowPortMus::UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) {
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) {
parent_local_surface_id_allocator_.UpdateFromChild(
- embedded_client_local_surface_id);
- local_surface_id_ =
- parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
+ embedded_client_local_surface_id_allocation);
UpdatePrimarySurfaceId();
// OnWindowMusBoundsChanged() triggers notifying the server of the new
@@ -487,8 +544,10 @@ void WindowPortMus::UpdateLocalSurfaceIdFromEmbeddedClient(
window_->bounds());
}
-const viz::LocalSurfaceId& WindowPortMus::GetLocalSurfaceId() {
- return local_surface_id_;
+const viz::LocalSurfaceIdAllocation&
+WindowPortMus::GetLocalSurfaceIdAllocation() {
+ return parent_local_surface_id_allocator_
+ .GetCurrentLocalSurfaceIdAllocation();
}
std::unique_ptr<WindowMusChangeData>
@@ -538,10 +597,12 @@ void WindowPortMus::OnPreInit(Window* window) {
void WindowPortMus::OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) {
- if (!window_->IsRootWindow() && local_surface_id_.is_valid() &&
+ if (!window_->IsRootWindow() && GetLocalSurfaceIdAllocation().IsValid() &&
local_layer_tree_frame_sink_) {
- local_surface_id_ = parent_local_surface_id_allocator_.GenerateId();
- local_layer_tree_frame_sink_->SetLocalSurfaceId(local_surface_id_);
+ parent_local_surface_id_allocator_.GenerateId();
+ local_layer_tree_frame_sink_->SetLocalSurfaceId(
+ parent_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id());
}
if (window_->delegate()) {
@@ -635,8 +696,10 @@ WindowPortMus::CreateLayerTreeFrameSink() {
DCHECK_EQ(window_mus_type(), WindowMusType::LOCAL);
DCHECK(!local_layer_tree_frame_sink_);
+ // TODO(sky): this needs to supply a RasterContextProvider.
auto client_layer_tree_frame_sink = RequestLayerTreeFrameSink(
- nullptr, window_->env()->context_factory()->GetGpuMemoryBufferManager());
+ nullptr, nullptr,
+ window_->env()->context_factory()->GetGpuMemoryBufferManager());
local_layer_tree_frame_sink_ = client_layer_tree_frame_sink->GetWeakPtr();
embed_frame_sink_id_ = GenerateFrameSinkIdFromServerId();
window_->SetEmbedFrameSinkId(embed_frame_sink_id_);
@@ -672,23 +735,94 @@ void WindowPortMus::UnregisterFrameSinkId(
window_tree_client_->UnregisterFrameSinkId(this);
}
+void WindowPortMus::TrackOcclusionState() {
+ // base::Unretained because |this| owns |visibility_tracker_|.
+ visibility_tracker_ = std::make_unique<VisibilityTracker>(
+ window_, base::BindRepeating(
+ &WindowPortMus::UpdateOcclusionStateAfterVisiblityChange,
+ base::Unretained(this)));
+ window_tree_client_->TrackOcclusionState(this);
+}
+
void WindowPortMus::UpdatePrimarySurfaceId() {
if (window_mus_type() != WindowMusType::LOCAL)
return;
- if (!window_->IsEmbeddingClient() || !local_surface_id_.is_valid())
+ if (!window_->IsEmbeddingClient() || !GetLocalSurfaceIdAllocation().IsValid())
return;
primary_surface_id_ =
- viz::SurfaceId(window_->GetFrameSinkId(), local_surface_id_);
+ viz::SurfaceId(window_->GetFrameSinkId(),
+ GetLocalSurfaceIdAllocation().local_surface_id());
if (!client_surface_embedder_) {
client_surface_embedder_ = std::make_unique<ClientSurfaceEmbedder>(
window_, /* inject_gutter */ false, gfx::Insets());
}
- client_surface_embedder_->SetPrimarySurfaceId(primary_surface_id_);
+ client_surface_embedder_->SetSurfaceId(primary_surface_id_);
client_surface_embedder_->UpdateSizeAndGutters();
}
+void WindowPortMus::SetOcclusionStateFromServer(
+ ws::mojom::OcclusionState occlusion_state) {
+ const Window::OcclusionState new_state =
+ WindowOcclusionStateFromMojom(occlusion_state);
+ const Window::OcclusionState old_state = window_->occlusion_state();
+
+ if (old_state == new_state)
+ return;
+
+ // Filter HIDDEN/VISIBLE state that does not match window target visibility.
+ // This happens when the client makes visibility changes without waiting for
+ // server's occlusion state update. The stale occlusion state is still
+ // received and should be dropped to avoid unnecessary state change.
+ // e.g.
+ // CLIENT: Hide()
+ // CLIENT: Show()
+ // SERVER: Receives Hide() and sends back HIDDEN
+ // SERVER: Receives Show() and sends back VISIBLE
+ // CLIENT: Receives HIDDEN and drops it because local state is visible.
+ // CLIENT: Receives VISIBLE and accepts it.
+ const bool visible = window_->IsVisible();
+ if ((visible && new_state == Window::OcclusionState::HIDDEN) ||
+ (!visible && new_state == Window::OcclusionState::VISIBLE)) {
+ return;
+ }
+
+ UpdateOcclusionState(new_state);
+}
+
+void WindowPortMus::UpdateOcclusionState(Window::OcclusionState new_state) {
+ const Window::OcclusionState old_state = window_->occlusion_state();
+
+ if (new_state == Window::OcclusionState::HIDDEN &&
+ old_state != Window::OcclusionState::UNKNOWN) {
+ occlusion_state_before_hidden_ = old_state;
+ } else {
+ occlusion_state_before_hidden_.reset();
+ }
+
+ // TODO: Support occlusion region tracking. See crbug.com/900568.
+ window_->SetOcclusionInfo(new_state, SkRegion());
+}
+
+void WindowPortMus::UpdateOcclusionStateAfterVisiblityChange(bool visible) {
+ DCHECK_EQ(visible, window_->IsVisible());
+
+ // No occlusion state update if |window_| is not added a root window.
+ if (!window_->GetRootWindow())
+ return;
+
+ if (!visible) {
+ // Set HIDDEN early when |window_| becomes hidden.
+ UpdateOcclusionState(Window::OcclusionState::HIDDEN);
+ } else {
+ // Restore to before-hidden state or VISIBLE when |window_| becomes visible.
+ UpdateOcclusionState(occlusion_state_before_hidden_
+ ? occlusion_state_before_hidden_.value()
+ : Window::OcclusionState::VISIBLE);
+ }
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/window_port_mus.h b/chromium/ui/aura/mus/window_port_mus.h
index 428b05a2732..14f60e525f5 100644
--- a/chromium/ui/aura/mus/window_port_mus.h
+++ b/chromium/ui/aura/mus/window_port_mus.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
+#include "base/time/time.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "services/ws/public/mojom/cursor/cursor.mojom.h"
@@ -22,6 +23,7 @@
#include "ui/aura/aura_export.h"
#include "ui/aura/mus/mus_types.h"
#include "ui/aura/mus/window_mus.h"
+#include "ui/aura/window.h"
#include "ui/aura/window_port.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/platform_window/mojo/text_input_state.mojom.h"
@@ -38,15 +40,15 @@ class GpuMemoryBufferManager;
namespace viz {
class ContextProvider;
+class RasterContextProvider;
}
namespace aura {
class ClientSurfaceEmbedder;
class PropertyConverter;
-class Window;
class WindowTreeClient;
-class WindowTreeClientPrivate;
+class WindowTreeClientTestApi;
class WindowTreeHostMus;
// WindowPortMus is a WindowPort that forwards calls to WindowTreeClient
@@ -100,6 +102,7 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
std::unique_ptr<cc::mojo_embedder::AsyncLayerTreeFrameSink>
RequestLayerTreeFrameSink(
scoped_refptr<viz::ContextProvider> context_provider,
+ scoped_refptr<viz::RasterContextProvider> raster_context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
viz::FrameSinkId GenerateFrameSinkIdFromServerId() const;
@@ -107,7 +110,7 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
private:
friend class WindowPortMusTestHelper;
friend class WindowTreeClient;
- friend class WindowTreeClientPrivate;
+ friend class WindowTreeClientTestApi;
friend class WindowTreeHostMus;
friend class HitTestDataProviderAuraTest;
@@ -204,6 +207,11 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
std::unique_ptr<ScopedServerChange> change;
};
+ // Derived from WindowObserver to update local occlusion state. Not using
+ // OnVisibilityChanged because occlusion state is based on Window::IsVisible
+ // and needs to consider ancestors' visibility as well.
+ class VisibilityTracker;
+
// Creates and adds a ServerChange to |server_changes_|. Returns the id
// assigned to the ServerChange.
ServerChangeIdType ScheduleChange(const ServerChangeType type,
@@ -253,7 +261,8 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
const viz::LocalSurfaceId& GetOrAllocateLocalSurfaceId(
const gfx::Size& surface_size_in_pixels) override;
void UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) override;
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) override;
void DestroyFromServer() override;
void AddTransientChildFromServer(WindowMus* child) override;
void RemoveTransientChildFromServer(WindowMus* child) override;
@@ -287,17 +296,29 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
std::unique_ptr<ui::PropertyData> data) override;
std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override;
void AllocateLocalSurfaceId() override;
- bool IsLocalSurfaceIdAllocationSuppressed() const override;
viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) override;
- const viz::LocalSurfaceId& GetLocalSurfaceId() override;
+ const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() override;
+ void InvalidateLocalSurfaceId() override;
void OnEventTargetingPolicyChanged() override;
bool ShouldRestackTransientChildren() override;
void RegisterFrameSinkId(const viz::FrameSinkId& frame_sink_id) override;
void UnregisterFrameSinkId(const viz::FrameSinkId& frame_sink_id) override;
+ void TrackOcclusionState() override;
void UpdatePrimarySurfaceId();
+ // Called by WindowTreeClient to update window occlusion state.
+ void SetOcclusionStateFromServer(ws::mojom::OcclusionState occlusion_state);
+
+ // Updates |window_| occlusion state to |new_state|.
+ void UpdateOcclusionState(Window::OcclusionState new_state);
+
+ // Update the local occlusion state after visibility of |window_| is changed.
+ // This is called from VisibilityTracker when window_->IsVisible changes to
+ // capture the visibility change from |window_| and its ancestors.
+ void UpdateOcclusionStateAfterVisiblityChange(bool visible);
+
WindowTreeClient* window_tree_client_;
Window* window_ = nullptr;
@@ -310,7 +331,6 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
viz::SurfaceId primary_surface_id_;
- viz::LocalSurfaceId local_surface_id_;
// TODO(sad, fsamuel): For 'mash' mode, where the embedder is responsible for
// allocating the LocalSurfaceIds, this should use a
// ChildLocalSurfaceIdAllocator instead.
@@ -333,6 +353,15 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
// the local surface id when necessary.
base::WeakPtr<cc::LayerTreeFrameSink> local_layer_tree_frame_sink_;
+ // Tracks |window_->IsVisible()| change and update local occlusion state.
+ std::unique_ptr<VisibilityTracker> visibility_tracker_;
+
+ // The occlusion state that is not UNKNOWN before changing to HIDDEN. If the
+ // value is set, it will be used when |window_| becomes visible again. This
+ // allows synchronous occlusion state change when making |window_| visible.
+ // Window Service will send back the real occlusion state later.
+ base::Optional<Window::OcclusionState> occlusion_state_before_hidden_;
+
base::WeakPtrFactory<WindowPortMus> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WindowPortMus);
diff --git a/chromium/ui/aura/mus/window_port_mus_unittest.cc b/chromium/ui/aura/mus/window_port_mus_unittest.cc
index fe616b2dc28..161ec145b66 100644
--- a/chromium/ui/aura/mus/window_port_mus_unittest.cc
+++ b/chromium/ui/aura/mus/window_port_mus_unittest.cc
@@ -4,12 +4,15 @@
#include "ui/aura/mus/window_port_mus.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/mus/client_surface_embedder.h"
#include "ui/aura/test/aura_mus_test_base.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/aura/test/mus/test_window_tree_delegate.h"
#include "ui/aura/test/mus/window_port_mus_test_helper.h"
#include "ui/aura/window.h"
#include "ui/base/ui_base_features.h"
@@ -18,6 +21,43 @@ namespace aura {
using WindowPortMusTest = test::AuraMusClientTestBase;
+namespace {
+
+class TrackOcclusionStateCallWaiter : public TestWindowTreeDelegate {
+ public:
+ explicit TrackOcclusionStateCallWaiter(TestWindowTree* test_window_tree)
+ : test_window_tree_(test_window_tree) {
+ test_window_tree_->set_delegate(this);
+ }
+
+ ~TrackOcclusionStateCallWaiter() override {
+ test_window_tree_->set_delegate(nullptr);
+ }
+
+ // Don't wait twice since the Runloop can only be used once.
+ void Wait() { run_loop_.Run(); }
+
+ // TestWindowTreeDelegate:
+ void TrackOcclusionState(ws::Id window_id) override {
+ track_occlusion_state_received_ = true;
+ run_loop_.Quit();
+ }
+
+ const base::Optional<bool>& track_occlusion_state_call_received() const {
+ return track_occlusion_state_received_;
+ }
+
+ private:
+ base::RunLoop run_loop_;
+ TestWindowTree* const test_window_tree_;
+
+ base::Optional<bool> track_occlusion_state_received_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackOcclusionStateCallWaiter);
+};
+
+} // namespace
+
// TODO(sadrul): https://crbug.com/842361.
TEST_F(WindowPortMusTest,
DISABLED_LayerTreeFrameSinkGetsCorrectLocalSurfaceId) {
@@ -28,7 +68,8 @@ TEST_F(WindowPortMusTest,
// correctly generates LocalSurfaceId.
window.SetEmbedFrameSinkId(viz::FrameSinkId(0, 1));
- viz::LocalSurfaceId local_surface_id = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
ASSERT_TRUE(local_surface_id.is_valid());
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink(
@@ -55,9 +96,10 @@ TEST_F(WindowPortMusTest, ClientSurfaceEmbedderUpdatesLayer) {
window.AllocateLocalSurfaceId();
auto* window_mus = WindowPortMus::Get(&window);
- viz::LocalSurfaceId local_surface_id = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
viz::SurfaceId primary_surface_id =
- window_mus->client_surface_embedder()->GetPrimarySurfaceIdForTesting();
+ window_mus->client_surface_embedder()->GetSurfaceIdForTesting();
EXPECT_EQ(local_surface_id, primary_surface_id.local_surface_id());
}
@@ -81,17 +123,20 @@ TEST_F(WindowPortMusTest,
viz::ParentLocalSurfaceIdAllocator* parent_allocator =
WindowPortMusTestHelper(&window).GetParentLocalSurfaceIdAllocator();
parent_allocator->Reset(current_id);
- viz::LocalSurfaceId updated_id = parent_allocator->GenerateId();
+ parent_allocator->GenerateId();
+ const viz::LocalSurfaceId& updated_id =
+ parent_allocator->GetCurrentLocalSurfaceIdAllocation().local_surface_id();
ASSERT_TRUE(updated_id.is_valid());
EXPECT_NE(updated_id, current_id);
- window.UpdateLocalSurfaceIdFromEmbeddedClient(updated_id);
+ window.UpdateLocalSurfaceIdFromEmbeddedClient(
+ parent_allocator->GetCurrentLocalSurfaceIdAllocation());
// Updating the LocalSurfaceId should propagate to the ClientSurfaceEmbedder.
auto* window_mus = WindowPortMus::Get(&window);
ASSERT_TRUE(window_mus);
ASSERT_TRUE(window_mus->client_surface_embedder());
EXPECT_EQ(updated_id, window_mus->client_surface_embedder()
- ->GetPrimarySurfaceIdForTesting()
+ ->GetSurfaceIdForTesting()
.local_surface_id());
// The server is notified of a bounds change, so that it sees the new
@@ -103,4 +148,57 @@ TEST_F(WindowPortMusTest,
EXPECT_EQ(updated_id, *(window_tree()->last_local_surface_id()));
}
+// Tests that Window::TrackOcclusionState calls into WindowTree under mus.
+TEST_F(WindowPortMusTest, TrackOcclusionState) {
+ Window window(nullptr);
+ window.Init(ui::LAYER_NOT_DRAWN);
+ window.SetBounds(gfx::Rect(400, 300));
+
+ TrackOcclusionStateCallWaiter waiter(window_tree());
+ window.TrackOcclusionState();
+ waiter.Wait();
+ EXPECT_TRUE(waiter.track_occlusion_state_call_received() == true);
+}
+
+TEST_F(WindowPortMusTest, LocalOcclusionStateFromVisibility) {
+ Window window(nullptr);
+ window.Init(ui::LAYER_NOT_DRAWN);
+ window.set_owned_by_parent(false);
+ window.SetBounds(gfx::Rect(400, 300));
+
+ root_window()->AddChild(&window);
+ window.TrackOcclusionState();
+ ASSERT_EQ(Window::OcclusionState::HIDDEN, window.occlusion_state());
+
+ // Use a dummy waiter to disable simulated WindowOcclusionTracker behavior.
+ TrackOcclusionStateCallWaiter waiter(window_tree());
+
+ // Single window case.
+ window.Show();
+ EXPECT_EQ(Window::OcclusionState::VISIBLE, window.occlusion_state());
+
+ window.Hide();
+ EXPECT_EQ(Window::OcclusionState::HIDDEN, window.occlusion_state());
+
+ // Window has a parent.
+ Window parent(nullptr);
+ parent.Init(ui::LAYER_NOT_DRAWN);
+ parent.set_owned_by_parent(false);
+ parent.SetBounds(gfx::Rect(400, 300));
+ root_window()->AddChild(&parent);
+ parent.AddChild(&window);
+
+ // Stays HIDDEN because parent is not shown.
+ window.Show();
+ EXPECT_EQ(Window::OcclusionState::HIDDEN, window.occlusion_state());
+
+ // Changes to VISIBLE when window.IsVisible() is true.
+ parent.Show();
+ EXPECT_EQ(Window::OcclusionState::VISIBLE, window.occlusion_state());
+
+ // Changes to HIDDEN when parent hides.
+ parent.Hide();
+ EXPECT_EQ(Window::OcclusionState::HIDDEN, window.occlusion_state());
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/window_tree_client.cc b/chromium/ui/aura/mus/window_tree_client.cc
index f28829be913..a0dbdb0bb41 100644
--- a/chromium/ui/aura/mus/window_tree_client.cc
+++ b/chromium/ui/aura/mus/window_tree_client.cc
@@ -38,6 +38,7 @@
#include "ui/aura/mus/embed_root.h"
#include "ui/aura/mus/embed_root_delegate.h"
#include "ui/aura/mus/focus_synchronizer.h"
+#include "ui/aura/mus/gesture_recognizer_impl_mus.h"
#include "ui/aura/mus/gesture_synchronizer.h"
#include "ui/aura/mus/in_flight_change.h"
#include "ui/aura/mus/input_method_mus.h"
@@ -65,6 +66,8 @@
#include "ui/display/screen.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/event.h"
+#include "ui/events/event_observer.h"
+#include "ui/events/mojo/event_struct_traits.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
@@ -219,6 +222,11 @@ bool WindowTreeClient::WaitForDisplays() {
return valid_wait;
}
+WindowMus* WindowTreeClient::GetWindowByServerId(ws::Id id) {
+ IdToWindowMap::const_iterator it = windows_.find(id);
+ return it != windows_.end() ? it->second : nullptr;
+}
+
void WindowTreeClient::SetCanFocus(Window* window, bool can_focus) {
DCHECK(tree_);
DCHECK(window);
@@ -256,6 +264,21 @@ void WindowTreeClient::SetHitTestInsets(WindowMus* window,
tree_->SetHitTestInsets(window->server_id(), mouse, touch);
}
+void WindowTreeClient::TrackOcclusionState(WindowMus* window) {
+ DCHECK(tree_);
+ tree_->TrackOcclusionState(window->server_id());
+}
+
+void WindowTreeClient::PauseWindowOcclusionTracking() {
+ DCHECK(tree_);
+ tree_->PauseWindowOcclusionTracking();
+}
+
+void WindowTreeClient::UnpauseWindowOcclusionTracking() {
+ DCHECK(tree_);
+ tree_->UnpauseWindowOcclusionTracking();
+}
+
void WindowTreeClient::RegisterFrameSinkId(
WindowMus* window,
const viz::FrameSinkId& frame_sink_id) {
@@ -356,11 +379,6 @@ void WindowTreeClient::RegisterWindowMus(WindowMus* window) {
}
}
-WindowMus* WindowTreeClient::GetWindowByServerId(ws::Id id) {
- IdToWindowMap::const_iterator it = windows_.find(id);
- return it != windows_.end() ? it->second : nullptr;
-}
-
bool WindowTreeClient::IsWindowKnown(aura::Window* window) {
WindowMus* window_mus = WindowMus::Get(window);
// NOTE: this function explicitly checks for a null WindowMus as it may be
@@ -536,6 +554,8 @@ void WindowTreeClient::WindowTreeConnectionEstablished(
drag_drop_controller_ = std::make_unique<DragDropControllerMus>(this, tree_);
capture_synchronizer_ = std::make_unique<CaptureSynchronizer>(this, tree_);
focus_synchronizer_ = std::make_unique<FocusSynchronizer>(this, tree_);
+ Env::GetInstance()->SetGestureRecognizer(
+ std::make_unique<GestureRecognizerImplMus>(this));
gesture_synchronizer_ = std::make_unique<GestureSynchronizer>(tree_);
}
@@ -645,28 +665,11 @@ void WindowTreeClient::SetWindowVisibleFromServer(WindowMus* window,
window_tree_host->Hide();
}
-void WindowTreeClient::NotifyPointerEventObserved(ui::PointerEvent* event,
- uint64_t display_id,
- WindowMus* window_mus) {
- aura::Window* window = window_mus ? window_mus->GetWindow() : nullptr;
- gfx::Point location_in_screen;
- if (window) {
- location_in_screen = event->location();
- client::GetScreenPositionClient(window->GetRootWindow())
- ->ConvertPointToScreen(window, &location_in_screen);
- } else {
- // When there is no window force the root and location to be the same.
- // They may differ if |window| was valid at the time of the event, but
- // was since deleted.
- event->set_location_f(event->root_location_f());
- location_in_screen = event->root_location();
- display::Display display;
- if (display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id,
- &display)) {
- location_in_screen += display.bounds().OffsetFromOrigin();
- }
- }
- delegate_->OnPointerEventObserved(*event, location_in_screen, window);
+void WindowTreeClient::UpdateObservedEventTypes() {
+ std::vector<ui::mojom::EventType> types;
+ for (auto type : event_type_to_observer_count_)
+ types.push_back(mojo::ConvertTo<ui::mojom::EventType>(type.first));
+ tree_->ObserveEventTypes(types);
}
void WindowTreeClient::ScheduleInFlightBoundsChange(
@@ -675,7 +678,8 @@ void WindowTreeClient::ScheduleInFlightBoundsChange(
const gfx::Rect& new_bounds) {
const uint32_t change_id =
ScheduleInFlightChange(std::make_unique<InFlightBoundsChange>(
- this, window, old_bounds, window->GetLocalSurfaceId()));
+ this, window, old_bounds,
+ window->GetLocalSurfaceIdAllocation().local_surface_id()));
base::Optional<viz::LocalSurfaceId> local_surface_id;
if (window->GetWindow()->IsEmbeddingClient() ||
window->HasLocalLayerTreeFrameSink()) {
@@ -726,21 +730,23 @@ void WindowTreeClient::OnWindowMusDestroyed(WindowMus* window, Origin origin) {
// deletion. The connection to the server is about to be dropped and the
// server will take appropriate action.
// TODO: decide how to deal with windows not owned by this client.
+ base::Optional<uint32_t> delete_change_id;
if (!in_shutdown_ && origin == Origin::CLIENT &&
(WasCreatedByThisClient(window) || IsRoot(window))) {
- const uint32_t change_id =
+ delete_change_id =
ScheduleInFlightChange(std::make_unique<CrashInFlightChange>(
window, ChangeType::DELETE_WINDOW));
- tree_->DeleteWindow(change_id, window->server_id());
+ tree_->DeleteWindow(delete_change_id.value(), window->server_id());
}
windows_.erase(window->server_id());
- // Remove any InFlightChanges associated with the window.
+ // Remove any InFlightChanges associated with the window, except the delete.
std::set<uint32_t> in_flight_change_ids_to_remove;
for (const auto& pair : in_flight_map_) {
- if (pair.second->window() == window)
- in_flight_change_ids_to_remove.insert(pair.first);
+ const uint32_t change_id = pair.first;
+ if (pair.second->window() == window && change_id != delete_change_id)
+ in_flight_change_ids_to_remove.insert(change_id);
}
for (auto change_id : in_flight_change_ids_to_remove)
in_flight_map_.erase(change_id);
@@ -900,17 +906,36 @@ gfx::Point WindowTreeClient::GetCursorScreenPoint() {
static_cast<int16_t>(location & 0xFFFF));
}
-void WindowTreeClient::StartPointerWatcher(bool want_moves) {
- if (has_pointer_watcher_)
- StopPointerWatcher();
- has_pointer_watcher_ = true;
- tree_->StartPointerWatcher(want_moves);
+void WindowTreeClient::OnEarlyShutdown() {
+ if (compositor_context_factory_)
+ compositor_context_factory_->ResetSharedWorkerContextProvider();
}
-void WindowTreeClient::StopPointerWatcher() {
- DCHECK(has_pointer_watcher_);
- tree_->StopPointerWatcher();
- has_pointer_watcher_ = false;
+void WindowTreeClient::OnEventObserverAdded(
+ ui::EventObserver* observer,
+ const std::set<ui::EventType>& types) {
+ bool requires_update = false;
+ for (auto type : types) {
+ requires_update |= (event_type_to_observer_count_[type] == 0);
+ ++event_type_to_observer_count_[type];
+ }
+ if (requires_update)
+ UpdateObservedEventTypes();
+}
+
+void WindowTreeClient::OnEventObserverRemoved(
+ ui::EventObserver* observer,
+ const std::set<ui::EventType>& types) {
+ bool requires_update = false;
+ for (auto type : types) {
+ --event_type_to_observer_count_[type];
+ requires_update |= (event_type_to_observer_count_[type] == 0);
+ DCHECK_GE(event_type_to_observer_count_[type], 0);
+ if (event_type_to_observer_count_[type] <= 0)
+ event_type_to_observer_count_.erase(type);
+ }
+ if (requires_update)
+ UpdateObservedEventTypes();
}
void WindowTreeClient::AddObserver(WindowTreeClientObserver* observer) {
@@ -943,6 +968,10 @@ void WindowTreeClient::SetEventTargetingPolicy(
tree_->SetEventTargetingPolicy(window->server_id(), policy);
}
+void WindowTreeClient::OnClientId(uint32_t client_id) {
+ id_ = client_id;
+}
+
void WindowTreeClient::OnEmbed(
ws::mojom::WindowDataPtr root_data,
ws::mojom::WindowTreePtr tree,
@@ -1268,29 +1297,10 @@ void WindowTreeClient::OnWindowInputEvent(uint32_t event_id,
ws::Id window_id,
int64_t display_id,
std::unique_ptr<ui::Event> event,
- bool matches_pointer_watcher) {
+ bool matches_event_observer) {
DCHECK(event);
WindowMus* window = GetWindowByServerId(window_id); // May be null.
- DCHECK(!event->IsPointerEvent());
-
- if (matches_pointer_watcher && has_pointer_watcher_) {
- // TODO(sky): remove this once PointerWatcher doesn't need PointerEvent.
- // https://crbug.com/865781
- std::unique_ptr<ui::Event> pointer_event;
- if (event->IsMouseEvent()) {
- pointer_event =
- std::make_unique<ui::PointerEvent>(*event->AsMouseEvent());
- } else if (event->IsTouchEvent()) {
- pointer_event =
- std::make_unique<ui::PointerEvent>(*event->AsTouchEvent());
- } else {
- NOTREACHED();
- }
- NotifyPointerEventObserved(pointer_event->AsPointerEvent(), display_id,
- window);
- }
-
// If the window has already been deleted, use |event| to update event states
// kept in aura::Env.
if (!window || !window->GetWindow()->GetHost()) {
@@ -1304,6 +1314,20 @@ void WindowTreeClient::OnWindowInputEvent(uint32_t event_id,
return;
}
+ if (matches_event_observer) {
+ std::unique_ptr<ui::Event> cloned_event(ui::Event::Clone(*event));
+ // Set the window as the event target, so event locations will be useful.
+ aura::Window* aura_window = window ? window->GetWindow() : nullptr;
+ ui::Event::DispatcherApi(cloned_event.get()).set_target(aura_window);
+ // The root location of located events should be in screen coordinates.
+ if (cloned_event->IsLocatedEvent() && cloned_event->target()) {
+ ui::LocatedEvent* located_event = cloned_event->AsLocatedEvent();
+ auto root = located_event->target()->GetScreenLocationF(*located_event);
+ located_event->set_root_location_f(root);
+ }
+ Env::GetInstance()->NotifyEventObservers(*cloned_event);
+ }
+
if (event->IsKeyEvent()) {
InputMethodMus* input_method = GetWindowTreeHostMus(window)->input_method();
if (input_method) {
@@ -1328,16 +1352,9 @@ void WindowTreeClient::OnWindowInputEvent(uint32_t event_id,
ack_handler.set_handled(event->handled());
}
-void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event,
- ws::Id window_id,
- int64_t display_id) {
+void WindowTreeClient::OnObservedInputEvent(std::unique_ptr<ui::Event> event) {
DCHECK(event);
- DCHECK(event->IsPointerEvent());
- if (!has_pointer_watcher_)
- return;
-
- NotifyPointerEventObserved(event->AsPointerEvent(), display_id,
- GetWindowByServerId(window_id));
+ Env::GetInstance()->NotifyEventObservers(*event);
}
void WindowTreeClient::OnWindowFocused(ws::Id focused_window_id) {
@@ -1453,6 +1470,8 @@ void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
current_move_loop_change_ = 0;
on_current_move_finished_.Run(success);
on_current_move_finished_.Reset();
+ for (auto& observer : observers_)
+ observer.OnWindowMoveEnded(success);
}
if (!change)
@@ -1481,6 +1500,17 @@ void WindowTreeClient::GetScreenProviderObserver(
screen_provider_observer_binding_.Bind(std::move(observer));
}
+void WindowTreeClient::OnOcclusionStateChanged(
+ ws::Id window_id,
+ ws::mojom::OcclusionState occlusion_state) {
+ WindowMus* window = GetWindowByServerId(window_id);
+ if (!window)
+ return;
+
+ WindowPortMus::Get(window->GetWindow())
+ ->SetOcclusionStateFromServer(occlusion_state);
+}
+
void WindowTreeClient::OnDisplaysChanged(
std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
@@ -1570,6 +1600,10 @@ void WindowTreeClient::OnWindowTreeHostPerformWindowMove(
// Tell the window manager to take over moving us.
tree_->PerformWindowMove(current_move_loop_change_, window_mus->server_id(),
source, cursor_location);
+ for (auto& observer : observers_) {
+ observer.OnWindowMoveStarted(window_tree_host->window(), cursor_location,
+ source);
+ }
}
void WindowTreeClient::OnWindowTreeHostCancelWindowMove(
diff --git a/chromium/ui/aura/mus/window_tree_client.h b/chromium/ui/aura/mus/window_tree_client.h
index 9183c781309..186f8e5c173 100644
--- a/chromium/ui/aura/mus/window_tree_client.h
+++ b/chromium/ui/aura/mus/window_tree_client.h
@@ -48,6 +48,7 @@ class Connector;
namespace ui {
class ContextFactory;
+class EventObserver;
struct PropertyData;
}
@@ -72,8 +73,8 @@ class TopmostWindowTracker;
class WindowMus;
class WindowPortMus;
class WindowTreeClientDelegate;
-class WindowTreeClientPrivate;
class WindowTreeClientObserver;
+class WindowTreeClientTestApi;
class WindowTreeClientTestObserver;
class WindowTreeHostMus;
@@ -125,6 +126,10 @@ class AURA_EXPORT WindowTreeClient
// Blocks until the initial screen configuration is received.
bool WaitForDisplays();
+ const base::Optional<uint32_t>& id() const { return id_; }
+
+ WindowMus* GetWindowByServerId(ws::Id id);
+
void SetCanFocus(Window* window, bool can_focus);
void SetCanAcceptDrops(WindowMus* window, bool can_accept_drops);
void SetEventTargetingPolicy(WindowMus* window,
@@ -140,6 +145,9 @@ class AURA_EXPORT WindowTreeClient
void SetHitTestInsets(WindowMus* window,
const gfx::Insets& mouse,
const gfx::Insets& touch);
+ void TrackOcclusionState(WindowMus* window);
+ void PauseWindowOcclusionTracking();
+ void UnpauseWindowOcclusionTracking();
// See WindowPort for details on these.
void RegisterFrameSinkId(WindowMus* window,
@@ -190,11 +198,14 @@ class AURA_EXPORT WindowTreeClient
// race the asynchronous initialization; but in that case we return (0, 0).
gfx::Point GetCursorScreenPoint();
- // See description in window_tree.mojom. When an existing pointer watcher is
- // updated or cleared then any future events from the server for that watcher
- // will be ignored.
- void StartPointerWatcher(bool want_moves);
- void StopPointerWatcher();
+ // May be called to do early shutdown.
+ void OnEarlyShutdown();
+
+ // Called when the local aura::Env adds or removes EventObservers.
+ void OnEventObserverAdded(ui::EventObserver* observer,
+ const std::set<ui::EventType>& types);
+ void OnEventObserverRemoved(ui::EventObserver* observer,
+ const std::set<ui::EventType>& types);
void AddObserver(WindowTreeClientObserver* observer);
void RemoveObserver(WindowTreeClientObserver* observer);
@@ -211,7 +222,7 @@ class AURA_EXPORT WindowTreeClient
friend class InFlightVisibleChange;
friend class TopmostWindowTracker;
friend class WindowPortMus;
- friend class WindowTreeClientPrivate;
+ friend class WindowTreeClientTestApi;
enum class Origin {
CLIENT,
@@ -236,8 +247,6 @@ class AURA_EXPORT WindowTreeClient
void RegisterWindowMus(WindowMus* window);
- WindowMus* GetWindowByServerId(ws::Id id);
-
bool IsWindowKnown(aura::Window* window);
// Returns the oldest InFlightChange that matches |change|.
@@ -327,9 +336,8 @@ class AURA_EXPORT WindowTreeClient
// TopmostWindowTracker.
void StopObservingTopmostWindow();
- void NotifyPointerEventObserved(ui::PointerEvent* event,
- uint64_t display_id,
- WindowMus* window_mus);
+ // Updates the set of event types requested for observation.
+ void UpdateObservedEventTypes();
// Called from OnWindowMusBoundsChanged() and SetRootWindowBounds().
void ScheduleInFlightBoundsChange(WindowMus* window,
@@ -360,6 +368,7 @@ class AURA_EXPORT WindowTreeClient
std::unique_ptr<ui::PropertyData> data);
// Overridden from WindowTreeClient:
+ void OnClientId(uint32_t client_id) override;
void OnEmbed(
ws::mojom::WindowDataPtr root,
ws::mojom::WindowTreePtr tree,
@@ -419,10 +428,8 @@ class AURA_EXPORT WindowTreeClient
ws::Id window_id,
int64_t display_id,
std::unique_ptr<ui::Event> event,
- bool matches_pointer_watcher) override;
- void OnPointerEventObserved(std::unique_ptr<ui::Event> event,
- ws::Id window_id,
- int64_t display_id) override;
+ bool matches_event_observer) override;
+ void OnObservedInputEvent(std::unique_ptr<ui::Event> event) override;
void OnWindowFocused(ws::Id focused_window_id) override;
void OnWindowCursorChanged(ws::Id window_id, ui::CursorData cursor) override;
void OnDragDropStart(const base::flat_map<std::string, std::vector<uint8_t>>&
@@ -452,6 +459,9 @@ class AURA_EXPORT WindowTreeClient
void RequestClose(ws::Id window_id) override;
void GetScreenProviderObserver(
ws::mojom::ScreenProviderObserverAssociatedRequest observer) override;
+ void OnOcclusionStateChanged(
+ ws::Id window_id,
+ ws::mojom::OcclusionState occlusion_state) override;
// ws::mojom::ScreenProviderObserver:
void OnDisplaysChanged(std::vector<ws::mojom::WsDisplayPtr> ws_displays,
@@ -550,7 +560,8 @@ class AURA_EXPORT WindowTreeClient
base::ObserverList<WindowTreeClientObserver>::Unchecked observers_;
- bool has_pointer_watcher_ = false;
+ // Tracks the number of observers registered for each observed event type.
+ std::map<ui::EventType, int> event_type_to_observer_count_;
// The current change id for the client.
uint32_t current_move_loop_change_ = 0u;
@@ -584,6 +595,9 @@ class AURA_EXPORT WindowTreeClient
mojo::AssociatedBinding<ws::mojom::ScreenProviderObserver>
screen_provider_observer_binding_{this};
+ // Id for this connection. The server provides this value in OnClientId().
+ base::Optional<uint32_t> id_;
+
base::WeakPtrFactory<WindowTreeClient> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeClient);
diff --git a/chromium/ui/aura/mus/window_tree_client_delegate.h b/chromium/ui/aura/mus/window_tree_client_delegate.h
index 0ac318a0e2f..aa73c1b8087 100644
--- a/chromium/ui/aura/mus/window_tree_client_delegate.h
+++ b/chromium/ui/aura/mus/window_tree_client_delegate.h
@@ -56,13 +56,6 @@ class AURA_EXPORT WindowTreeClientDelegate {
// the corresponding WindowTreeClient.
virtual void OnLostConnection(WindowTreeClient* client) = 0;
- // Called when the WindowTreeClient receives an input event observed via
- // StartPointerWatcher(). |target| may be null for events that were sent to
- // windows owned by other processes.
- virtual void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- Window* target) = 0;
-
virtual PropertyConverter* GetPropertyConverter() = 0;
// See ws::mojom::ScreenProviderObserver for details on this.
diff --git a/chromium/ui/aura/mus/window_tree_client_observer.h b/chromium/ui/aura/mus/window_tree_client_observer.h
index 7410549a66f..30be54a4880 100644
--- a/chromium/ui/aura/mus/window_tree_client_observer.h
+++ b/chromium/ui/aura/mus/window_tree_client_observer.h
@@ -5,10 +5,12 @@
#ifndef UI_AURA_MUS_WINDOW_TREE_CLIENT_OBSERVER_H_
#define UI_AURA_MUS_WINDOW_TREE_CLIENT_OBSERVER_H_
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/aura_export.h"
namespace aura {
+class Window;
class WindowTreeClient;
class AURA_EXPORT WindowTreeClientObserver {
@@ -16,6 +18,14 @@ class AURA_EXPORT WindowTreeClientObserver {
// Called early on in the destructor of WindowTreeClient.
virtual void OnWillDestroyClient(WindowTreeClient* client) {}
+ // Called when a WindowMove started on |window| from |source| event.
+ virtual void OnWindowMoveStarted(Window* window,
+ const gfx::Point& cursor_location,
+ ws::mojom::MoveLoopSource source) {}
+
+ // Called when the WindowMove ended.
+ virtual void OnWindowMoveEnded(bool success) {}
+
protected:
virtual ~WindowTreeClientObserver() {}
};
diff --git a/chromium/ui/aura/mus/window_tree_client_unittest.cc b/chromium/ui/aura/mus/window_tree_client_unittest.cc
index 2ca4cce0c21..03c3b55880c 100644
--- a/chromium/ui/aura/mus/window_tree_client_unittest.cc
+++ b/chromium/ui/aura/mus/window_tree_client_unittest.cc
@@ -23,7 +23,6 @@
#include "ui/aura/client/capture_client_observer.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/focus_client.h"
-#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/mus/capture_synchronizer.h"
#include "ui/aura/mus/client_surface_embedder.h"
@@ -40,7 +39,7 @@
#include "ui/aura/test/aura_mus_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h"
#include "ui/aura/test/mus/window_port_mus_test_helper.h"
-#include "ui/aura/test/mus/window_tree_client_private.h"
+#include "ui/aura/test/mus/window_tree_client_test_api.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_window_targeter.h"
@@ -56,6 +55,7 @@
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
+#include "ui/events/event_observer.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/test_event_handler.h"
#include "ui/gfx/geometry/dip_util.h"
@@ -87,7 +87,7 @@ std::unique_ptr<Window> CreateWindowUsingId(
ws::mojom::WindowData window_data;
window_data.window_id = server_id;
WindowMus* window_mus =
- WindowTreeClientPrivate(window_tree_client)
+ WindowTreeClientTestApi(window_tree_client)
.NewWindowFromWindowData(WindowMus::Get(parent), window_data);
// WindowTreeClient implicitly creates the Window but doesn't own it.
// Pass ownership to the caller.
@@ -126,40 +126,30 @@ std::vector<uint8_t> ConvertToPropertyTransportValue(int64_t value) {
return mojo::ConvertTo<std::vector<uint8_t>>(value);
}
-class TestScreenPositionClient : public client::ScreenPositionClient {
+void OnWindowMoveDone(int* call_count, bool* last_result, bool result) {
+ (*call_count)++;
+ *last_result = result;
+}
+
+// A simple event observer that records the last observed event.
+class TestEventObserver : public ui::EventObserver {
public:
- TestScreenPositionClient() = default;
- ~TestScreenPositionClient() override = default;
+ TestEventObserver() = default;
+ ~TestEventObserver() override = default;
+
+ const ui::Event* last_event() const { return last_event_.get(); }
+ void ResetLastEvent() { last_event_.reset(); }
private:
- // ScreenPositionClient:
- void ConvertPointToScreen(const Window* window, gfx::PointF* point) override {
- const Window* root_window = window->GetRootWindow();
- Window::ConvertPointToTarget(window, root_window, point);
- gfx::Rect bounds = root_window->GetHost()->GetBoundsInPixels();
- point->Offset(bounds.x(), bounds.y());
- }
- void ConvertPointFromScreen(const Window* window,
- gfx::PointF* point) override {
- // unused.
- }
- void ConvertHostPointToScreen(Window* root_window,
- gfx::Point* point) override {
- // unused.
- }
- void SetBounds(Window* window,
- const gfx::Rect& bounds,
- const display::Display& display) override {
- // unused.
+ // ui::EventObserver:
+ void OnEvent(const ui::Event& event) override {
+ last_event_ = ui::Event::Clone(event);
}
- DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient);
-};
+ std::unique_ptr<ui::Event> last_event_;
-void OnWindowMoveDone(int* call_count, bool* last_result, bool result) {
- (*call_count)++;
- *last_result = result;
-}
+ DISALLOW_COPY_AND_ASSIGN(TestEventObserver);
+};
} // namespace
@@ -231,12 +221,8 @@ class WindowTreeClientTestSurfaceSync
// WindowTreeClientTest with --force-device-scale-factor=2.
class WindowTreeClientTestHighDPI : public WindowTreeClientTest {
public:
- WindowTreeClientTestHighDPI() {}
- ~WindowTreeClientTestHighDPI() override {}
-
- const ui::PointerEvent* last_event_observed() const {
- return last_event_observed_.get();
- }
+ WindowTreeClientTestHighDPI() = default;
+ ~WindowTreeClientTestHighDPI() override = default;
// WindowTreeClientTest:
void SetUp() override {
@@ -244,15 +230,8 @@ class WindowTreeClientTestHighDPI : public WindowTreeClientTest {
switches::kForceDeviceScaleFactor, "2");
WindowTreeClientTest::SetUp();
}
- void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- Window* target) override {
- last_event_observed_.reset(new ui::PointerEvent(event));
- }
private:
- std::unique_ptr<ui::PointerEvent> last_event_observed_;
-
DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTestHighDPI);
};
@@ -278,19 +257,22 @@ TEST_F(WindowTreeClientTest, SetBoundsFailedLocalSurfaceId) {
WindowPortMusTestHelper(&window).SimulateEmbedding();
const gfx::Rect original_bounds(window.bounds());
+ const viz::LocalSurfaceId original_local_surface_id(
+ window.GetLocalSurfaceIdAllocation().local_surface_id());
const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100));
ASSERT_NE(new_bounds, window.bounds());
window.SetBounds(new_bounds);
EXPECT_EQ(new_bounds, window.bounds());
WindowMus* window_mus = WindowMus::Get(&window);
ASSERT_NE(nullptr, window_mus);
- EXPECT_TRUE(window_mus->GetLocalSurfaceId().is_valid());
+ EXPECT_TRUE(window_mus->GetLocalSurfaceIdAllocation().IsValid());
// Reverting the change should also revert the viz::LocalSurfaceId.
ASSERT_TRUE(window_tree()->AckSingleChangeOfType(WindowTreeChangeType::BOUNDS,
false));
EXPECT_EQ(original_bounds, window.bounds());
- EXPECT_FALSE(window_mus->GetLocalSurfaceId().is_valid());
+ EXPECT_EQ(original_local_surface_id,
+ window.GetLocalSurfaceIdAllocation().local_surface_id());
}
INSTANTIATE_TEST_CASE_P(/* no prefix */,
@@ -303,10 +285,9 @@ TEST_P(WindowTreeClientTestSurfaceSync, ClientSurfaceEmbedderCreated) {
window.Init(ui::LAYER_NOT_DRAWN);
WindowPortMusTestHelper(&window).SimulateEmbedding();
- // The window will allocate a viz::LocalSurfaceId once it has a bounds.
WindowPortMus* window_port_mus = WindowPortMus::Get(&window);
ASSERT_NE(nullptr, window_port_mus);
- EXPECT_FALSE(WindowMus::Get(&window)->GetLocalSurfaceId().is_valid());
+
// A ClientSurfaceEmbedder is only created once there is bounds and a
// FrameSinkId.
EXPECT_EQ(nullptr, window_port_mus->client_surface_embedder());
@@ -314,7 +295,7 @@ TEST_P(WindowTreeClientTestSurfaceSync, ClientSurfaceEmbedderCreated) {
ASSERT_NE(new_bounds, window.bounds());
window.SetBounds(new_bounds);
EXPECT_EQ(new_bounds, window.bounds());
- EXPECT_TRUE(WindowMus::Get(&window)->GetLocalSurfaceId().is_valid());
+ EXPECT_TRUE(WindowMus::Get(&window)->GetLocalSurfaceIdAllocation().IsValid());
// Once the bounds have been set, the ClientSurfaceEmbedder should be created.
ClientSurfaceEmbedder* client_surface_embedder =
@@ -505,7 +486,6 @@ TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) {
// This shouldn't trigger the bounds changing yet.
EXPECT_EQ(new_bounds, root_window.bounds());
- EXPECT_FALSE(root_window_mus->GetLocalSurfaceId().is_valid());
// Tell the client the change failed, which should trigger failing to the
// most recent bounds from server.
@@ -513,14 +493,14 @@ TEST_F(WindowTreeClientTest, SetBoundsFailedWithPendingChange) {
false));
EXPECT_EQ(server_changed_bounds, root_window.bounds());
EXPECT_EQ(server_changed_local_surface_id,
- root_window_mus->GetLocalSurfaceId());
+ root_window_mus->GetLocalSurfaceIdAllocation().local_surface_id());
// Simulate server changing back to original bounds. Should take immediately.
window_tree_client()->OnWindowBoundsChanged(server_id(&root_window),
server_changed_bounds,
original_bounds, base::nullopt);
EXPECT_EQ(original_bounds, root_window.bounds());
- EXPECT_FALSE(root_window_mus->GetLocalSurfaceId().is_valid());
+ EXPECT_FALSE(root_window_mus->GetLocalSurfaceIdAllocation().IsValid());
}
TEST_F(WindowTreeClientTest, TwoInFlightBoundsChangesBothCanceled) {
@@ -927,7 +907,7 @@ TEST_F(WindowTreeClientTest, InputEventBasic) {
EXPECT_EQ(event_location_in_child, window_delegate.last_event_location());
}
-TEST_F(WindowTreeClientTest, InputEventPointerEvent) {
+TEST_F(WindowTreeClientTest, InputEventMouse) {
InputEventBasicTestWindowDelegate window_delegate(window_tree());
WindowTreeHostMus window_tree_host(
CreateInitParamsForTopLevel(window_tree_client_impl()));
@@ -1255,6 +1235,7 @@ TEST_F(WindowTreeClientTest, InputEventRootWindow) {
EXPECT_EQ(gfx::Point(20, 30), root_handler.last_event_location());
EXPECT_EQ(0, child_delegate.move_count());
EXPECT_EQ(gfx::Point(), child_delegate.last_event_location());
+ top_level->RemovePreTargetHandler(&root_handler);
}
TEST_F(WindowTreeClientTest, InputMouseEventNoWindow) {
@@ -1376,91 +1357,42 @@ TEST_F(WindowTreeClientTest, InputTouchEventNoWindow) {
EXPECT_FALSE(env->is_touch_down());
}
-class WindowTreeClientPointerObserverTest : public WindowTreeClientTest {
- public:
- WindowTreeClientPointerObserverTest() {}
- ~WindowTreeClientPointerObserverTest() override {}
-
- void DeleteLastEventObserved() { last_event_observed_.reset(); }
- const ui::PointerEvent* last_event_observed() const {
- return last_event_observed_.get();
- }
- const gfx::Point& last_location_in_screen() const {
- return last_location_in_screen_;
- }
-
- // WindowTreeClientTest:
- void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- Window* target) override {
- last_event_observed_.reset(new ui::PointerEvent(event));
- last_location_in_screen_ = location_in_screen;
- }
-
- protected:
- client::ScreenPositionClient* screen_position_client() {
- return &screen_position_client_;
- }
-
- private:
- std::unique_ptr<ui::PointerEvent> last_event_observed_;
- gfx::Point last_location_in_screen_;
- TestScreenPositionClient screen_position_client_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowTreeClientPointerObserverTest);
-};
-
-// Tests pointer watchers triggered by events that did not hit a target in this
-// window tree.
-TEST_F(WindowTreeClientPointerObserverTest, OnPointerEventObserved) {
+// Tests observation of events that did not hit a target in this window tree.
+TEST_F(WindowTreeClientTest, OnObservedInputEvent) {
std::unique_ptr<Window> top_level(std::make_unique<Window>(nullptr));
top_level->SetType(client::WINDOW_TYPE_NORMAL);
top_level->Init(ui::LAYER_NOT_DRAWN);
top_level->SetBounds(gfx::Rect(0, 0, 100, 100));
top_level->Show();
- // Start a pointer watcher for all events excluding move events.
- window_tree_client_impl()->StartPointerWatcher(false /* want_moves */);
-
- const int64_t kDisplayId = 111;
- test_screen()->display_list().AddDisplay(
- display::Display(kDisplayId, gfx::Rect(800, 0, 400, 400)),
- display::DisplayList::Type::NOT_PRIMARY);
+ // Start observing touch press events.
+ TestEventObserver test_event_observer;
+ top_level->env()->AddEventObserver(&test_event_observer, top_level->env(),
+ {ui::ET_TOUCH_PRESSED});
// Simulate the server sending an observed event.
- std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent(
- ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks()));
- window_tree_client()->OnPointerEventObserved(std::move(pointer_event_down),
- 0u, kDisplayId);
-
- // Delegate sensed the event.
- const ui::PointerEvent* last_event = last_event_observed();
- ASSERT_TRUE(last_event);
- EXPECT_EQ(ui::ET_POINTER_DOWN, last_event->type());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
- EXPECT_EQ(gfx::Point(800, 0), last_location_in_screen());
- DeleteLastEventObserved();
+ ui::TouchEvent touch_press(
+ ui::ET_TOUCH_PRESSED, gfx::Point(), ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ window_tree_client()->OnObservedInputEvent(ui::Event::Clone(touch_press));
+
+ // The observer should have been notified of the event.
+ ASSERT_TRUE(test_event_observer.last_event());
+ EXPECT_EQ(ui::ET_TOUCH_PRESSED, test_event_observer.last_event()->type());
+ test_event_observer.ResetLastEvent();
- // Stop the pointer watcher.
- window_tree_client_impl()->StopPointerWatcher();
+ // Remove the event observer.
+ top_level->env()->RemoveEventObserver(&test_event_observer);
// Simulate another event from the server.
- std::unique_ptr<ui::PointerEvent> pointer_event_up(new ui::PointerEvent(
- ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks()));
- window_tree_client()->OnPointerEventObserved(std::move(pointer_event_up), 0u,
- kDisplayId);
+ window_tree_client()->OnObservedInputEvent(ui::Event::Clone(touch_press));
- // No event was sensed.
- EXPECT_FALSE(last_event_observed());
+ // The observer should not have been notified of the event.
+ EXPECT_FALSE(test_event_observer.last_event());
}
-// Tests pointer watchers triggered by events that hit this window tree.
-TEST_F(WindowTreeClientPointerObserverTest,
- OnWindowInputEventWithPointerWatcher) {
+// Tests observation of events that did hit a target in this window tree.
+TEST_F(WindowTreeClientTest, OnWindowInputEventWithObserver) {
WindowTreeHostMus window_tree_host(
CreateInitParamsForTopLevel(window_tree_client_impl()));
Window* top_level = window_tree_host.window();
@@ -1469,26 +1401,23 @@ TEST_F(WindowTreeClientPointerObserverTest,
window_tree_host.InitHost();
window_tree_host.Show();
EXPECT_EQ(bounds.size(), top_level->bounds().size());
- client::SetScreenPositionClient(window_tree_host.window(),
- screen_position_client());
- // Start a pointer watcher for all events excluding move events.
- window_tree_client_impl()->StartPointerWatcher(false /* want_moves */);
+ // Start observing touch press events.
+ TestEventObserver test_event_observer;
+ top_level->env()->AddEventObserver(&test_event_observer, top_level->env(),
+ {ui::ET_TOUCH_PRESSED});
// Simulate the server dispatching an event that also matched the observer.
- ui::TouchEvent touch_event_down(
+ ui::TouchEvent touch_press(
ui::ET_TOUCH_PRESSED, gfx::Point(), ui::EventTimeForNow(),
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- ui::EF_CONTROL_DOWN);
- window_tree_client()->OnWindowInputEvent(
- 1, server_id(top_level), 0, ui::Event::Clone(touch_event_down), true);
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ window_tree_client()->OnWindowInputEvent(1, server_id(top_level), 0,
+ ui::Event::Clone(touch_press), true);
- // Delegate sensed the event.
- const ui::Event* last_event = last_event_observed();
- ASSERT_TRUE(last_event);
- EXPECT_EQ(ui::ET_POINTER_DOWN, last_event->type());
- EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags());
- EXPECT_EQ(gfx::Point(50, 50), last_location_in_screen());
+ // The observer should have been notified of the event.
+ ASSERT_TRUE(test_event_observer.last_event());
+ EXPECT_EQ(ui::ET_TOUCH_PRESSED, test_event_observer.last_event()->type());
+ top_level->env()->RemoveEventObserver(&test_event_observer);
}
// Verifies focus is reverted if the server replied that the change failed.
@@ -1545,7 +1474,7 @@ TEST_F(WindowTreeClientTest, SetFocusFailedWithPendingChange) {
EXPECT_TRUE(child1.HasFocus());
}
-TEST_F(WindowTreeClientTest, FocusOnRemovedWindowWithInFlightFocusChange) {
+TEST_F(WindowTreeClientTest, FocusOnRemovedWindowWithoutInFlightFocusChange) {
std::unique_ptr<Window> child1(std::make_unique<Window>(nullptr));
child1->Init(ui::LAYER_NOT_DRAWN);
root_window()->AddChild(child1.get());
@@ -1554,26 +1483,20 @@ TEST_F(WindowTreeClientTest, FocusOnRemovedWindowWithInFlightFocusChange) {
root_window()->AddChild(&child2);
child1->Focus();
+ // Acked for the focus change.
+ EXPECT_TRUE(
+ window_tree()->AckSingleChangeOfType(WindowTreeChangeType::FOCUS, true));
// Destroy child1, which should set focus to null.
child1.reset(nullptr);
EXPECT_EQ(nullptr, client::GetFocusClient(root_window())->GetFocusedWindow());
+ // The reset of the focus shouldn't be sent to the server.
+ EXPECT_EQ(0u,
+ window_tree()->GetChangeCountForType(WindowTreeChangeType::FOCUS));
// Server changes focus to 2.
window_tree_client()->OnWindowFocused(server_id(&child2));
- // Shouldn't take immediately.
- EXPECT_FALSE(child2.HasFocus());
-
- // Ack both changes, focus should still be null.
- ASSERT_TRUE(
- window_tree()->AckFirstChangeOfType(WindowTreeChangeType::FOCUS, true));
- EXPECT_EQ(nullptr, client::GetFocusClient(root_window())->GetFocusedWindow());
- ASSERT_TRUE(
- window_tree()->AckSingleChangeOfType(WindowTreeChangeType::FOCUS, true));
- EXPECT_EQ(nullptr, client::GetFocusClient(root_window())->GetFocusedWindow());
-
- // Change to 2 again, this time it should take.
- window_tree_client()->OnWindowFocused(server_id(&child2));
+ // Should take effect immediately.
EXPECT_TRUE(child2.HasFocus());
}
@@ -2489,7 +2412,21 @@ TEST_F(WindowTreeClientTestHighDPI, NewTopLevelWindowBounds) {
top_level->GetHost()->GetBoundsInPixels());
}
-TEST_F(WindowTreeClientTestHighDPI, PointerEventsInDip) {
+TEST_F(WindowTreeClientTestHighDPI, HostCtorInitializesDisplayScale) {
+ // WindowTreeHost's ctor attempts to initialize the display scale factor.
+ WindowTreeHostMus window_tree_host(
+ CreateInitParamsForTopLevel(window_tree_client_impl()));
+ EXPECT_EQ(2.0f, window_tree_host.device_scale_factor());
+ // This test sets pixel bounds before calling WindowTreeHost::InitHost() to
+ // simulate circumstances similar to <http://crbug.com/899084>. Pixel bounds
+ // should still be scaled to DIP bounds for the window tree before InitHost.
+ gfx::Rect bounds(2, 4, 60, 80);
+ gfx::Rect pixel_bounds = gfx::ConvertRectToPixel(2.0f, bounds);
+ window_tree_host.SetBoundsInPixels(pixel_bounds);
+ EXPECT_EQ(bounds, window_tree()->last_set_window_bounds());
+}
+
+TEST_F(WindowTreeClientTestHighDPI, ObservedInputEventsInDip) {
display::Screen* screen = display::Screen::GetScreen();
const display::Display primary_display = screen->GetPrimaryDisplay();
ASSERT_EQ(2.0f, primary_display.device_scale_factor());
@@ -2500,26 +2437,23 @@ TEST_F(WindowTreeClientTestHighDPI, PointerEventsInDip) {
top_level->SetBounds(gfx::Rect(0, 0, 100, 100));
top_level->Show();
- // Start a pointer watcher for all events excluding move events.
- window_tree_client_impl()->StartPointerWatcher(false /* want_moves */);
+ // Start observing touch press events.
+ TestEventObserver test_event_observer;
+ top_level->env()->AddEventObserver(&test_event_observer, top_level->env(),
+ {ui::ET_TOUCH_PRESSED});
- // Simulate the server sending an observed event.
+ // Simulate the server sending an observed event in screen dip coordinates.
const gfx::Point location(10, 12);
- const gfx::Point root_location(14, 16);
- std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent(
- ui::ET_POINTER_DOWN, location, root_location, ui::EF_CONTROL_DOWN, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks()));
- window_tree_client()->OnPointerEventObserved(std::move(pointer_event_down),
- 0u, primary_display.id());
-
- // Delegate received the event in Dips.
- const ui::PointerEvent* last_event = last_event_observed();
+ ui::TouchEvent touch_press(
+ ui::ET_TOUCH_PRESSED, location, ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1));
+ window_tree_client()->OnObservedInputEvent(ui::Event::Clone(touch_press));
+
+ // The observer should have received the event in screen dip coordinates.
+ const ui::Event* last_event = test_event_observer.last_event();
ASSERT_TRUE(last_event);
- // NOTE: the root and location are the same as there was no window supplied to
- // OnPointerEventObserved().
- EXPECT_EQ(root_location, last_event->location());
- EXPECT_EQ(root_location, last_event->root_location());
+ EXPECT_EQ(location, last_event->AsLocatedEvent()->location());
+ EXPECT_EQ(location, last_event->AsLocatedEvent()->root_location());
}
TEST_F(WindowTreeClientTestHighDPI, InputEventsInDip) {
@@ -2639,7 +2573,7 @@ TEST_F(WindowTreeClientTest, ChangeFocusInEmbedRootWindow) {
TestEmbedRootDelegate embed_root_delegate;
std::unique_ptr<EmbedRoot> embed_root =
window_tree_client_impl()->CreateEmbedRoot(&embed_root_delegate);
- WindowTreeClientPrivate(window_tree_client_impl())
+ WindowTreeClientTestApi(window_tree_client_impl())
.CallOnEmbedFromToken(embed_root.get());
ASSERT_TRUE(embed_root->window());
window_tree_client()->OnWindowFocused(server_id(embed_root->window()));
@@ -2688,4 +2622,54 @@ TEST_F(WindowTreeClientTest, PerformWindowMoveDoneAfterDelete) {
EXPECT_TRUE(last_result);
}
+// Verifies occlusion state from server is applied to underlying window.
+TEST_F(WindowTreeClientTest, OcclusionStateFromServer) {
+ struct {
+ const char* name;
+ bool window_is_visible;
+ ws::mojom::OcclusionState changed_state_from_server;
+ Window::OcclusionState expected_state;
+ } kTestCases[] = {
+ // VISIBLE is set when window is visible.
+ {"visible-set", true, ws::mojom::OcclusionState::kVisible,
+ Window::OcclusionState::VISIBLE},
+ // VISIBLE is not set when window hidden.
+ {"visible-not-set", false, ws::mojom::OcclusionState::kVisible,
+ Window::OcclusionState::HIDDEN},
+
+ // OCCLUDED is always set.
+ {"occluded-with-visible", true, ws::mojom::OcclusionState::kOccluded,
+ Window::OcclusionState::OCCLUDED},
+ {"occluded-with-invisible", false, ws::mojom::OcclusionState::kOccluded,
+ Window::OcclusionState::OCCLUDED},
+
+ // HIDDEN is set when window target visibility is false.
+ {"hidden-set", false, ws::mojom::OcclusionState::kHidden,
+ Window::OcclusionState::HIDDEN},
+ // HIDDEN is not set when window target visibility is true.
+ {"hidden-not-set", true, ws::mojom::OcclusionState::kHidden,
+ Window::OcclusionState::VISIBLE},
+ };
+
+ for (const auto& test : kTestCases) {
+ Window window(nullptr);
+ window.Init(ui::LAYER_NOT_DRAWN);
+ window.set_owned_by_parent(false);
+ root_window()->AddChild(&window);
+
+ window.TrackOcclusionState();
+ ASSERT_EQ(Window::OcclusionState::HIDDEN, window.occlusion_state());
+
+ if (test.window_is_visible && !window.IsVisible()) {
+ window.Show();
+ } else if (!test.window_is_visible && window.IsVisible()) {
+ window.Hide();
+ }
+
+ window_tree_client()->OnOcclusionStateChanged(
+ server_id(&window), test.changed_state_from_server);
+ EXPECT_EQ(test.expected_state, window.occlusion_state()) << test.name;
+ }
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/mus/window_tree_host_mus.cc b/chromium/ui/aura/mus/window_tree_host_mus.cc
index 47ff9645626..b6c7b101fa6 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus.cc
+++ b/chromium/ui/aura/mus/window_tree_host_mus.cc
@@ -120,7 +120,10 @@ void WindowTreeHostMus::SetBoundsFromServerInPixels(
const gfx::Rect& bounds_in_pixels,
const viz::LocalSurfaceId& local_surface_id) {
base::AutoReset<bool> resetter(&in_set_bounds_from_server_, true);
- SetBoundsInPixels(bounds_in_pixels, local_surface_id);
+ // TODO(jonross): Update Mus to pass the correct allocation time.
+ SetBoundsInPixels(
+ bounds_in_pixels,
+ viz::LocalSurfaceIdAllocation(local_surface_id, base::TimeTicks::Now()));
}
void WindowTreeHostMus::SetClientArea(
@@ -171,10 +174,11 @@ void WindowTreeHostMus::HideImpl() {
void WindowTreeHostMus::SetBoundsInPixels(
const gfx::Rect& bounds,
- const viz::LocalSurfaceId& local_surface_id) {
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
if (!in_set_bounds_from_server_)
delegate_->OnWindowTreeHostBoundsWillChange(this, bounds);
- WindowTreeHostPlatform::SetBoundsInPixels(bounds, local_surface_id);
+ WindowTreeHostPlatform::SetBoundsInPixels(bounds,
+ local_surface_id_allocation);
}
void WindowTreeHostMus::DispatchEvent(ui::Event* event) {
diff --git a/chromium/ui/aura/mus/window_tree_host_mus.h b/chromium/ui/aura/mus/window_tree_host_mus.h
index eaafd008187..c8c9b9f9507 100644
--- a/chromium/ui/aura/mus/window_tree_host_mus.h
+++ b/chromium/ui/aura/mus/window_tree_host_mus.h
@@ -85,9 +85,10 @@ class AURA_EXPORT WindowTreeHostMus : public WindowTreeHostPlatform,
// aura::WindowTreeHostPlatform:
void HideImpl() override;
- void SetBoundsInPixels(const gfx::Rect& bounds,
- const viz::LocalSurfaceId& local_surface_id =
- viz::LocalSurfaceId()) override;
+ void SetBoundsInPixels(
+ const gfx::Rect& bounds,
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation =
+ viz::LocalSurfaceIdAllocation()) override;
void DispatchEvent(ui::Event* event) override;
void OnClosed() override;
void OnActivationChanged(bool active) override;
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc b/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc
new file mode 100644
index 00000000000..f34b36a8fd2
--- /dev/null
+++ b/chromium/ui/aura/native_window_occlusion_tracker_unittest.cc
@@ -0,0 +1,158 @@
+// 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/aura/native_window_occlusion_tracker_win.h"
+
+#include <winuser.h>
+
+#include "base/win/scoped_gdi_object.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/win/window_impl.h"
+
+namespace aura {
+
+// Test wrapper around native window HWND.
+class TestNativeWindow : public gfx::WindowImpl {
+ public:
+ TestNativeWindow() {}
+ ~TestNativeWindow() override;
+
+ private:
+ // Overridden from gfx::WindowImpl:
+ BOOL ProcessWindowMessage(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT& result,
+ DWORD msg_map_id) override {
+ return FALSE; // Results in DefWindowProc().
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestNativeWindow);
+};
+
+TestNativeWindow::~TestNativeWindow() {
+ if (hwnd())
+ DestroyWindow(hwnd());
+}
+
+// This class currently tests the behavior of
+// NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque with hwnds
+// with various attributes (e.g., minimized, transparent, etc).
+class NativeWindowOcclusionTrackerTest : public test::AuraTestBase {
+ public:
+ NativeWindowOcclusionTrackerTest() {}
+
+ TestNativeWindow* native_win() { return native_win_.get(); }
+
+ HWND CreateNativeWindow(DWORD ex_style) {
+ native_win_ = std::make_unique<TestNativeWindow>();
+ native_win_->set_window_style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN);
+ native_win_->set_window_ex_style(ex_style);
+ gfx::Rect bounds(0, 0, 100, 100);
+ native_win_->Init(nullptr, bounds);
+ HWND hwnd = native_win_->hwnd();
+ base::win::ScopedRegion region(CreateRectRgn(0, 0, 0, 0));
+ if (GetWindowRgn(hwnd, region.get()) == COMPLEXREGION) {
+ // On Windows 7, the newly created window has a complex region, which
+ // means it will be ignored during the occlusion calculation. So, force
+ // it to have a simple region so that we get test coverage on win 7.
+ RECT bounding_rect;
+ EXPECT_TRUE(GetWindowRect(hwnd, &bounding_rect));
+ base::win::ScopedRegion rectangular_region(
+ CreateRectRgnIndirect(&bounding_rect));
+ SetWindowRgn(hwnd, rectangular_region.get(), /*redraw=*/TRUE);
+ }
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ EXPECT_TRUE(UpdateWindow(hwnd));
+ return hwnd;
+ }
+
+ // Wrapper around IsWindowVisibleAndFullyOpaque so only the test class
+ // needs to be a friend of NativeWindowOcclusionTrackerWin.
+ bool CheckWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* win_rect) {
+ bool ret = NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
+ hwnd, win_rect);
+ // In general, if IsWindowVisibleAndFullyOpaque returns false, the
+ // returned rect should not be altered.
+ if (!ret)
+ EXPECT_EQ(*win_rect, gfx::Rect(0, 0, 0, 0));
+ return ret;
+ }
+
+ private:
+ std::unique_ptr<TestNativeWindow> native_win_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerTest);
+};
+
+TEST_F(NativeWindowOcclusionTrackerTest, VisibleOpaqueWindow) {
+ HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ gfx::Rect returned_rect;
+ // Normal windows should be visible.
+ EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &returned_rect));
+
+ // Check that the returned rect == the actual window rect of the hwnd.
+ RECT win_rect;
+ ASSERT_TRUE(GetWindowRect(hwnd, &win_rect));
+ EXPECT_EQ(returned_rect, gfx::Rect(win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, MinimizedWindow) {
+ HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ gfx::Rect win_rect;
+ ShowWindow(hwnd, SW_MINIMIZE);
+ // Minimized windows are not considered visible.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, TransparentWindow) {
+ HWND hwnd = CreateNativeWindow(WS_EX_TRANSPARENT);
+ gfx::Rect win_rect;
+ // Transparent windows are not considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, ToolWindow) {
+ HWND hwnd = CreateNativeWindow(WS_EX_TOOLWINDOW);
+ gfx::Rect win_rect;
+ // Tool windows are not considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, LayeredAlphaWindow) {
+ HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+ gfx::Rect win_rect;
+ BYTE alpha = 1;
+ DWORD flags = LWA_ALPHA;
+ COLORREF color_ref = RGB(1, 1, 1);
+ SetLayeredWindowAttributes(hwnd, color_ref, alpha, flags);
+ // Layered windows with alpha < 255 are not considered visible and opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, LayeredNonAlphaWindow) {
+ HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+ gfx::Rect win_rect;
+ BYTE alpha = 1;
+ DWORD flags = 0;
+ COLORREF color_ref = RGB(1, 1, 1);
+ SetLayeredWindowAttributes(hwnd, color_ref, alpha, flags);
+ // Layered non alpha windows are considered visible and opaque.
+ EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+TEST_F(NativeWindowOcclusionTrackerTest, ComplexRegionWindow) {
+ HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+ gfx::Rect win_rect;
+ // Create a region with rounded corners, which should be a complex region.
+ base::win::ScopedRegion region(CreateRoundRectRgn(1, 1, 100, 100, 5, 5));
+ SetWindowRgn(hwnd, region.get(), /*redraw=*/TRUE);
+ // Windows with complex regions are not considered visible and fully opaque.
+ EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win.cc b/chromium/ui/aura/native_window_occlusion_tracker_win.cc
new file mode 100644
index 00000000000..b0372b96bb5
--- /dev/null
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win.cc
@@ -0,0 +1,540 @@
+// 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/aura/native_window_occlusion_tracker_win.h"
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/win/scoped_gdi_object.h"
+#include "ui/aura/window_tree_host.h"
+
+namespace aura {
+
+namespace {
+
+// ~16 ms = time between frames when frame rate is 60 FPS.
+const base::TimeDelta kUpdateOcclusionDelay =
+ base::TimeDelta::FromMilliseconds(16);
+
+NativeWindowOcclusionTrackerWin* g_tracker = nullptr;
+
+} // namespace
+
+NativeWindowOcclusionTrackerWin*
+NativeWindowOcclusionTrackerWin::GetOrCreateInstance() {
+ if (!g_tracker)
+ g_tracker = new NativeWindowOcclusionTrackerWin();
+
+ return g_tracker;
+}
+
+void NativeWindowOcclusionTrackerWin::Enable(Window* window) {
+ DCHECK(window->IsRootWindow());
+ if (window->HasObserver(this)) {
+ DCHECK(FALSE) << "window shouldn't already be observing occlusion tracker";
+ return;
+ }
+ // Add this as an observer so that we can be notified
+ // when it's no longer true that all windows are minimized, and when the
+ // window is destroyed.
+ HWND root_window_hwnd = window->GetHost()->GetAcceleratedWidget();
+ window->AddObserver(this);
+ // Remember this mapping from hwnd to Window*.
+ hwnd_root_window_map_[root_window_hwnd] = window;
+ // Notify the occlusion thread of the new HWND to track.
+ update_occlusion_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WindowOcclusionCalculator::EnableOcclusionTrackingForWindow,
+ base::Unretained(occlusion_calculator_.get()), root_window_hwnd));
+}
+
+void NativeWindowOcclusionTrackerWin::Disable(Window* window) {
+ DCHECK(window->IsRootWindow());
+ HWND root_window_hwnd = window->GetHost()->GetAcceleratedWidget();
+ // Check that the root_window_hwnd doesn't get cleared before this is called.
+ DCHECK(root_window_hwnd);
+ hwnd_root_window_map_.erase(root_window_hwnd);
+ window->RemoveObserver(this);
+ update_occlusion_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WindowOcclusionCalculator::DisableOcclusionTrackingForWindow,
+ base::Unretained(occlusion_calculator_.get()), root_window_hwnd));
+}
+
+void NativeWindowOcclusionTrackerWin::OnWindowVisibilityChanged(Window* window,
+ bool visible) {
+ if (!window->IsRootWindow())
+ return;
+ window->GetHost()->SetNativeWindowOcclusionState(
+ visible ? Window::OcclusionState::UNKNOWN
+ : Window::OcclusionState::HIDDEN);
+ update_occlusion_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&WindowOcclusionCalculator::HandleVisibilityChanged,
+ base::Unretained(occlusion_calculator_.get()), visible));
+}
+
+void NativeWindowOcclusionTrackerWin::OnWindowDestroying(Window* window) {
+ Disable(window);
+}
+
+NativeWindowOcclusionTrackerWin::NativeWindowOcclusionTrackerWin()
+ : // Use a COMSTATaskRunner so that registering and unregistering
+ // event hooks will happen on the same thread, as required by Windows,
+ // and the task runner will have a message loop to call
+ // EventHookCallback.
+ update_occlusion_task_runner_(base::CreateCOMSTATaskRunnerWithTraits(
+ {base::MayBlock(),
+ // This may be needed to determine that a window is no longer
+ // occluded.
+ base::TaskPriority::USER_VISIBLE,
+ // Occlusion calculation doesn't need to happen on shutdown.
+ // event hooks should also be cleaned up by Windows.
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
+ occlusion_calculator_ = std::make_unique<WindowOcclusionCalculator>(
+ update_occlusion_task_runner_, base::SequencedTaskRunnerHandle::Get());
+}
+
+NativeWindowOcclusionTrackerWin::~NativeWindowOcclusionTrackerWin() {
+ // This shouldn't be reached, because if it is, |occlusion_calculator_| will
+ // be deleted on the ui thread, which is problematic if there tasks scheduled
+ // on the background thread.
+ NOTREACHED();
+}
+
+// static
+bool NativeWindowOcclusionTrackerWin::IsWindowVisibleAndFullyOpaque(
+ HWND hwnd,
+ gfx::Rect* window_rect) {
+ // Filter out windows that are not “visible”, IsWindowVisible().
+ if (!IsWindow(hwnd) || !IsWindowVisible(hwnd))
+ return false;
+
+ // Filter out minimized windows.
+ if (IsIconic(hwnd))
+ return false;
+
+ LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
+
+ // Filter out “transparent” windows, windows where the mouse clicks fall
+ // through them.
+ if (ex_styles & WS_EX_TRANSPARENT)
+ return false;
+
+ // Filter out “tool windows”, which are floating windows that do not appear on
+ // the taskbar or ALT-TAB. Floating windows can have larger window rectangles
+ // than what is visible to the user, so by filtering them out we will avoid
+ // incorrectly marking native windows as occluded.
+ if (ex_styles & WS_EX_TOOLWINDOW)
+ return false;
+
+ // Filter out layered windows that are not opaque or that set a transparency
+ // colorkey.
+ if (ex_styles & WS_EX_LAYERED) {
+ BYTE alpha;
+ DWORD flags;
+ if (GetLayeredWindowAttributes(hwnd, nullptr, &alpha, &flags)) {
+ if (flags & LWA_ALPHA && alpha < 255)
+ return false;
+ if (flags & LWA_COLORKEY)
+ return false;
+ }
+ }
+
+ // Filter out windows that do not have a simple rectangular region.
+ base::win::ScopedRegion region(CreateRectRgn(0, 0, 0, 0));
+ if (GetWindowRgn(hwnd, region.get()) == COMPLEXREGION)
+ return false;
+
+ RECT win_rect;
+ // Filter out windows that take up zero area. The call to GetWindowRect is one
+ // of the most expensive parts of this function, so it is last.
+ if (!GetWindowRect(hwnd, &win_rect))
+ return false;
+ if (IsRectEmpty(&win_rect))
+ return false;
+ *window_rect = gfx::Rect(win_rect);
+ return true;
+}
+
+void NativeWindowOcclusionTrackerWin::UpdateOcclusionState(
+ const base::flat_map<HWND, Window::OcclusionState>&
+ root_window_hwnds_occlusion_state) {
+ for (const auto& root_window_pair : root_window_hwnds_occlusion_state) {
+ auto it = hwnd_root_window_map_.find(root_window_pair.first);
+ // The window was destroyed while processing occlusion.
+ if (it == hwnd_root_window_map_.end())
+ continue;
+ Window* root_window = it->second;
+ // Check Window::IsVisible here, on the UI thread, because it can't be
+ // checked on the occlusion calculation thread.
+ it->second->GetHost()->SetNativeWindowOcclusionState(
+ !root_window->IsVisible() ? Window::OcclusionState::HIDDEN
+ : root_window_pair.second);
+ }
+}
+
+NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ WindowOcclusionCalculator(
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner)
+ : task_runner_(task_runner), ui_thread_task_runner_(ui_thread_task_runner) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ~WindowOcclusionCalculator() {
+ DCHECK(global_event_hooks_.empty());
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ EnableOcclusionTrackingForWindow(HWND hwnd) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ NativeWindowOcclusionState default_state;
+ root_window_hwnds_occlusion_state_[hwnd] = default_state;
+ if (global_event_hooks_.empty())
+ RegisterEventHooks();
+
+ // Schedule an occlusion calculation so that the newly tracked window does
+ // not have a stale occlusion status.
+ ScheduleOcclusionCalculationIfNeeded();
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ DisableOcclusionTrackingForWindow(HWND hwnd) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ root_window_hwnds_occlusion_state_.erase(hwnd);
+ if (root_window_hwnds_occlusion_state_.empty()) {
+ UnregisterEventHooks();
+ if (occlusion_update_timer_.IsRunning())
+ occlusion_update_timer_.Stop();
+ }
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ HandleVisibilityChanged(bool visible) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // May have gone from having no visible windows to having one, in
+ // which case we need to register event hooks.
+ if (visible)
+ MaybeRegisterEventHooks();
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ MaybeRegisterEventHooks() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (global_event_hooks_.empty())
+ RegisterEventHooks();
+}
+
+// static
+void CALLBACK
+NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::EventHookCallback(
+ HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD dwEventThread,
+ DWORD dwmsEventTime) {
+ g_tracker->occlusion_calculator_->ProcessEventHookCallback(event, hwnd,
+ idObject, idChild);
+}
+
+// static
+BOOL CALLBACK NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ComputeNativeWindowOcclusionStatusCallback(HWND hwnd, LPARAM lParam) {
+ return g_tracker->occlusion_calculator_
+ ->ProcessComputeNativeWindowOcclusionStatusCallback(
+ hwnd, reinterpret_cast<base::flat_set<DWORD>*>(lParam));
+}
+
+// static
+BOOL CALLBACK NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ UpdateVisibleWindowProcessIdsCallback(HWND hwnd, LPARAM lParam) {
+ g_tracker->occlusion_calculator_
+ ->ProcessUpdateVisibleWindowProcessIdsCallback(hwnd);
+ return TRUE;
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ UpdateVisibleWindowProcessIds() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ pids_for_location_change_hook_.clear();
+ EnumWindows(&UpdateVisibleWindowProcessIdsCallback, 0);
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ComputeNativeWindowOcclusionStatus() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (root_window_hwnds_occlusion_state_.empty())
+ return;
+ // Set up initial conditions for occlusion calculation.
+ bool all_minimized = true;
+ for (auto& root_window_pair : root_window_hwnds_occlusion_state_) {
+ root_window_pair.second.unoccluded_region.setEmpty();
+ HWND hwnd = root_window_pair.first;
+
+ // IsIconic() checks for a minimized window. Immediately set the state of
+ // minimized windows to HIDDEN.
+ if (IsIconic(hwnd)) {
+ root_window_pair.second.occlusion_state = Window::OcclusionState::HIDDEN;
+ } else {
+ root_window_pair.second.occlusion_state = Window::OcclusionState::UNKNOWN;
+ RECT window_rect;
+ if (GetWindowRect(hwnd, &window_rect) != 0) {
+ root_window_pair.second.unoccluded_region =
+ SkRegion(SkIRect::MakeLTRB(window_rect.left, window_rect.top,
+ window_rect.right, window_rect.bottom));
+ }
+ // If call to GetWindowRect fails, window will be treated as occluded,
+ // because unoccluded_region will be empty.
+ all_minimized = false;
+ }
+ }
+ // Unregister event hooks if all native windows are minimized.
+ if (all_minimized) {
+ UnregisterEventHooks();
+ } else {
+ base::flat_set<DWORD> current_pids_with_visible_windows;
+ // Calculate unoccluded region if there is a non-minimized native window.
+ // Also compute |current_pids_with_visible_windows| as we enumerate
+ // the windows.
+ EnumWindows(&ComputeNativeWindowOcclusionStatusCallback,
+ reinterpret_cast<LPARAM>(&current_pids_with_visible_windows));
+ // Check if |pids_for_location_change_hook_| has any pids of processes
+ // currently without visible windows. If so, unhook the win event,
+ // remove the pid from |pids_for_location_change_hook_| and remove
+ // the corresponding event hook from |process_event_hooks_|.
+ base::flat_set<DWORD> pids_to_remove;
+ for (auto loc_change_pid : pids_for_location_change_hook_) {
+ if (current_pids_with_visible_windows.find(loc_change_pid) ==
+ current_pids_with_visible_windows.end()) {
+ // Remove the event hook from our map, and unregister the event hook.
+ // It's possible the eventhook will no longer be valid, but if we don't
+ // unregister the event hook, a process that toggles between having
+ // visible windows and not having visible windows could cause duplicate
+ // event hooks to get registered for the process.
+ UnhookWinEvent(process_event_hooks_[loc_change_pid]);
+ process_event_hooks_.erase(loc_change_pid);
+ pids_to_remove.insert(loc_change_pid);
+ }
+ }
+ if (!pids_to_remove.empty()) {
+ // EraseIf is O(n) so erase pids not found in one fell swoop.
+ base::EraseIf(pids_for_location_change_hook_,
+ [&pids_to_remove](DWORD pid) {
+ return pids_to_remove.find(pid) != pids_to_remove.end();
+ });
+ }
+ }
+ // Determine new occlusion status and post a task to the browser ui
+ // thread to update the window occlusion state on the root windows.
+ base::flat_map<HWND, Window::OcclusionState> window_occlusion_states;
+
+ for (auto& root_window_pair : root_window_hwnds_occlusion_state_) {
+ Window::OcclusionState new_state;
+ if (root_window_pair.second.occlusion_state !=
+ Window::OcclusionState::UNKNOWN) {
+ new_state = root_window_pair.second.occlusion_state;
+ } else {
+ new_state = root_window_pair.second.unoccluded_region.isEmpty()
+ ? Window::OcclusionState::OCCLUDED
+ : Window::OcclusionState::VISIBLE;
+ }
+ window_occlusion_states[root_window_pair.first] = new_state;
+ root_window_pair.second.occlusion_state = new_state;
+ }
+ ui_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&NativeWindowOcclusionTrackerWin::UpdateOcclusionState,
+ base::Unretained(g_tracker), window_occlusion_states));
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ScheduleOcclusionCalculationIfNeeded() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!occlusion_update_timer_.IsRunning())
+ occlusion_update_timer_.Start(
+ FROM_HERE, kUpdateOcclusionDelay, this,
+ &WindowOcclusionCalculator::ComputeNativeWindowOcclusionStatus);
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ RegisterGlobalEventHook(UINT event_min, UINT event_max) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ HWINEVENTHOOK event_hook =
+ SetWinEventHook(event_min, event_max, nullptr, &EventHookCallback, 0, 0,
+ WINEVENT_OUTOFCONTEXT);
+
+ global_event_hooks_.push_back(event_hook);
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ RegisterEventHookForProcess(DWORD pid) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ pids_for_location_change_hook_.insert(pid);
+ process_event_hooks_[pid] = SetWinEventHook(
+ EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, nullptr,
+ &EventHookCallback, pid, 0, WINEVENT_OUTOFCONTEXT);
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ RegisterEventHooks() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(global_event_hooks_.empty());
+
+ // Detects native window move (drag) and resizing events.
+ RegisterGlobalEventHook(EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND);
+
+ // Detects native window minimize and restore from taskbar events.
+ RegisterGlobalEventHook(EVENT_SYSTEM_MINIMIZESTART, EVENT_SYSTEM_MINIMIZEEND);
+
+ // Detects foreground window changing.
+ RegisterGlobalEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND);
+
+ // Detects object state changes, e.g., enable/disable state, native window
+ // maximize and native window restore events.
+ RegisterGlobalEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE);
+
+ // Determine which subset of processes to set EVENT_OBJECT_LOCATIONCHANGE on
+ // because otherwise event throughput is very high, as it generates events
+ // for location changes of all objects, including the mouse moving on top of a
+ // window.
+ UpdateVisibleWindowProcessIds();
+ for (DWORD pid : pids_for_location_change_hook_)
+ RegisterEventHookForProcess(pid);
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ UnregisterEventHooks() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ window_is_moving_ = false;
+ for (HWINEVENTHOOK event_hook : global_event_hooks_)
+ UnhookWinEvent(event_hook);
+ global_event_hooks_.clear();
+
+ for (DWORD pid : pids_for_location_change_hook_)
+ UnhookWinEvent(process_event_hooks_[pid]);
+ process_event_hooks_.clear();
+
+ pids_for_location_change_hook_.clear();
+}
+
+bool NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ProcessComputeNativeWindowOcclusionStatusCallback(
+ HWND hwnd,
+ base::flat_set<DWORD>* current_pids_with_visible_windows) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ gfx::Rect window_rect;
+ // Check if |hwnd| is a root_window; if so, we're done figuring out
+ // if it's occluded because we've seen all the windows "over" it.
+ // TODO(davidbienvenu): Explore checking if occlusion state has been
+ // computed for all |root_window_hwnds_occlusion_state_|, and if so, skipping
+ // further oclcusion calculations. However, we still want to keep computing
+ // |current_pids_with_visible_windows_|, so this function always returns true.
+ for (auto& root_window_pair : root_window_hwnds_occlusion_state_) {
+ if (hwnd == root_window_pair.first) {
+ if (root_window_pair.second.occlusion_state ==
+ Window::OcclusionState::HIDDEN) {
+ break;
+ }
+
+ root_window_pair.second.occlusion_state =
+ root_window_pair.second.unoccluded_region.isEmpty()
+ ? Window::OcclusionState::OCCLUDED
+ : Window::OcclusionState::VISIBLE;
+ break;
+ }
+ }
+ if (!IsWindowVisibleAndFullyOpaque(hwnd, &window_rect))
+ return true;
+ // We are interested in this window, but are not currently hooking it with
+ // EVENT_OBJECT_LOCATION_CHANGE, so we need to hook it. We check
+ // this by seeing if its PID is in |process_event_hooks_|.
+ DWORD pid;
+ GetWindowThreadProcessId(hwnd, &pid);
+ current_pids_with_visible_windows->insert(pid);
+ if (!base::ContainsKey(process_event_hooks_, pid))
+ RegisterEventHookForProcess(pid);
+
+ SkRegion window_region(SkIRect::MakeLTRB(window_rect.x(), window_rect.y(),
+ window_rect.right(),
+ window_rect.bottom()));
+
+ for (auto& root_window_pair : root_window_hwnds_occlusion_state_) {
+ if (root_window_pair.second.occlusion_state !=
+ Window::OcclusionState::UNKNOWN)
+ continue;
+ if (!root_window_pair.second.unoccluded_region.op(
+ window_region, SkRegion::kDifference_Op)) {
+ root_window_pair.second.occlusion_state =
+ Window::OcclusionState::OCCLUDED;
+ }
+ }
+ return true;
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ProcessEventHookCallback(DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild) {
+ // Can't do DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_) here. See
+ // comment before call to PostTask below as to why.
+
+ // No need to calculate occlusion if a zero HWND generated the event. This
+ // happens if there is no window associated with the event, e.g., mouse move
+ // events.
+ if (!hwnd)
+ return;
+ // Don't continually calculate occlusion while a window is moving, but rather
+ // once at the beginning and once at the end.
+ if (event == EVENT_SYSTEM_MOVESIZESTART) {
+ window_is_moving_ = true;
+ } else if (event == EVENT_SYSTEM_MOVESIZEEND) {
+ window_is_moving_ = false;
+ } else if (window_is_moving_) {
+ if (event == EVENT_OBJECT_LOCATIONCHANGE ||
+ event == EVENT_OBJECT_STATECHANGE) {
+ return;
+ }
+ // If we get an event that isn't a location/state change, then we probably
+ // missed the movesizeend notification, or got events out of order. In
+ // that case, we want to go back to calculating occlusion.
+ window_is_moving_ = false;
+ }
+ // ProcessEventHookCallback is called from the task_runner's PeekMessage
+ // call, on the task runner's thread, but before the task_tracker thread sets
+ // up the thread sequence. In order to prevent DCHECK failures with the
+ // |occlusion_update_timer_, we need to call
+ // ScheduleOcclusionCalculationIfNeeded from a task.
+ // See SchedulerWorkerCOMDelegate::GetWorkFromWindowsMessageQueue().
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &WindowOcclusionCalculator::ScheduleOcclusionCalculationIfNeeded,
+ base::Unretained(this)));
+}
+
+void NativeWindowOcclusionTrackerWin::WindowOcclusionCalculator::
+ ProcessUpdateVisibleWindowProcessIdsCallback(HWND hwnd) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ gfx::Rect window_rect;
+ if (IsWindowVisibleAndFullyOpaque(hwnd, &window_rect)) {
+ DWORD pid;
+ GetWindowThreadProcessId(hwnd, &pid);
+ pids_for_location_change_hook_.insert(pid);
+ }
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win.h b/chromium/ui/aura/native_window_occlusion_tracker_win.h
new file mode 100644
index 00000000000..477e77ab0d0
--- /dev/null
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win.h
@@ -0,0 +1,217 @@
+// 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_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
+#define UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
+
+#include <windows.h>
+#include <winuser.h>
+
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+
+// This class keeps track of whether any HWNDs are occluding any app windows.
+// It notifies the host of any app window whose occlusion state changes. Most
+// code should not need to use this; it's an implementation detail.
+class AURA_EXPORT NativeWindowOcclusionTrackerWin : public WindowObserver {
+ public:
+ static NativeWindowOcclusionTrackerWin* GetOrCreateInstance();
+
+ // Enables notifying the host of |window| via SetNativeWindowOcclusionState()
+ // when the occlusion state has been computed.
+ void Enable(Window* window);
+
+ // Disables notifying the host of |window| via
+ // OnNativeWindowOcclusionStateChanged() when the occlusion state has been
+ // computed. It's not neccesary to call this when |window| is deleted because
+ // OnWindowDestroying calls Disable.
+ void Disable(Window* window);
+
+ // aura::WindowObserver:
+ void OnWindowVisibilityChanged(Window* window, bool visible) override;
+ void OnWindowDestroying(Window* window) override;
+
+ private:
+ friend class NativeWindowOcclusionTrackerTest;
+
+ // This class computes the occlusion state of the tracked windows.
+ // It runs on a separate thread, and notifies the main thread of
+ // the occlusion state of the tracked windows.
+ class WindowOcclusionCalculator {
+ public:
+ WindowOcclusionCalculator(
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner);
+ ~WindowOcclusionCalculator();
+
+ void EnableOcclusionTrackingForWindow(HWND hwnd);
+ void DisableOcclusionTrackingForWindow(HWND hwnd);
+
+ // If a window becomes visible, makes sure event hooks are registered.
+ void HandleVisibilityChanged(bool visible);
+
+ private:
+ friend class NativeWindowOcclusionTrackerTest;
+ struct NativeWindowOcclusionState {
+ // The region of the native window that is not occluded by other windows.
+ SkRegion unoccluded_region;
+
+ // The current occlusion state of the native window. Default to UNKNOWN
+ // because we do not know the state starting out. More information on
+ // these states can be found in aura::Window.
+ aura::Window::OcclusionState occlusion_state =
+ aura::Window::OcclusionState::UNKNOWN;
+ };
+
+ // Registers event hooks, if not registered.
+ void MaybeRegisterEventHooks();
+
+ // This is the callback registered to get notified of various Windows
+ // events, like window moving/resizing.
+ static void CALLBACK EventHookCallback(HWINEVENTHOOK hWinEventHook,
+ DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild,
+ DWORD dwEventThread,
+ DWORD dwmsEventTime);
+
+ // EnumWindows callback used to iterate over all hwnds to determine
+ // occlusion status of all tracked root windows. Also builds up
+ // |current_pids_with_visible_windows_| and registers event hooks for newly
+ // discovered processes with visible hwnds.
+ static BOOL CALLBACK
+ ComputeNativeWindowOcclusionStatusCallback(HWND hwnd, LPARAM lParam);
+
+ // EnumWindows callback used to update the list of process ids with
+ // visible hwnds, |pids_for_location_change_hook_|.
+ static BOOL CALLBACK UpdateVisibleWindowProcessIdsCallback(HWND hwnd,
+ LPARAM lParam);
+
+ // Determines which processes owning visible application windows to set the
+ // EVENT_OBJECT_LOCATIONCHANGE event hook for and stores the pids in
+ // |pids_for_location_change_hook_|.
+ void UpdateVisibleWindowProcessIds();
+
+ // Computes the native window occlusion status for all tracked root aura
+ // windows in |root_window_hwnds_occlusion_state_| and notifies them if
+ // their occlusion status has changed.
+ void ComputeNativeWindowOcclusionStatus();
+
+ // Schedules an occlusion calculation |update_occlusion_delay_| time in the
+ // future, if one isn't already scheduled.
+ void ScheduleOcclusionCalculationIfNeeded();
+
+ // Registers a global event hook (not per process) for the events in the
+ // range from |event_min| to |event_max|, inclusive.
+ void RegisterGlobalEventHook(UINT event_min, UINT event_max);
+
+ // Registers the EVENT_OBJECT_LOCATIONCHANGE event hook for the process with
+ // passed id. The process has one or more visible, opaque windows.
+ void RegisterEventHookForProcess(DWORD pid);
+
+ // Registers/Unregisters the event hooks necessary for occlusion tracking
+ // via calls to RegisterEventHook. These event hooks are disabled when all
+ // tracked windows are minimized.
+ void RegisterEventHooks();
+ void UnregisterEventHooks();
+
+ // EnumWindows callback for occlusion calculation. Returns true to
+ // continue enumeration, false otherwise. Currently, always returns
+ // true because this function also updates
+ // |current_pids_with_visible_windows|, and needs to see all HWNDs.
+ bool ProcessComputeNativeWindowOcclusionStatusCallback(
+ HWND hwnd,
+ base::flat_set<DWORD>* current_pids_with_visible_windows);
+
+ // Processes events sent to OcclusionEventHookCallback.
+ // It generally triggers scheduling of the occlusion calculation, but
+ // ignores certain events in order to not calculate occlusion more than
+ // necessary.
+ void ProcessEventHookCallback(DWORD event,
+ HWND hwnd,
+ LONG idObject,
+ LONG idChild);
+
+ // EnumWindows callback for determining which processes to set the
+ // EVENT_OBJECT_LOCATIONCHANGE event hook for. We set that event hook for
+ // processes hosting fully visible, opaque windows.
+ void ProcessUpdateVisibleWindowProcessIdsCallback(HWND hwnd);
+
+ // Task runner for our thread.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ // Task runner for the thread that created |this|. UpdateOcclusionState
+ // task is posted to this task runner.
+ const scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner_;
+
+ // Map of root app window hwnds and their occlusion state. This contains
+ // both visible and hidden windows.
+ base::flat_map<HWND, NativeWindowOcclusionState>
+ root_window_hwnds_occlusion_state_;
+
+ // Values returned by SetWinEventHook are stored so that hooks can be
+ // unregistered when necessary.
+ std::vector<HWINEVENTHOOK> global_event_hooks_;
+
+ // Map from process id to EVENT_OBJECT_LOCATIONCHANGE event hook.
+ base::flat_map<DWORD, HWINEVENTHOOK> process_event_hooks_;
+
+ // Pids of processes for which the EVENT_OBJECT_LOCATIONCHANGE event hook is
+ // set. These are the processes hosting windows in
+ // |visible_and_fully_opaque_windows_|.
+ base::flat_set<DWORD> pids_for_location_change_hook_;
+
+ // Timer to delay occlusion update.
+ base::OneShotTimer occlusion_update_timer_;
+
+ // Used to keep track of whether we're in the middle of getting window move
+ // events, in order to wait until the window move is complete before
+ // calculating window occlusion.
+ bool window_is_moving_ = false;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(WindowOcclusionCalculator);
+ };
+
+ NativeWindowOcclusionTrackerWin();
+ ~NativeWindowOcclusionTrackerWin() override;
+
+ // Returns true if we are interested in |hwnd| for purposes of occlusion
+ // calculation. We are interested in |hwnd| if it is a window that is visible,
+ // opaque, and bounded. If we are interested in |hwnd|, stores the window
+ // rectangle in |window_rect|.
+ static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect);
+
+ // Updates root windows occclusion state.
+ void UpdateOcclusionState(const base::flat_map<HWND, Window::OcclusionState>&
+ root_window_hwnds_occlusion_state);
+
+ // Task runner to call ComputeNativeWindowOcclusionStatus, and to handle
+ // Windows event notifications, off of the UI thread.
+ const scoped_refptr<base::SequencedTaskRunner> update_occlusion_task_runner_;
+
+ // Map of HWND to root app windows. Maintained on the UI thread, and used
+ // to send occlusion state notifications to Windows from
+ // |root_window_hwnds_occlusion_state_|.
+ base::flat_map<HWND, Window*> hwnd_root_window_map_;
+
+ std::unique_ptr<WindowOcclusionCalculator> occlusion_calculator_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerWin);
+};
+
+} // namespace aura
+
+#endif // UI_AURA_NATIVE_WINDOW_OCCLUSION_TRACKER_WIN_H_
diff --git a/chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc b/chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc
new file mode 100644
index 00000000000..674a2a90d76
--- /dev/null
+++ b/chromium/ui/aura/native_window_occlusion_tracker_win_interactive_test.cc
@@ -0,0 +1,211 @@
+// 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/aura/native_window_occlusion_tracker_win.h"
+
+#include <winuser.h>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/task/task_scheduler/task_scheduler.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/win/scoped_gdi_object.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/env.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_focus_client.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_window_parenting_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_occlusion_tracker.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/aura/window_tree_host_platform.h"
+#include "ui/base/ime/input_method_initializer.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/display/win/dpi.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/win/window_impl.h"
+#include "ui/gl/test/gl_surface_test_support.h"
+
+namespace aura {
+
+// This class is used to verify expectations about occlusion state changes by
+// adding instances of it as an observer of aura:Windows the tests create and
+// checking that they get the expected call(s) to OnOcclusionStateChanged.
+// The tests verify that the current state, when idle, is the expected state,
+// because the state can be VISIBLE before it reaches the expected state.
+class MockWindowTreeHostObserver : public WindowTreeHostObserver {
+ public:
+ explicit MockWindowTreeHostObserver(base::OnceClosure quit_closure)
+ : quit_closure_(std::move(quit_closure)) {}
+ ~MockWindowTreeHostObserver() override { EXPECT_FALSE(is_expecting_call()); }
+
+ // WindowTreeHostObserver:
+ void OnOcclusionStateChanged(WindowTreeHost* host,
+ Window::OcclusionState new_state) override {
+ EXPECT_NE(new_state, Window::OcclusionState::UNKNOWN);
+ // Should only get notified when the occlusion state changes.
+ EXPECT_NE(new_state, cur_state_);
+ cur_state_ = new_state;
+ if (cur_state_ == expectation_) {
+ EXPECT_FALSE(quit_closure_.is_null());
+ std::move(quit_closure_).Run();
+ }
+ }
+
+ void set_expectation(Window::OcclusionState expectation) {
+ expectation_ = expectation;
+ }
+
+ bool is_expecting_call() const { return expectation_ != cur_state_; }
+
+ private:
+ Window::OcclusionState expectation_ = Window::OcclusionState::UNKNOWN;
+ Window::OcclusionState cur_state_ = Window::OcclusionState::UNKNOWN;
+ base::OnceClosure quit_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockWindowTreeHostObserver);
+};
+
+// Test wrapper around native window HWND.
+class TestNativeWindow : public gfx::WindowImpl {
+ public:
+ TestNativeWindow() {}
+ ~TestNativeWindow() override;
+
+ private:
+ // Overridden from gfx::WindowImpl:
+ BOOL ProcessWindowMessage(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT& result,
+ DWORD msg_map_id) override {
+ return FALSE; // Results in DefWindowProc().
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestNativeWindow);
+};
+
+TestNativeWindow::~TestNativeWindow() {
+ if (hwnd())
+ DestroyWindow(hwnd());
+}
+
+class NativeWindowOcclusionTrackerTest : public test::AuraTestBase {
+ public:
+ NativeWindowOcclusionTrackerTest() {}
+ void SetUp() override {
+ if (gl::GetGLImplementation() == gl::kGLImplementationNone)
+ gl::GLSurfaceTestSupport::InitializeOneOff();
+
+ AuraTestBase::SetUp();
+ ui::InitializeInputMethodForTesting();
+
+ display::Screen::SetScreenInstance(test_screen());
+
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kCalculateNativeWinOcclusion);
+ }
+
+ void SetNativeWindowBounds(HWND hwnd, const gfx::Rect& bounds) {
+ RECT wr = bounds.ToRECT();
+ AdjustWindowRectEx(&wr, GetWindowLong(hwnd, GWL_STYLE), FALSE,
+ GetWindowLong(hwnd, GWL_EXSTYLE));
+
+ // Make sure to keep the window onscreen, as AdjustWindowRectEx() may have
+ // moved part of it offscreen.
+ gfx::Rect window_bounds(wr);
+ window_bounds.set_x(std::max(0, window_bounds.x()));
+ window_bounds.set_y(std::max(0, window_bounds.y()));
+ SetWindowPos(hwnd, HWND_TOP, window_bounds.x(), window_bounds.y(),
+ window_bounds.width(), window_bounds.height(),
+ SWP_NOREPOSITION);
+ EXPECT_TRUE(UpdateWindow(hwnd));
+ }
+
+ HWND CreateNativeWindowWithBounds(const gfx::Rect& bounds) {
+ native_win_ = std::make_unique<TestNativeWindow>();
+ native_win_->set_window_style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN);
+ native_win_->Init(nullptr, bounds);
+ HWND hwnd = native_win_->hwnd();
+ SetNativeWindowBounds(hwnd, bounds);
+ base::win::ScopedRegion region(CreateRectRgn(0, 0, 0, 0));
+ if (GetWindowRgn(hwnd, region.get()) == COMPLEXREGION) {
+ // On Windows 7, the newly created window has a complex region, which
+ // means it will be ignored during the occlusion calculation. So, force
+ // it to have a simple region so that we get test coverage on win 7.
+ RECT bounding_rect;
+ GetWindowRect(hwnd, &bounding_rect);
+ base::win::ScopedRegion rectangular_region(
+ CreateRectRgnIndirect(&bounding_rect));
+ SetWindowRgn(hwnd, rectangular_region.get(), TRUE);
+ }
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ EXPECT_TRUE(UpdateWindow(hwnd));
+ return hwnd;
+ }
+
+ void CreateTrackedAuraWindowWithBounds(MockWindowTreeHostObserver* observer,
+ gfx::Rect bounds) {
+ host()->Show();
+ host()->SetBoundsInPixels(bounds);
+ host()->AddObserver(observer);
+
+ Window* window = CreateNormalWindow(1, host()->window(), nullptr);
+ window->SetBounds(bounds);
+
+ window->env()->GetWindowOcclusionTracker()->Track(window);
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ std::unique_ptr<TestNativeWindow> native_win_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeWindowOcclusionTrackerTest);
+};
+
+// Simple test completely covering an aura window with a native window.
+TEST_F(NativeWindowOcclusionTrackerTest, SimpleOcclusion) {
+ base::RunLoop run_loop;
+
+ MockWindowTreeHostObserver observer(run_loop.QuitClosure());
+ CreateTrackedAuraWindowWithBounds(&observer, gfx::Rect(0, 0, 100, 100));
+ observer.set_expectation(Window::OcclusionState::OCCLUDED);
+ CreateNativeWindowWithBounds(gfx::Rect(0, 0, 100, 100));
+ run_loop.Run();
+ EXPECT_FALSE(observer.is_expecting_call());
+}
+
+// Simple test with an aura window and native window that do not overlap.
+TEST_F(NativeWindowOcclusionTrackerTest, SimpleVisible) {
+ base::RunLoop run_loop;
+ MockWindowTreeHostObserver observer(run_loop.QuitClosure());
+ CreateTrackedAuraWindowWithBounds(&observer, gfx::Rect(0, 0, 100, 100));
+ observer.set_expectation(Window::OcclusionState::VISIBLE);
+ CreateNativeWindowWithBounds(gfx::Rect(200, 0, 100, 100));
+
+ run_loop.Run();
+ EXPECT_FALSE(observer.is_expecting_call());
+}
+
+// Simple test with a minimized aura window and native window.
+TEST_F(NativeWindowOcclusionTrackerTest, SimpleHidden) {
+ base::RunLoop run_loop;
+ MockWindowTreeHostObserver observer(run_loop.QuitClosure());
+ CreateTrackedAuraWindowWithBounds(&observer, gfx::Rect(0, 0, 100, 100));
+ CreateNativeWindowWithBounds(gfx::Rect(200, 0, 100, 100));
+ // Minimize the tracked aura window and check that its occlusion state
+ // is HIDDEN.
+ ::ShowWindow(host()->GetAcceleratedWidget(), SW_MINIMIZE);
+ observer.set_expectation(Window::OcclusionState::HIDDEN);
+ run_loop.Run();
+ EXPECT_FALSE(observer.is_expecting_call());
+}
+
+} // namespace aura
diff --git a/chromium/ui/aura/test/ui_controls_factory_ozone.cc b/chromium/ui/aura/test/ui_controls_factory_ozone.cc
index 24ef109d467..2c6070f7207 100644
--- a/chromium/ui/aura/test/ui_controls_factory_ozone.cc
+++ b/chromium/ui/aura/test/ui_controls_factory_ozone.cc
@@ -41,6 +41,8 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
public:
UIControlsOzone(WindowTreeHost* host) : host_(host) {}
+ private:
+ // ui_controls::UIControlsAura:
bool SendKeyPress(gfx::NativeWindow window,
ui::KeyboardCode key,
bool control,
@@ -124,18 +126,9 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
bool SendMouseMoveNotifyWhenDone(long screen_x,
long screen_y,
base::OnceClosure closure) override {
- // The location needs to be in display's coordinate.
- gfx::Point display_location(screen_x, screen_y);
- display::Display display;
- if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(
- host_->GetDisplayId(), &display)) {
- LOG(ERROR) << "Failed to see the display for " << host_->GetDisplayId();
+ gfx::Point host_location(screen_x, screen_y);
+ if (!ScreenDIPToHostPixels(&host_location))
return false;
- }
- display_location -= display.bounds().OffsetFromOrigin();
-
- gfx::Point host_location = display_location;
- host_->ConvertDIPToPixels(&host_location);
last_mouse_location_ = host_location;
ui::EventType event_type;
@@ -164,19 +157,9 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
if (last_mouse_location_.has_value()) {
host_location = last_mouse_location_.value();
} else {
- // The location needs to be in display's coordinate.
- gfx::Point display_location =
- host_->window()->env()->last_mouse_location();
- display::Display display;
- if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(
- host_->GetDisplayId(), &display)) {
- LOG(ERROR) << "Failed to see the display for " << host_->GetDisplayId();
+ host_location = host_->window()->env()->last_mouse_location();
+ if (!ScreenDIPToHostPixels(&host_location))
return false;
- }
- display_location -= display.bounds().OffsetFromOrigin();
-
- host_location = display_location;
- host_->ConvertDIPToPixels(&host_location);
}
int changed_button_flag = 0;
@@ -228,8 +211,44 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
return SendMouseEvents(type, ui_controls::UP | ui_controls::DOWN,
ui_controls::kNoAccelerator);
}
+#if defined(OS_CHROMEOS)
+ bool SendTouchEvents(int action, int id, int x, int y) override {
+ return SendTouchEventsNotifyWhenDone(action, id, x, y, base::OnceClosure());
+ }
+ bool SendTouchEventsNotifyWhenDone(int action,
+ int id,
+ int x,
+ int y,
+ base::OnceClosure task) override {
+ DCHECK_NE(0, action);
+ gfx::Point host_location(x, y);
+ if (!ScreenDIPToHostPixels(&host_location))
+ return false;
+ bool has_move = action & ui_controls::MOVE;
+ bool has_release = action & ui_controls::RELEASE;
+ ui::PointerDetails details(ui::EventPointerType::POINTER_TYPE_TOUCH, id,
+ 1.0f, 1.0f, 0.0f);
+ if (action & ui_controls::PRESS) {
+ ui::TouchEvent event(ui::ET_TOUCH_PRESSED, host_location,
+ base::TimeTicks::Now(), details);
+ SendEventToSink(&event, (has_move || has_release) ? base::OnceClosure()
+ : std::move(task));
+ }
+ if (has_move) {
+ ui::TouchEvent event(ui::ET_TOUCH_MOVED, host_location,
+ base::TimeTicks::Now(), details);
+ SendEventToSink(&event,
+ has_release ? base::OnceClosure() : std::move(task));
+ }
+ if (has_release) {
+ ui::TouchEvent event(ui::ET_TOUCH_RELEASED, host_location,
+ base::TimeTicks::Now(), details);
+ SendEventToSink(&event, std::move(task));
+ }
+ return true;
+ }
+#endif
- private:
void SendEventToSink(ui::Event* event, base::OnceClosure closure) {
if (host_->window()->env()->mode() == aura::Env::Mode::MUS) {
GetEventInjector()->InjectEvent(
@@ -311,6 +330,19 @@ class UIControlsOzone : public ui_controls::UIControlsAura {
return event_injector_.get();
}
+ bool ScreenDIPToHostPixels(gfx::Point* location) {
+ // The location needs to be in display's coordinate.
+ display::Display display;
+ if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(
+ host_->GetDisplayId(), &display)) {
+ LOG(ERROR) << "Failed to find the display for " << host_->GetDisplayId();
+ return false;
+ }
+ *location -= display.bounds().OffsetFromOrigin();
+ host_->ConvertDIPToPixels(location);
+ return true;
+ }
+
WindowTreeHost* host_;
ws::mojom::EventInjectorPtr event_injector_;
diff --git a/chromium/ui/aura/window.cc b/chromium/ui/aura/window.cc
index 18829840094..ef148894298 100644
--- a/chromium/ui/aura/window.cc
+++ b/chromium/ui/aura/window.cc
@@ -334,14 +334,27 @@ void Window::SetBounds(const gfx::Rect& new_bounds) {
void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen,
const display::Display& dst_display) {
+ WindowTreeHost* host = GetHost();
+ bool is_moving = false;
+ if (host && host->GetDisplayId() != dst_display.id()) {
+ is_moving = true;
+ for (auto& observer : observers_)
+ observer.OnWillMoveWindowToDisplay(this, dst_display.id());
+ }
+
+ aura::client::ScreenPositionClient* screen_position_client = nullptr;
Window* root = GetRootWindow();
- if (root) {
- aura::client::ScreenPositionClient* screen_position_client =
- aura::client::GetScreenPositionClient(root);
+ if (root)
+ screen_position_client = aura::client::GetScreenPositionClient(root);
+ if (screen_position_client)
screen_position_client->SetBounds(this, new_bounds_in_screen, dst_display);
- return;
+ else
+ SetBounds(new_bounds_in_screen);
+
+ if (is_moving) {
+ for (auto& observer : observers_)
+ observer.OnDidMoveWindowToDisplay(this);
}
- SetBounds(new_bounds_in_screen);
}
gfx::Rect Window::GetTargetBounds() const {
@@ -537,12 +550,10 @@ bool Window::ShouldRestackTransientChildren() {
}
void Window::AddObserver(WindowObserver* observer) {
- observer->OnObservingWindow(this);
observers_.AddObserver(observer);
}
void Window::RemoveObserver(WindowObserver* observer) {
- observer->OnUnobservingWindow(this);
observers_.RemoveObserver(observer);
}
@@ -874,11 +885,14 @@ void Window::SetVisible(bool visible) {
NotifyWindowVisibilityChanged(this, visible);
}
-void Window::SetOcclusionState(OcclusionState occlusion_state) {
- if (occlusion_state != occlusion_state_) {
+void Window::SetOcclusionInfo(OcclusionState occlusion_state,
+ const SkRegion& occluded_region) {
+ if (occlusion_state != occlusion_state_ ||
+ occluded_region_ != occluded_region) {
occlusion_state_ = occlusion_state;
+ occluded_region_ = occluded_region;
if (delegate_)
- delegate_->OnWindowOcclusionChanged(occlusion_state);
+ delegate_->OnWindowOcclusionChanged(occlusion_state, occluded_region);
}
}
@@ -1102,38 +1116,41 @@ std::unique_ptr<cc::LayerTreeFrameSink> Window::CreateLayerTreeFrameSink() {
auto sink = port_->CreateLayerTreeFrameSink();
DCHECK(frame_sink_id_.is_valid());
DCHECK(embeds_external_client_);
- DCHECK(GetLocalSurfaceId().is_valid());
+ DCHECK(GetLocalSurfaceIdAllocation().local_surface_id().is_valid());
created_layer_tree_frame_sink_ = true;
return sink;
}
viz::SurfaceId Window::GetSurfaceId() const {
- return viz::SurfaceId(GetFrameSinkId(), port_->GetLocalSurfaceId());
+ return viz::SurfaceId(
+ GetFrameSinkId(),
+ port_->GetLocalSurfaceIdAllocation().local_surface_id());
}
void Window::AllocateLocalSurfaceId() {
port_->AllocateLocalSurfaceId();
}
-bool Window::IsLocalSurfaceIdAllocationSuppressed() const {
- return port_->IsLocalSurfaceIdAllocationSuppressed();
-}
-
viz::ScopedSurfaceIdAllocator Window::GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) {
return port_->GetSurfaceIdAllocator(std::move(allocation_task));
}
-const viz::LocalSurfaceId& Window::GetLocalSurfaceId() const {
- return port_->GetLocalSurfaceId();
+const viz::LocalSurfaceIdAllocation& Window::GetLocalSurfaceIdAllocation()
+ const {
+ return port_->GetLocalSurfaceIdAllocation();
+}
+
+void Window::InvalidateLocalSurfaceId() {
+ port_->InvalidateLocalSurfaceId();
}
void Window::UpdateLocalSurfaceIdFromEmbeddedClient(
- const base::Optional<viz::LocalSurfaceId>&
- embedded_client_local_surface_id) {
- if (embedded_client_local_surface_id) {
+ const base::Optional<viz::LocalSurfaceIdAllocation>&
+ embedded_client_local_surface_id_allocation) {
+ if (embedded_client_local_surface_id_allocation) {
port_->UpdateLocalSurfaceIdFromEmbeddedClient(
- *embedded_client_local_surface_id);
+ *embedded_client_local_surface_id_allocation);
} else {
port_->AllocateLocalSurfaceId();
}
@@ -1163,7 +1180,7 @@ bool Window::IsEmbeddingClient() const {
}
void Window::TrackOcclusionState() {
- env_->GetWindowOcclusionTracker()->Track(this);
+ port_->TrackOcclusionState();
}
bool Window::RequiresDoubleTapGestureEvents() const {
@@ -1318,7 +1335,7 @@ std::unique_ptr<ui::Layer> Window::RecreateLayer() {
}
void Window::UpdateLayerName() {
-#if !defined(NDEBUG)
+#if DCHECK_IS_ON()
DCHECK(layer());
std::string layer_name(GetName());
diff --git a/chromium/ui/aura/window.h b/chromium/ui/aura/window.h
index 6175dcd10ba..010edc94e27 100644
--- a/chromium/ui/aura/window.h
+++ b/chromium/ui/aura/window.h
@@ -19,6 +19,8 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/window_types.h"
@@ -94,30 +96,36 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
STACK_ABOVE,
STACK_BELOW
};
+
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
enum class OcclusionState {
// The window's occlusion state isn't tracked (Window::TrackOcclusionState)
// or hasn't been computed yet.
- UNKNOWN,
+ UNKNOWN = 0,
// The window or one of its descendants IsVisible() [1] and:
// - Its bounds aren't completely covered by fully opaque windows [2], or,
// - Its transform, bounds or opacity is animated.
- VISIBLE,
+ VISIBLE = 1,
// The window or one of its descendants IsVisible() [1], but they all:
// - Have bounds completely covered by fully opaque windows [2], and,
// - Have no transform, bounds or opacity animation.
- OCCLUDED,
+ OCCLUDED = 2,
// The window is not IsVisible() [1].
- HIDDEN,
+ HIDDEN = 3,
// [1] A window can only be IsVisible() if all its parent are IsVisible().
// [2] A window is "fully opaque" if:
// - It's visible (IsVisible()).
// - It's not transparent (transparent()).
// - It's transform, bounds and opacity aren't animated.
// - Its combined opacity is 1 (GetCombinedOpacity()).
- // - The type of its layer is not ui::LAYER_NOT_DRAWN.
+ // - It has content to draw. Either the type of its layer is not
+ // ui::LAYER_NOT_DRAWN, or it is a server window hosting remote client
+ // content in Window Service.
//
// TODO(fdoray): A window that clips its children shouldn't be VISIBLE just
// because it has an animated child.
+ kMaxValue = HIDDEN,
};
typedef std::vector<Window*> Windows;
@@ -199,6 +207,18 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// WindowOcclusionTracker::ScopedPause.
OcclusionState occlusion_state() const { return occlusion_state_; }
+ // Returns the currently occluded region. This will be empty unless
+ // the window is tracked and has a VISIBLE occlusion state. That is,
+ // this is only maintained when the window is partially occluded. Further,
+ // this region may extend outside the window bounds. For performance reasons,
+ // the actual intersection with the window is not computed. The occluded
+ // region is the set of window rectangles that may occlude this window.
+ // Note that this means that the occluded region may be updated if one of
+ // those windows moves, even if the actual intersection of the occluded
+ // region with this window does not change. Clients may compute the actual
+ // intersection region if necessary.
+ const SkRegion& occluded_region() const { return occluded_region_; }
+
// Returns the window's bounds in root window's coordinates.
gfx::Rect GetBoundsInRootWindow() const;
@@ -397,22 +417,22 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// that does not involve a resize or a device scale factor change.
void AllocateLocalSurfaceId();
- // When a child-allocated viz::LocalSurfaceId is being processed, this returns
- // true.
- bool IsLocalSurfaceIdAllocationSuppressed() const;
-
viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task);
- // Gets the current viz::LocalSurfaceId.
- const viz::LocalSurfaceId& GetLocalSurfaceId() const;
+ // Returns the current viz::LocalSurfaceIdAllocation.
+ const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() const;
+
+ // Marks the current viz::LocalSurfaceId as invalid. AllocateLocalSurfaceId
+ // must be called before submitting new CompositorFrames.
+ void InvalidateLocalSurfaceId();
// Sets the current viz::LocalSurfaceId, in cases where the embedded client
// has allocated one. Also sets child sequence number component of the
// viz::LocalSurfaceId allocator.
void UpdateLocalSurfaceIdFromEmbeddedClient(
- const base::Optional<viz::LocalSurfaceId>&
- embedded_client_local_surface_id);
+ const base::Optional<viz::LocalSurfaceIdAllocation>&
+ local_surface_id_allocation);
// Returns the FrameSinkId. In LOCAL mode, this returns a valid FrameSinkId
// only if a LayerTreeFrameSink has been created. In MUS mode, this always
@@ -465,6 +485,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
friend class WindowOcclusionTracker;
friend class WindowPort;
friend class WindowPortForShutdown;
+ friend class WindowPortMus;
friend class WindowTargeter;
friend class test::WindowTestApi;
@@ -482,8 +503,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// specific changes. Called from Show()/Hide().
void SetVisible(bool visible);
- // Updates the occlusion state of the window.
- void SetOcclusionState(OcclusionState occlusion_state);
+ // Updates the occlusion info of the window.
+ void SetOcclusionInfo(OcclusionState occlusion_state,
+ const SkRegion& occluded_region);
// Schedules a paint for the Window's entire bounds.
void SchedulePaint();
@@ -619,6 +641,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Occlusion state of the window.
OcclusionState occlusion_state_;
+ // Occluded region of the window.
+ SkRegion occluded_region_;
+
int id_;
// The FrameSinkId associated with this window. If this window is embedding
@@ -638,7 +663,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Makes the window pass all events through to any windows behind it.
ws::mojom::EventTargetingPolicy event_targeting_policy_;
- base::ObserverList<WindowObserver, true>::Unchecked observers_;
+ base::ObserverList<WindowObserver, true> observers_;
DISALLOW_COPY_AND_ASSIGN(Window);
};
diff --git a/chromium/ui/aura/window_delegate.h b/chromium/ui/aura/window_delegate.h
index 7911cb92df7..8107a0d3b41 100644
--- a/chromium/ui/aura/window_delegate.h
+++ b/chromium/ui/aura/window_delegate.h
@@ -86,11 +86,12 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler {
// Window::TargetVisibility() for details.
virtual void OnWindowTargetVisibilityChanged(bool visible) = 0;
- // Called when the occlusion state of the Window changes while tracked (see
- // WindowOcclusionTracker::Track). |occlusion_state| is the new occlusion
- // state of the Window.
- virtual void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) {}
+ // Called when the occlusion state or occluded region of the Window changes
+ // while tracked (see WindowOcclusionTracker::Track). |occlusion_state| is
+ // the new occlusion state of the Window. |occluded_region| is the new
+ // occluded region of the Window.
+ virtual void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) {}
// Called from Window::HitTest to check if the window has a custom hit test
// mask. It works similar to the views counterparts. That is, if the function
diff --git a/chromium/ui/aura/window_event_dispatcher.cc b/chromium/ui/aura/window_event_dispatcher.cc
index f6ea825d7e2..f22e6d1f000 100644
--- a/chromium/ui/aura/window_event_dispatcher.cc
+++ b/chromium/ui/aura/window_event_dispatcher.cc
@@ -419,9 +419,10 @@ void WindowEventDispatcher::UpdateCapture(Window* old_capture,
if (old_capture && old_capture->GetRootWindow() == window() &&
old_capture->delegate()) {
- // Send a capture changed event with bogus location data.
- ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
- gfx::Point(), ui::EventTimeForNow(), 0, 0);
+ // Send a capture changed event with the most recent mouse screen location.
+ const gfx::Point location = host_->window()->env()->last_mouse_location();
+ ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, location, location,
+ ui::EventTimeForNow(), 0, 0);
DispatchDetails details = DispatchEvent(old_capture, &event);
if (details.dispatcher_destroyed)
@@ -1079,6 +1080,8 @@ DispatchDetails WindowEventDispatcher::PreDispatchTouchEvent(
// The event is invalid - ignore it.
event->StopPropagation();
event->DisableSynchronousHandling();
+ for (auto& observer : env_->window_event_dispatcher_observers())
+ observer.OnWindowEventDispatcherIgnoredEvent(this);
return DispatchDetails();
}
@@ -1092,8 +1095,10 @@ DispatchDetails WindowEventDispatcher::PreDispatchTouchEvent(
DispatchDetails WindowEventDispatcher::PreDispatchKeyEvent(
ui::KeyEvent* event) {
if (skip_ime_ || !host_->has_input_method() ||
- (event->flags() & ui::EF_IS_SYNTHESIZED))
+ (event->flags() & ui::EF_IS_SYNTHESIZED) ||
+ !host_->ShouldSendKeyEventToIme()) {
return DispatchDetails();
+ }
DispatchDetails details = host_->GetInputMethod()->DispatchKeyEvent(event);
event->StopPropagation();
return details;
diff --git a/chromium/ui/aura/window_event_dispatcher.h b/chromium/ui/aura/window_event_dispatcher.h
index c66b2a1d2a7..1137a7b4df0 100644
--- a/chromium/ui/aura/window_event_dispatcher.h
+++ b/chromium/ui/aura/window_event_dispatcher.h
@@ -75,6 +75,8 @@ class AURA_EXPORT WindowEventDispatcher : public ui::EventProcessor,
Window* mouse_moved_handler() { return mouse_moved_handler_; }
Window* touchpad_pinch_handler() { return touchpad_pinch_handler_; }
+ WindowTargeter* event_targeter() { return event_targeter_.get(); }
+
// Overridden from ui::EventProcessor:
ui::EventTargeter* GetDefaultEventTargeter() override;
diff --git a/chromium/ui/aura/window_event_dispatcher_observer.h b/chromium/ui/aura/window_event_dispatcher_observer.h
index 88dcb60ec03..424df0d54a1 100644
--- a/chromium/ui/aura/window_event_dispatcher_observer.h
+++ b/chromium/ui/aura/window_event_dispatcher_observer.h
@@ -37,6 +37,12 @@ class AURA_EXPORT WindowEventDispatcherObserver {
virtual void OnWindowEventDispatcherDispatchedHeldEvents(
WindowEventDispatcher* dispatcher) {}
+ // Called when the WindowEventDispatcher doesn't dispatch the event because
+ // it's not appropriate at this time. For example a TouchEvent may be ignored
+ // at certain points in a gesture.
+ virtual void OnWindowEventDispatcherIgnoredEvent(
+ WindowEventDispatcher* dispatcher) {}
+
protected:
virtual ~WindowEventDispatcherObserver() {}
};
diff --git a/chromium/ui/aura/window_event_dispatcher_unittest.cc b/chromium/ui/aura/window_event_dispatcher_unittest.cc
index fc0967392b9..1e4680488c6 100644
--- a/chromium/ui/aura/window_event_dispatcher_unittest.cc
+++ b/chromium/ui/aura/window_event_dispatcher_unittest.cc
@@ -379,6 +379,9 @@ TEST_P(WindowEventDispatcherTest, CanProcessEventsWithinSubtree) {
// Prevent w3 from being deleted by the hierarchy since its delegate is owned
// by this scope.
w3->parent()->RemoveChild(w3.get());
+
+ client.GetNonLockWindow()->RemovePreTargetHandler(&nonlock_ef);
+ client.GetLockWindow()->RemovePreTargetHandler(&lock_ef);
}
TEST_P(WindowEventDispatcherTest, DontIgnoreUnknownKeys) {
@@ -692,6 +695,7 @@ TEST_P(WindowEventDispatcherTest, MAYBE(RepostTargetsCaptureWindow)) {
// Mouse moves/enters may be generated. We only care about a pressed.
EXPECT_TRUE(EventTypesToString(recorder.events()).find("MOUSE_PRESSED") !=
std::string::npos) << EventTypesToString(recorder.events());
+ window->RemovePreTargetHandler(&recorder);
}
TEST_P(WindowEventDispatcherTest, MouseMovesHeld) {
@@ -911,6 +915,9 @@ TEST_P(WindowEventDispatcherTest, MouseEventWithoutTargetWindow) {
ASSERT_EQ(2u, recorder_second.mouse_locations().size());
EXPECT_EQ(gfx::Point(2, 3).ToString(),
recorder_second.mouse_locations()[0].ToString());
+
+ window_first->RemovePreTargetHandler(&recorder_first);
+ window_second->RemovePreTargetHandler(&recorder_second);
}
// Tests that a mouse exit is dispatched to the last mouse location when
@@ -939,6 +946,7 @@ TEST_P(WindowEventDispatcherTest, DispatchMouseExitWhenHidingWindow) {
ASSERT_EQ(1u, recorder.mouse_locations().size());
EXPECT_EQ(gfx::Point(12, 23).ToString(),
recorder.mouse_locations()[0].ToString());
+ window->RemovePreTargetHandler(&recorder);
}
// Tests that a mouse-exit event is not synthesized during shutdown.
@@ -964,6 +972,7 @@ TEST_P(WindowEventDispatcherTest, NoMouseExitInShutdown) {
// Hiding the window does not generate a mouse-exit event.
window->Hide();
EXPECT_TRUE(recorder.events().empty());
+ window->RemovePreTargetHandler(&recorder);
}
// Verifies that a direct call to ProcessedTouchEvent() does not cause a crash.
@@ -1039,6 +1048,7 @@ TEST_P(WindowEventDispatcherTest, TouchMovesHeldOnScroll) {
recorder.touch_locations()[0].ToString());
EXPECT_EQ(gfx::Point(-40, 10).ToString(),
recorder.touch_locations()[1].ToString());
+ window->RemovePreTargetHandler(&handler);
root_window()->RemovePreTargetHandler(&recorder);
}
@@ -1162,6 +1172,7 @@ TEST_P(WindowEventDispatcherTest, DoNotDispatchInShutdown) {
// Event was not dispatched.
EXPECT_TRUE(recorder.events().empty());
+ window->RemovePreTargetHandler(&recorder);
}
#if defined(OS_WIN) && defined(ARCH_CPU_X86)
@@ -1253,6 +1264,7 @@ TEST_P(WindowEventDispatcherTest,
EXPECT_EQ(ui::ET_MOUSE_MOVED, recorder.events().back());
EXPECT_EQ(ui::EF_IS_SYNTHESIZED, recorder.mouse_event_flags().back());
recorder.Reset();
+ window->RemovePreTargetHandler(&recorder);
}
// Tests that a mouse exit is dispatched to the last known cursor location
@@ -1441,6 +1453,8 @@ TEST_P(WindowEventDispatcherTest, DeleteWindowDuringDispatch) {
generator.PressLeftButton();
EXPECT_FALSE(tracker.Contains(w11));
EXPECT_FALSE(d11.got_event());
+
+ w1->RemovePreTargetHandler(&w1_filter);
}
namespace {
@@ -1695,16 +1709,24 @@ class OnMouseExitDeletingEventFilter : public EventFilterRecorder {
object_to_delete_ = object_to_delete;
}
+ void set_delete_closure(base::OnceClosure delete_closure) {
+ delete_closure_ = std::move(delete_closure);
+ }
+
private:
// Overridden from ui::EventFilterRecorder.
void OnMouseEvent(ui::MouseEvent* event) override {
EventFilterRecorder::OnMouseEvent(event);
if (object_to_delete_ && event->type() == ui::ET_MOUSE_EXITED) {
+ if (delete_closure_)
+ std::move(delete_closure_).Run();
delete object_to_delete_;
object_to_delete_ = nullptr;
}
}
+ // Closure that is run prior to |object_to_delete_| being deleted.
+ base::OnceClosure delete_closure_;
T* object_to_delete_;
DISALLOW_COPY_AND_ASSIGN(OnMouseExitDeletingEventFilter);
@@ -1737,7 +1759,6 @@ TEST_P(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) {
// Set window 2 as the window that is to be deleted when a mouse-exited event
// happens on window 1.
w1_filter.set_object_to_delete(w2);
-
// Move mouse over window 2. This should generate a mouse-exited event for
// window 1 resulting in deletion of window 2. The original mouse-moved event
// that was targeted to window 2 should be dropped since window 2 is
@@ -1748,6 +1769,7 @@ TEST_P(WindowEventDispatcherTest, DeleteWindowDuringMouseMovedDispatch) {
// Check events received by window 1.
EXPECT_EQ("MOUSE_ENTERED MOUSE_MOVED MOUSE_EXITED",
EventTypesToString(w1_filter.events()));
+ w1->RemovePreTargetHandler(&w1_filter);
}
// Tests the case where the event dispatcher is deleted during the pre-dispatch
@@ -1784,6 +1806,12 @@ TEST_P(WindowEventDispatcherTest, DeleteDispatcherDuringPreDispatch) {
EventFilterRecorder w2_filter;
w2->AddPreTargetHandler(&w2_filter);
+ w1_filter.set_delete_closure(
+ base::BindLambdaForTesting([&w1_filter, &w2_filter, &w1, &w2]() {
+ w1->RemovePreTargetHandler(&w1_filter);
+ w2->RemovePreTargetHandler(&w2_filter);
+ }));
+
// Move mouse over window 2. This should generate a mouse-exited event for
// window 1 resulting in deletion of window tree host and its event
// dispatcher. The event dispatching should abort since the dispatcher is
@@ -2086,6 +2114,8 @@ TEST_P(WindowEventDispatcherTest, TouchpadPinchEventsRetargetOnCapture) {
EXPECT_EQ("GESTURE_PINCH_UPDATE GESTURE_PINCH_END",
EventTypesToString(recorder2.events()));
+ window1->RemovePreTargetHandler(&recorder1);
+ window2->RemovePreTargetHandler(&recorder2);
}
// Places two windows side by side. Presses down on one window, and starts a
@@ -2123,6 +2153,9 @@ TEST_P(WindowEventDispatcherTest, EndingEventDoesntRetarget) {
EventTypesToString(recorder1.events()));
EXPECT_TRUE(recorder2.events().empty());
+
+ window1->RemovePreTargetHandler(&recorder1);
+ window2->RemovePreTargetHandler(&recorder2);
}
namespace {
@@ -2306,6 +2339,7 @@ class WindowEventDispatcherTestWithMessageLoop
}
void TearDown() override {
+ window_->RemovePreTargetHandler(&handler_);
window_.reset();
WindowEventDispatcherTest::TearDown();
}
@@ -2428,6 +2462,7 @@ TEST_P(WindowEventDispatcherTestInHighDPI, TouchMovesHeldOnScroll) {
EXPECT_EQ(gfx::Point(-40, 10).ToString(),
recorder.touch_locations()[1].ToString());
root_window()->RemovePreTargetHandler(&recorder);
+ window->RemovePreTargetHandler(&handler);
}
// This handler triggers a nested run loop when it receives a right click
@@ -2812,6 +2847,8 @@ TEST_P(WindowEventDispatcherTest,
EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder_second.events()[0]);
EXPECT_EQ(event_location.ToString(),
recorder_second.mouse_locations()[0].ToString());
+ window_first->RemovePreTargetHandler(&recorder_first);
+ window_second->RemovePreTargetHandler(&recorder_second);
}
class AsyncWindowDelegate : public test::TestWindowDelegate {
@@ -2873,6 +2910,7 @@ TEST_P(WindowEventDispatcherTest, GestureEventCoordinates) {
EXPECT_EQ(gfx::Point(kX - kWindowOffset, kY - kWindowOffset).ToString(),
recorder.gesture_locations()[0].ToString());
root_window()->RemovePreTargetHandler(&recorder);
+ window->RemovePreTargetHandler(&handler);
}
// Tests that a scroll-generating touch-event is marked as such.
@@ -3322,7 +3360,7 @@ TEST_F(WindowEventDispatcherMusTest, RootLocationDoesntChange) {
EXPECT_EQ(root_location, event_handler.event_root_location());
EXPECT_EQ(root_location, event_handler.env_root_location());
- root_window()->RemovePreTargetHandler(&event_handler);
+ child_window->RemovePreTargetHandler(&event_handler);
}
class NestedLocationDelegate : public test::TestWindowDelegate {
diff --git a/chromium/ui/aura/window_observer.cc b/chromium/ui/aura/window_observer.cc
index 9301f4c5450..1c8a745d55a 100644
--- a/chromium/ui/aura/window_observer.cc
+++ b/chromium/ui/aura/window_observer.cc
@@ -5,27 +5,13 @@
#include "ui/aura/window_observer.h"
#include "base/logging.h"
-#include "ui/aura/window.h"
namespace aura {
-WindowObserver::WindowObserver() : observing_(0) {
-}
+WindowObserver::WindowObserver() = default;
WindowObserver::~WindowObserver() {
- CHECK_EQ(0, observing_);
-}
-
-void WindowObserver::OnObservingWindow(aura::Window* window) {
- if (!window->HasObserver(this))
- observing_++;
+ CHECK(!IsInObserverList());
}
-void WindowObserver::OnUnobservingWindow(aura::Window* window) {
- if (window->HasObserver(this))
- observing_--;
-}
-
-void WindowObserver::OnEmbeddedAppDisconnected(Window* window) {}
-
} // namespace aura
diff --git a/chromium/ui/aura/window_observer.h b/chromium/ui/aura/window_observer.h
index 65e10f924b9..1da8e5fbacf 100644
--- a/chromium/ui/aura/window_observer.h
+++ b/chromium/ui/aura/window_observer.h
@@ -5,7 +5,7 @@
#ifndef UI_AURA_WINDOW_OBSERVER_H_
#define UI_AURA_WINDOW_OBSERVER_H_
-#include "base/macros.h"
+#include "base/observer_list_types.h"
#include "base/strings/string16.h"
#include "ui/aura/aura_export.h"
#include "ui/compositor/property_change_reason.h"
@@ -19,7 +19,7 @@ namespace aura {
class Window;
-class AURA_EXPORT WindowObserver {
+class AURA_EXPORT WindowObserver : public base::CheckedObserver {
public:
struct HierarchyChangeParams {
enum HierarchyChangePhase {
@@ -148,6 +148,17 @@ class AURA_EXPORT WindowObserver {
virtual void OnWindowRemovingFromRootWindow(Window* window,
Window* new_root) {}
+ // Called from SetBoundsInScreen() when a window is moving to a new display as
+ // the result of changing bounds. |new_display_id| is the specified new
+ // display id. This is called before the bounds are actually changed.
+ virtual void OnWillMoveWindowToDisplay(Window* window,
+ int64_t new_display_id) {}
+
+ // Called from SetBoundsInScreen() when the task of the window moving to a new
+ // display finished. Sometimes the window may stay in the old display, but
+ // this will be called anyways.
+ virtual void OnDidMoveWindowToDisplay(Window* window) {}
+
// Called when the window title has changed.
virtual void OnWindowTitleChanged(Window* window) {}
@@ -161,25 +172,10 @@ class AURA_EXPORT WindowObserver {
// Called when the app embedded in |window| disconnects (is no longer
// embedded).
- virtual void OnEmbeddedAppDisconnected(Window* window);
+ virtual void OnEmbeddedAppDisconnected(Window* window) {}
protected:
- virtual ~WindowObserver();
-
- private:
- friend class Window;
-
- // Called when this is added as an observer on |window|.
- void OnObservingWindow(Window* window);
-
- // Called when this is removed from the observers on |window|.
- void OnUnobservingWindow(Window* window);
-
- // Tracks the number of windows being observed to track down
- // http://crbug.com/365364.
- int observing_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowObserver);
+ ~WindowObserver() override;
};
} // namespace aura
diff --git a/chromium/ui/aura/window_occlusion_tracker.cc b/chromium/ui/aura/window_occlusion_tracker.cc
index 16a1d228990..f7e4fbbb004 100644
--- a/chromium/ui/aura/window_occlusion_tracker.cc
+++ b/chromium/ui/aura/window_occlusion_tracker.cc
@@ -6,11 +6,13 @@
#include "base/auto_reset.h"
#include "base/containers/adapters.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/aura/env.h"
#include "ui/aura/window_tracker.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "ui/gfx/transform.h"
@@ -41,17 +43,6 @@ bool WindowOrParentHasShape(Window* window) {
return false;
}
-// Returns true if |window| opaquely fills its bounds. |window| must be visible.
-bool VisibleWindowIsOpaque(Window* window) {
- DCHECK(window->IsVisible());
- DCHECK(window->layer());
- return !window->transparent() &&
- window->layer()->type() != ui::LAYER_NOT_DRAWN &&
- window->layer()->GetCombinedOpacity() == 1.0f &&
- // For simplicity, a shaped window is not considered opaque.
- !WindowOrParentHasShape(window);
-}
-
// Returns the transform of |window| relative to its root.
// |parent_transform_relative_to_root| is the transform of |window->parent()|
// relative to its root.
@@ -96,36 +87,45 @@ SkIRect GetWindowBoundsInRootWindow(
return skirect_bounds;
}
-// Returns true iff the occlusion states in |tracked_windows| match those
-// returned by Window::occlusion_state().
-bool OcclusionStatesMatch(
- const base::flat_map<Window*, Window::OcclusionState>& tracked_windows) {
- for (const auto& tracked_window : tracked_windows) {
- if (tracked_window.second != tracked_window.first->occlusion_state())
- return false;
- }
- return true;
-}
-
} // namespace
-WindowOcclusionTracker::ScopedPause::ScopedPause(Env* env)
- : tracker_(env->GetWindowOcclusionTracker()) {
- ++tracker_->num_pause_occlusion_tracking_;
+WindowOcclusionTracker::ScopedPause::ScopedPause(Env* env) : env_(env) {
+ env_->PauseWindowOcclusionTracking();
}
WindowOcclusionTracker::ScopedPause::~ScopedPause() {
- --tracker_->num_pause_occlusion_tracking_;
- DCHECK_GE(tracker_->num_pause_occlusion_tracking_, 0);
- tracker_->MaybeComputeOcclusion();
+ env_->UnpauseWindowOcclusionTracking();
+}
+
+WindowOcclusionTracker::ScopedExclude::ScopedExclude(Window* window)
+ : window_(window) {
+ window->AddObserver(this);
+ window->env()->GetWindowOcclusionTracker()->Exclude(window_);
+}
+
+WindowOcclusionTracker::ScopedExclude::~ScopedExclude() {
+ Shutdown();
+}
+
+void WindowOcclusionTracker::ScopedExclude::OnWindowDestroying(
+ aura::Window* window) {
+ DCHECK_EQ(window_, window);
+ Shutdown();
+}
+
+void WindowOcclusionTracker::ScopedExclude::Shutdown() {
+ if (window_) {
+ window_->RemoveObserver(this);
+ window_->env()->GetWindowOcclusionTracker()->Unexclude(window_);
+ window_ = nullptr;
+ }
}
void WindowOcclusionTracker::Track(Window* window) {
DCHECK(window);
DCHECK(window != window->GetRootWindow());
- auto insert_result =
- tracked_windows_.insert({window, Window::OcclusionState::UNKNOWN});
+ auto insert_result = tracked_windows_.insert({window, {}});
DCHECK(insert_result.second);
if (!window_observer_.IsObserving(window))
window_observer_.Add(window);
@@ -137,6 +137,16 @@ WindowOcclusionTracker::WindowOcclusionTracker() = default;
WindowOcclusionTracker::~WindowOcclusionTracker() = default;
+bool WindowOcclusionTracker::OcclusionStatesMatch(
+ const base::flat_map<Window*, OcclusionData>& tracked_windows) {
+ for (const auto& tracked_window : tracked_windows) {
+ if (tracked_window.second.occlusion_state !=
+ tracked_window.first->occlusion_state())
+ return false;
+ }
+ return true;
+}
+
void WindowOcclusionTracker::MaybeComputeOcclusion() {
if (num_pause_occlusion_tracking_ ||
num_times_occlusion_recomputed_in_current_step_ != 0) {
@@ -147,7 +157,7 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
&num_times_occlusion_recomputed_in_current_step_, 0);
// Recompute occlusion states until either:
- // - They are stable, i.e. calling Window::SetOcclusionState() on all tracked
+ // - They are stable, i.e. calling Window::SetOcclusionInfo() on all tracked
// windows does not provoke changes that could affect occlusion.
// - Occlusion states have been recomputed
// |kMaxComputeOcclusionIterationsBeforeStable|
@@ -164,7 +174,7 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
bool found_dirty_root = false;
// Compute occlusion states and store them in |tracked_windows_|. Do not
- // call Window::SetOcclusionState() in this phase to prevent changes to the
+ // call Window::SetOcclusionInfo() in this phase to prevent changes to the
// window tree while it is being traversed.
for (auto& root_window_pair : root_windows_) {
if (root_window_pair.second.dirty) {
@@ -184,7 +194,7 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
++num_times_occlusion_recomputed_;
++num_times_occlusion_recomputed_in_current_step_;
- // Call Window::SetOcclusionState() on tracked windows. A WindowDelegate may
+ // Call Window::SetOcclusionInfo() on tracked windows. A WindowDelegate may
// change the window tree in response to this.
WindowTracker tracked_windows_list;
for (const auto& tracked_window : tracked_windows_)
@@ -194,15 +204,20 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
Window* window = tracked_windows_list.Pop();
auto it = tracked_windows_.find(window);
if (it != tracked_windows_.end() &&
- it->second != Window::OcclusionState::UNKNOWN) {
+ it->second.occlusion_state != Window::OcclusionState::UNKNOWN) {
// Fallback to VISIBLE/HIDDEN if the maximum number of times that
// occlusion can be recomputed was exceeded.
if (exceeded_max_num_times_occlusion_recomputed) {
- it->second = window->IsVisible() ? Window::OcclusionState::VISIBLE
- : Window::OcclusionState::HIDDEN;
+ if (window->IsVisible()) {
+ it->second.occlusion_state = Window::OcclusionState::VISIBLE;
+ } else {
+ it->second.occlusion_state = Window::OcclusionState::HIDDEN;
+ }
+ it->second.occluded_region = SkRegion();
}
- window->SetOcclusionState(it->second);
+ window->SetOcclusionInfo(it->second.occlusion_state,
+ it->second.occluded_region);
}
}
}
@@ -224,7 +239,7 @@ bool WindowOcclusionTracker::RecomputeOcclusionImpl(
return false;
}
- if (WindowIsAnimated(window)) {
+ if (WindowIsAnimated(window) || WindowIsExcluded(window)) {
SetWindowAndDescendantsAreOccluded(window, false);
return true;
}
@@ -246,33 +261,53 @@ bool WindowOcclusionTracker::RecomputeOcclusionImpl(
const SkIRect* clipped_bounds_for_children =
window->layer()->GetMasksToBounds() ? &window_bounds : clipped_bounds;
bool has_visible_child = false;
+ SkRegion occluded_region_before_traversing_children = *occluded_region;
for (auto* child : base::Reversed(window->children())) {
has_visible_child |=
RecomputeOcclusionImpl(child, transform_relative_to_root,
clipped_bounds_for_children, occluded_region);
}
- // Compute window occlusion state.
- if (occluded_region->contains(window_bounds)) {
- SetOccluded(window, !has_visible_child);
- return has_visible_child;
+ // Window is fully occluded.
+ if (occluded_region->contains(window_bounds) && !has_visible_child) {
+ SetOccluded(window, true, SkRegion());
+ return false;
}
- SetOccluded(window, false);
+ // Window is partially occluded or unoccluded.
+ SetOccluded(window, false, occluded_region_before_traversing_children);
+
if (VisibleWindowIsOpaque(window))
occluded_region->op(window_bounds, SkRegion::kUnion_Op);
return true;
}
+bool WindowOcclusionTracker::VisibleWindowIsOpaque(Window* window) const {
+ DCHECK(window->IsVisible());
+ DCHECK(window->layer());
+ return !window->transparent() && WindowHasContent(window) &&
+ window->layer()->GetCombinedOpacity() == 1.0f &&
+ // For simplicity, a shaped window is not considered opaque.
+ !WindowOrParentHasShape(window);
+}
+
+bool WindowOcclusionTracker::WindowHasContent(Window* window) const {
+ if (window->layer()->type() != ui::LAYER_NOT_DRAWN)
+ return true;
+
+ if (window_has_content_callback_)
+ return window_has_content_callback_.Run(window);
+
+ return false;
+}
+
void WindowOcclusionTracker::CleanupAnimatedWindows() {
base::EraseIf(animated_windows_, [=](Window* window) {
ui::LayerAnimator* const animator = window->layer()->GetAnimator();
if (animator->IsAnimatingOnePropertyOf(kSkipWindowWhenPropertiesAnimated))
return false;
animator->RemoveObserver(this);
- auto root_window_state_it = root_windows_.find(window->GetRootWindow());
- if (root_window_state_it != root_windows_.end())
- MarkRootWindowAsDirty(&root_window_state_it->second);
+ MarkRootWindowAsDirty(window->GetRootWindow());
return true;
});
}
@@ -298,22 +333,31 @@ bool WindowOcclusionTracker::MaybeObserveAnimatedWindow(Window* window) {
void WindowOcclusionTracker::SetWindowAndDescendantsAreOccluded(
Window* window,
bool is_occluded) {
- SetOccluded(window, is_occluded);
+ SetOccluded(window, is_occluded, SkRegion());
for (Window* child_window : window->children())
SetWindowAndDescendantsAreOccluded(child_window, is_occluded);
}
-void WindowOcclusionTracker::SetOccluded(Window* window, bool is_occluded) {
+void WindowOcclusionTracker::SetOccluded(Window* window,
+ bool is_occluded,
+ const SkRegion& occluded_region) {
auto tracked_window = tracked_windows_.find(window);
if (tracked_window == tracked_windows_.end())
return;
+ // Set the occluded region of the window.
+ tracked_window->second.occluded_region = occluded_region;
+
if (!window->IsVisible())
- tracked_window->second = Window::OcclusionState::HIDDEN;
+ tracked_window->second.occlusion_state = Window::OcclusionState::HIDDEN;
else if (is_occluded)
- tracked_window->second = Window::OcclusionState::OCCLUDED;
+ tracked_window->second.occlusion_state = Window::OcclusionState::OCCLUDED;
else
- tracked_window->second = Window::OcclusionState::VISIBLE;
+ tracked_window->second.occlusion_state = Window::OcclusionState::VISIBLE;
+
+ DCHECK(tracked_window->second.occlusion_state ==
+ Window::OcclusionState::VISIBLE ||
+ tracked_window->second.occluded_region.isEmpty());
}
bool WindowOcclusionTracker::WindowIsTracked(Window* window) const {
@@ -324,6 +368,10 @@ bool WindowOcclusionTracker::WindowIsAnimated(Window* window) const {
return base::ContainsKey(animated_windows_, window);
}
+bool WindowOcclusionTracker::WindowIsExcluded(Window* window) const {
+ return base::ContainsKey(excluded_windows_, window);
+}
+
template <typename Predicate>
void WindowOcclusionTracker::MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(
Window* window,
@@ -345,12 +393,12 @@ void WindowOcclusionTracker::MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(
if (root_window_state_it->second.dirty)
return;
if (predicate()) {
- MarkRootWindowAsDirty(&root_window_state_it->second);
+ MarkRootWindowStateAsDirty(&root_window_state_it->second);
MaybeComputeOcclusion();
}
}
-void WindowOcclusionTracker::MarkRootWindowAsDirty(
+void WindowOcclusionTracker::MarkRootWindowStateAsDirty(
RootWindowState* root_window_state) {
// If a root window is marked as dirty and occlusion states have already been
// recomputed |kMaxRecomputeOcclusion| times, it means that they are not
@@ -361,6 +409,14 @@ void WindowOcclusionTracker::MarkRootWindowAsDirty(
root_window_state->dirty = true;
}
+bool WindowOcclusionTracker::MarkRootWindowAsDirty(aura::Window* root_window) {
+ auto root_window_state_it = root_windows_.find(root_window);
+ if (root_window_state_it == root_windows_.end())
+ return false;
+ MarkRootWindowStateAsDirty(&root_window_state_it->second);
+ return true;
+}
+
bool WindowOcclusionTracker::WindowOrParentIsAnimated(Window* window) const {
while (window && !WindowIsAnimated(window))
window = window->parent();
@@ -395,7 +451,7 @@ bool WindowOcclusionTracker::WindowOrDescendantIsOpaque(
WindowIsAnimated(window)) {
return false;
}
- if (!window->transparent() && window->layer()->type() != ui::LAYER_NOT_DRAWN)
+ if (!window->transparent() && WindowHasContent(window))
return true;
for (Window* child_window : window->children()) {
if (WindowOrDescendantIsOpaque(child_window, true))
@@ -409,13 +465,15 @@ bool WindowOcclusionTracker::WindowOpacityChangeMayAffectOcclusionStates(
// Changing the opacity of a window has no effect on the occlusion state of
// the window or its children. It can however affect the occlusion state of
// other windows in the tree if it is visible and not animated (animated
- // windows aren't considered in occlusion computations).
- return window->IsVisible() && !WindowOrParentIsAnimated(window);
+ // windows aren't considered in occlusion computations), unless it is
+ // excluded.
+ return window->IsVisible() && !WindowOrParentIsAnimated(window) &&
+ !WindowIsExcluded(window);
}
bool WindowOcclusionTracker::WindowMoveMayAffectOcclusionStates(
Window* window) const {
- return !WindowOrParentIsAnimated(window) &&
+ return !WindowOrParentIsAnimated(window) && !WindowIsExcluded(window) &&
(WindowOrDescendantIsOpaque(window) ||
WindowOrDescendantIsTrackedAndVisible(window));
}
@@ -425,9 +483,18 @@ void WindowOcclusionTracker::TrackedWindowAddedToRoot(Window* window) {
DCHECK(root_window);
RootWindowState& root_window_state = root_windows_[root_window];
++root_window_state.num_tracked_windows;
- if (root_window_state.num_tracked_windows == 1)
+ MarkRootWindowStateAsDirty(&root_window_state);
+
+ // It's only useful to track the host if |window| is the first tracked window
+ // under |root_window|. All windows under the same root have the same host.
+ if (root_window_state.num_tracked_windows == 1) {
AddObserverToWindowAndDescendants(root_window);
- MarkRootWindowAsDirty(&root_window_state);
+ auto* host = root_window->GetHost();
+ if (host) {
+ host->AddObserver(this);
+ host->EnableNativeWindowOcclusionTracking();
+ }
+ }
MaybeComputeOcclusion();
}
@@ -440,6 +507,8 @@ void WindowOcclusionTracker::TrackedWindowRemovedFromRoot(Window* window) {
if (root_window_state_it->second.num_tracked_windows == 0) {
RemoveObserverFromWindowAndDescendants(root_window);
root_windows_.erase(root_window_state_it);
+ root_window->GetHost()->RemoveObserver(this);
+ root_window->GetHost()->DisableNativeWindowOcclusionTracking();
}
}
@@ -468,6 +537,37 @@ void WindowOcclusionTracker::AddObserverToWindowAndDescendants(Window* window) {
AddObserverToWindowAndDescendants(child_window);
}
+void WindowOcclusionTracker::Pause() {
+ ++num_pause_occlusion_tracking_;
+}
+
+void WindowOcclusionTracker::Unpause() {
+ --num_pause_occlusion_tracking_;
+ DCHECK_GE(num_pause_occlusion_tracking_, 0);
+ MaybeComputeOcclusion();
+}
+
+void WindowOcclusionTracker::Exclude(Window* window) {
+ // If threre is a valid use case to exclude the same window twice
+ // (e.g. independent clients may try to exclude the same window),
+ // introduce the count.
+ DCHECK(!WindowIsExcluded(window));
+ excluded_windows_.insert(window);
+ if (window->IsVisible()) {
+ if (MarkRootWindowAsDirty(window->GetRootWindow()))
+ MaybeComputeOcclusion();
+ }
+}
+
+void WindowOcclusionTracker::Unexclude(Window* window) {
+ DCHECK(WindowIsExcluded(window));
+ excluded_windows_.erase(window);
+ if (window->IsVisible()) {
+ if (MarkRootWindowAsDirty(window->GetRootWindow()))
+ MaybeComputeOcclusion();
+ }
+}
+
void WindowOcclusionTracker::OnLayerAnimationEnded(
ui::LayerAnimationSequence* sequence) {
CleanupAnimatedWindows();
@@ -609,11 +709,14 @@ void WindowOcclusionTracker::OnWindowLayerRecreated(Window* window) {
return;
animator->RemoveObserver(this);
- auto root_window_state_it = root_windows_.find(window->GetRootWindow());
- if (root_window_state_it != root_windows_.end()) {
- MarkRootWindowAsDirty(&root_window_state_it->second);
+ if (MarkRootWindowAsDirty(window->GetRootWindow()))
MaybeComputeOcclusion();
- }
+}
+
+void WindowOcclusionTracker::OnOcclusionStateChanged(
+ WindowTreeHost* host,
+ aura::Window::OcclusionState new_state) {
+ UMA_HISTOGRAM_ENUMERATION("WindowOcclusionChanged", new_state);
}
} // namespace aura
diff --git a/chromium/ui/aura/window_occlusion_tracker.h b/chromium/ui/aura/window_occlusion_tracker.h
index 2b546a5a8b6..6258792f8f0 100644
--- a/chromium/ui/aura/window_occlusion_tracker.h
+++ b/chromium/ui/aura/window_occlusion_tracker.h
@@ -6,7 +6,9 @@
#define UI_AURA_WINDOW_OCCLUSION_TRACKER_H_
#include <memory>
+#include <utility>
+#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
@@ -14,6 +16,7 @@
#include "ui/aura/aura_export.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
+#include "ui/aura/window_tree_host_observer.h"
#include "ui/compositor/layer_animation_observer.h"
struct SkIRect;
@@ -44,25 +47,59 @@ class Env;
// Note that an occluded window may be drawn on the screen by window switching
// features such as "Alt-Tab" or "Overview".
class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
- public WindowObserver {
+ public WindowObserver,
+ public WindowTreeHostObserver {
public:
// Prevents window occlusion state computations within its scope. If an event
// that could cause window occlusion states to change occurs within the scope
// of a ScopedPause, window occlusion state computations are delayed until all
// ScopedPause objects have been destroyed.
+ // TODO(crbug.com/867150): Pause the tracker in Window Service under mus.
class AURA_EXPORT ScopedPause {
public:
explicit ScopedPause(Env* env);
~ScopedPause();
private:
- WindowOcclusionTracker* const tracker_;
+ Env* const env_;
DISALLOW_COPY_AND_ASSIGN(ScopedPause);
};
+ // Exclude the window from occlusion tracking so that a window behind the
+ // given window is still considered visible. The excluded window itself and
+ // its descendant windows, if tracked, are considered visible. This is useful
+ // for a window being dragged or resized to avoid unnecessary occlusion state
+ // change triggered by these operation, because the window bounds are
+ // temporary until it is finished.
+ // Note that this is intended to be used by window manager and not by mus
+ // client process.
+ class AURA_EXPORT ScopedExclude : public aura::WindowObserver {
+ public:
+ explicit ScopedExclude(Window* window);
+ ~ScopedExclude() override;
+
+ Window* window() { return window_; }
+
+ private:
+ // aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override;
+
+ void Shutdown();
+
+ Window* window_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedExclude);
+ };
+
// Start tracking the occlusion state of |window|.
void Track(Window* window);
+ // Set a callback to determine whether a window has content to draw in
+ // addition to layer type check (window layer type != ui::LAYER_NOT_DRAWN).
+ using WindowHasContentCallback = base::RepeatingCallback<bool(const Window*)>;
+ void set_window_has_content_callback(WindowHasContentCallback callback) {
+ window_has_content_callback_ = std::move(callback);
+ }
+
private:
friend class test::WindowOcclusionTrackerTestApi;
friend class Env;
@@ -77,9 +114,22 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
bool dirty = false;
};
+ // Holds occlusion related information for tracked windows.
+ struct OcclusionData {
+ // Occlusion state for a tracked window.
+ Window::OcclusionState occlusion_state = Window::OcclusionState::UNKNOWN;
+ // Region in root window coordinates that is occluded.
+ SkRegion occluded_region;
+ };
+
WindowOcclusionTracker();
~WindowOcclusionTracker() override;
+ // Returns true iff the occlusion states in |tracked_windows| match those
+ // returned by Window::occlusion_state().
+ static bool OcclusionStatesMatch(
+ const base::flat_map<Window*, OcclusionData>& tracked_windows);
+
// Recomputes the occlusion state of tracked windows under roots marked as
// dirty in |root_windows_| if there are no active ScopedPause instance.
void MaybeComputeOcclusion();
@@ -96,6 +146,13 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
const SkIRect* clipped_bounds,
SkRegion* occluded_region);
+ // Returns true if |window| opaquely fills its bounds. |window| must be
+ // visible.
+ bool VisibleWindowIsOpaque(Window* window) const;
+
+ // Returns true if |window| has content.
+ bool WindowHasContent(Window* window) const;
+
// Removes windows whose bounds and transform are not animated from
// |animated_windows_|. Marks the root of those windows as dirty.
void CleanupAnimatedWindows();
@@ -109,9 +166,12 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
void SetWindowAndDescendantsAreOccluded(Window* window, bool is_occluded);
// Updates the occlusion state of |window| in |tracked_windows_|, based on
- // |is_occluded| and window->IsVisible(). No-op if |window| is not in
+ // |is_occluded| and window->IsVisible(). Updates the occluded region of
+ // |window| using |occluded_region|. No-op if |window| is not in
// |tracked_windows_|.
- void SetOccluded(Window* window, bool is_occluded);
+ void SetOccluded(Window* window,
+ bool is_occluded,
+ const SkRegion& occluded_region);
// Returns true if |window| is in |tracked_windows_|.
bool WindowIsTracked(Window* window) const;
@@ -119,6 +179,9 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// Returns true if |window| is in |animated_windows_|.
bool WindowIsAnimated(Window* window) const;
+ // Returns true if |window| is in |excluded_windows_|.
+ bool WindowIsExcluded(Window* window) const;
+
// If the root of |window| is not dirty and |predicate| is true, marks the
// root of |window| as dirty. Then, calls MaybeComputeOcclusion().
// |predicate| is not evaluated if the root of |window| is already dirty when
@@ -127,8 +190,12 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
void MarkRootWindowAsDirtyAndMaybeComputeOcclusionIf(Window* window,
Predicate predicate);
- // Marks |root_window| as dirty.
- void MarkRootWindowAsDirty(RootWindowState* root_window_state);
+ // Marks |root_window_state| as dirty.
+ void MarkRootWindowStateAsDirty(RootWindowState* root_window_state);
+
+ // Marks |root_window| as dirty. Returns false if none of the descendent
+ // windows in |root_window| are tracked.
+ bool MarkRootWindowAsDirty(aura::Window* root_window);
// Returns true if |window| or one of its parents is in |animated_windows_|.
bool WindowOrParentIsAnimated(Window* window) const;
@@ -167,6 +234,15 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// Add |this| to the observer list of |window| and its descendants.
void AddObserverToWindowAndDescendants(Window* window);
+ // Pauses/unpauses the occlusion state computation.
+ void Pause();
+ void Unpause();
+
+ // Exclucde/Unexclude a window from occlusion tracking. See comment on
+ // ScopedExclude.
+ void Exclude(Window* window);
+ void Unexclude(Window* window);
+
// ui::LayerAnimationObserver:
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
@@ -193,8 +269,11 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
Window* new_root) override;
void OnWindowLayerRecreated(Window* window) override;
- // Windows whose occlusion state is tracked.
- base::flat_map<Window*, Window::OcclusionState> tracked_windows_;
+ // Windows whose occlusion data is tracked.
+ base::flat_map<Window*, OcclusionData> tracked_windows_;
+ // WindowTreeHostObserver
+ void OnOcclusionStateChanged(WindowTreeHost* host,
+ Window::OcclusionState new_state) override;
// Windows whose bounds or transform are animated.
//
@@ -205,6 +284,10 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// aborted.
base::flat_set<Window*> animated_windows_;
+ // Windows that are excluded from occlustion tracking. See comment on
+ // ScopedExclude.
+ base::flat_set<Window*> excluded_windows_;
+
// Root Windows of Windows in |tracked_windows_|.
base::flat_map<Window*, RootWindowState> root_windows_;
@@ -222,6 +305,9 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
// Tracks the observed windows.
ScopedObserver<Window, WindowObserver> window_observer_{this};
+ // Callback to be invoked for additional window has content check.
+ WindowHasContentCallback window_has_content_callback_;
+
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionTracker);
};
diff --git a/chromium/ui/aura/window_occlusion_tracker_unittest.cc b/chromium/ui/aura/window_occlusion_tracker_unittest.cc
index ee9247f9d99..2910be974fd 100644
--- a/chromium/ui/aura/window_occlusion_tracker_unittest.cc
+++ b/chromium/ui/aura/window_occlusion_tracker_unittest.cc
@@ -4,13 +4,14 @@
#include "ui/aura/window_occlusion_tracker.h"
+#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
#include "base/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/env.h"
#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/env_test_helper.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/test/window_occlusion_tracker_test_api.h"
@@ -36,24 +37,33 @@ class MockWindowDelegate : public test::ColorTestWindowDelegate {
void set_window(Window* window) { window_ = window; }
- void set_expectation(Window::OcclusionState expectation) {
- expectation_ = expectation;
+ void SetName(const std::string& name) { window_->SetName(name); }
+
+ void set_expectation(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) {
+ expected_occlusion_state_ = occlusion_state;
+ expected_occluded_region_ = occluded_region;
}
bool is_expecting_call() const {
- return expectation_ != Window::OcclusionState::UNKNOWN;
+ return expected_occlusion_state_ != Window::OcclusionState::UNKNOWN;
}
- void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) override {
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ SCOPED_TRACE(window_->GetName());
ASSERT_TRUE(window_);
EXPECT_NE(occlusion_state, Window::OcclusionState::UNKNOWN);
- EXPECT_EQ(occlusion_state, expectation_);
- expectation_ = Window::OcclusionState::UNKNOWN;
+ EXPECT_EQ(occlusion_state, expected_occlusion_state_);
+ EXPECT_EQ(occluded_region, expected_occluded_region_);
+ expected_occlusion_state_ = Window::OcclusionState::UNKNOWN;
+ expected_occluded_region_ = SkRegion();
}
private:
- Window::OcclusionState expectation_ = Window::OcclusionState::UNKNOWN;
+ Window::OcclusionState expected_occlusion_state_ =
+ Window::OcclusionState::UNKNOWN;
+ SkRegion expected_occluded_region_ = SkRegion();
Window* window_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(MockWindowDelegate);
@@ -88,11 +98,15 @@ class WindowOcclusionTrackerTest : public test::AuraTestBase {
}
private:
- test::EnvTestHelper env_test_helper_;
-
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionTrackerTest);
};
+SkRegion SkRegionFromSkIRects(std::initializer_list<SkIRect> rects) {
+ SkRegion r;
+ r.setRects(rects.begin(), rects.size());
+ return r;
+}
+
} // namespace
// Verify that non-overlapping windows have a VISIBLE occlusion state.
@@ -101,13 +115,16 @@ class WindowOcclusionTrackerTest : public test::AuraTestBase {
// |____| |____|
TEST_F(WindowOcclusionTrackerTest, NonOverlappingWindows) {
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(15, 0, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(15, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
}
@@ -117,13 +134,16 @@ TEST_F(WindowOcclusionTrackerTest, NonOverlappingWindows) {
// |_____|
TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) {
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeWH(5, 5)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
}
@@ -136,31 +156,31 @@ TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) {
TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded and expect window a to be
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 15, 15));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Hide window b. Expect window a to be non-occluded and window b to be
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
- delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Show window b. Expect window a to be occluded and window b to be non-
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->Show();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -175,15 +195,15 @@ TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) {
TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded and expect window a to be
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 15, 15));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -191,13 +211,13 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) {
// Change the opacity of window b to 0.5f. Expect both windows to be non-
// occluded.
EXPECT_FALSE(delegate_a->is_expecting_call());
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetOpacity(0.5f);
EXPECT_FALSE(delegate_a->is_expecting_call());
// Change the opacity of window b back to 1.0f. Expect window a to be
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetOpacity(1.0f);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -207,24 +227,24 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) {
TEST_F(WindowOcclusionTrackerTest, SemiTransparentUntrackedWindowCoversWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create untracked window b. Expect window a to be occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 15, 15));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Change the opacity of window b to 0.5f. Expect both windows to be non-
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetOpacity(0.5f);
EXPECT_FALSE(delegate_a->is_expecting_call());
// Change the opacity of window b back to 1.0f. Expect window a to be
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetOpacity(1.0f);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -237,25 +257,31 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentUntrackedWindowCoversWindow) {
TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b with bounds that partially cover window a. Expect both
// windows to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeWH(5, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c with bounds that cover the portion of window a that isn't
// already covered by window b. Expect window a to be occluded and window a/b
// to be non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(5, 0, 5, 10)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(5, 0, 5, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
}
@@ -264,23 +290,23 @@ TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) {
TEST_F(WindowOcclusionTrackerTest, SiblingOccludesWindowAndChild) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, with bounds that occlude half of its parent window a.
// Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c, with bounds that occlude window a and window b. Expect it
// to be non-occluded, and window a and b to be occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -292,23 +318,28 @@ TEST_F(WindowOcclusionTrackerTest, SiblingOccludesWindowAndChild) {
TEST_F(WindowOcclusionTrackerTest, ChildAndSiblingOccludeOneWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, with bounds that occlude half of its parent window a.
// Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c, with bounds that occlude the other half of window a.
// Expect it to be non-occluded and expect window a to remain non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 20)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 20)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
}
@@ -316,22 +347,26 @@ TEST_F(WindowOcclusionTrackerTest, ChildAndSiblingOccludeOneWindow) {
TEST_F(WindowOcclusionTrackerTest, ChildrenOccludeOneWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, with bounds that cover half of its parent window a. Expect
// it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a);
- EXPECT_FALSE(delegate_b->is_expecting_call());
+ EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window c, with bounds that cover the other half of its parent window
// a. Expect it to be non-occluded. Expect window a to remain non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 20)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 20), window_a);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
}
@@ -340,27 +375,35 @@ TEST_F(WindowOcclusionTrackerTest, ChildrenOccludeOneWindow) {
TEST_F(WindowOcclusionTrackerTest, ChildDoesNotOccludeParent) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b with window a as parent. The bounds of window b fully cover
// window a. Expect both windows to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b =
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c whose bounds don't overlap existing windows.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(15, 0, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(15, 0, 10, 10)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(15, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Change the parent of window b from window a to window c. Expect all windows
// to remain non-occluded.
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_c->AddChild(window_b);
+ EXPECT_FALSE(delegate_b->is_expecting_call());
}
// Verify that when the stacking order of windows change, occlusion states are
@@ -369,28 +412,28 @@ TEST_F(WindowOcclusionTrackerTest, StackingChanged) {
// Create three windows that have the same bounds. Expect window on top of the
// stack to be non-occluded and other windows to be occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Move window a on top of the stack. Expect it to be non-occluded and expect
// window c to be occluded.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
- delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -403,7 +446,7 @@ TEST_F(WindowOcclusionTrackerTest, StackingChanged) {
TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Create window a which is transparent. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_a->is_expecting_call());
@@ -411,14 +454,14 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Create window b which has the same bounds as its parent window a. Expect it
// to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c which is transparent and has the same bounds as window a
// and window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -426,9 +469,9 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Create window d which has the same bounds as its parent window c. Expect
// window d to be non-occluded and window a and b to be occluded.
MockWindowDelegate* delegate_d = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_d, gfx::Rect(0, 0, 10, 10), window_c);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -436,10 +479,10 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Move window a on top of the stack. Expect window a and b to be non-occluded
// and window c and d to be occluded.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
- delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_d->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_d->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -454,12 +497,12 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) {
// Create window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_b->is_expecting_call());
// Stack window a on top of window b. Expect window b to be occluded.
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
}
@@ -468,17 +511,20 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) {
TEST_F(WindowOcclusionTrackerTest, BoundsChanged) {
// Create two non-overlapping windows. Expect them to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Move window b on top of window a. Expect window a to be occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->SetBounds(window_a->bounds());
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -499,26 +545,29 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(test_controller.animator());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Start animating the bounds of window b so that it moves on top of window a.
// Window b should be non-occluded when the animation starts.
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->SetBounds(window_a->bounds());
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -527,9 +576,13 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window b should occlude window a at the end of the animation.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ // Window b should have window c in its potential occlusion region.
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(nullptr);
}
@@ -546,18 +599,21 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -565,7 +621,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
// Start animating the bounds of window c so that it moves on top of window a.
// Window b should be non-occluded when the animation starts.
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_c->SetBounds(window_a->bounds());
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -574,9 +630,13 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window c should occlude window a at the end of the animation.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ // Window b should have a potentially occluded region including window c.
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 0, 10, 10)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
window_c->layer()->SetAnimator(nullptr);
}
@@ -586,14 +646,14 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which doesn't overlap window a and is transparent. Expect
// it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -601,13 +661,16 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {
// Create window c which has window b as parent and doesn't occlude any
// window.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Move window b so that window c occludes window a. Expect window a to be
// occluded and other windows to be non-occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->SetBounds(gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -617,15 +680,18 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. It should not occlude window a.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 10, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
// Move window b on top of window a. Expect window a to be occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->SetBounds(window_a->bounds());
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -635,18 +701,21 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) {
TEST_F(WindowOcclusionTrackerTest, TransformChanged) {
// Create two non-overlapping windows. Expect them to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Scale and translate window b so that it covers window a. Expect window a to
// be occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
gfx::Transform transform;
transform.Translate(0.0f, -10.0f);
transform.Scale(2.0f, 2.0f);
@@ -670,26 +739,29 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(test_controller.animator());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Start animating the transform of window b so that it moves on top of window
// a. Window b should be non-occluded when the animation starts.
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
auto transform = std::make_unique<ui::InterpolatedScale>(
gfx::Point3F(1, 1, 1), gfx::Point3F(2.0f, 2.0f, 1));
transform->SetChild(std::make_unique<ui::InterpolatedTranslation>(
@@ -704,9 +776,13 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window b should occlude window a at the end of the animation.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ // Window b should see window c as part of the potential occlusion region.
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(nullptr);
}
@@ -723,18 +799,21 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 20, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 20, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 20, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -742,7 +821,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
// Start animating the bounds of window c so that it moves on top of window a.
// Window b should be non-occluded when the animation starts.
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
auto transform = std::make_unique<ui::InterpolatedScale>(
gfx::Point3F(1, 1, 1), gfx::Point3F(2.0f, 2.0f, 1));
transform->SetChild(std::make_unique<ui::InterpolatedTranslation>(
@@ -757,9 +836,13 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window c should occlude window a at the end of the animation.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ // Window b should now see window c in the potential occlusion region.
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeWH(20, 20)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
window_c->layer()->SetAnimator(nullptr);
}
@@ -769,14 +852,14 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which doesn't overlap window a and is transparent. Expect
// it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -784,13 +867,16 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {
// Create window c which has window b as parent and doesn't occlude any
// window.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Scale and translate window b so that window c occludes window a. Expect
// window a to be occluded and other windows to be non-occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
gfx::Transform transform;
transform.Translate(0.0f, -10.0f);
transform.Scale(2.0f, 2.0f);
@@ -803,16 +889,19 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. It should not occlude window a.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 10, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
// Scale and translate window b so that it occludes window a. Expect window a
// to be occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
gfx::Transform transform;
transform.Translate(0.0f, -10.0f);
transform.Scale(2.0f, 2.0f);
@@ -825,17 +914,17 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) {
TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which occludes window a.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Delete window b. Expect a to be non-occluded.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delete window_b;
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -845,22 +934,59 @@ TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) {
TEST_F(WindowOcclusionTrackerTest, RemoveUntrackedWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which occludes window a.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Delete window b. Expect a to be non-occluded.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
root_window()->RemoveChild(window_b);
EXPECT_FALSE(delegate_a->is_expecting_call());
delete window_b;
}
+// Verify that occlusion tracking with customized WindowHasContent callback.
+TEST_F(WindowOcclusionTrackerTest, CustomizedWindowHasContent) {
+ // Create window a. Expect it to be non-occluded.
+ MockWindowDelegate* delegate_a = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Create window b with layer type LAYER_NOT_DRAWN. Occlusion state of a is
+ // not changed.
+ MockWindowDelegate* delegate_b = new MockWindowDelegate();
+ Window* window_b = new Window(delegate_b);
+ delegate_b->set_window(window_b);
+ window_b->Init(ui::LAYER_NOT_DRAWN);
+ window_b->SetBounds(gfx::Rect(0, 0, 10, 10));
+ root_window()->AddChild(window_b);
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
+ window_b->TrackOcclusionState();
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+
+ // Use customized WindowHasContent callback to mark b as opaque.
+ window_b->env()->GetWindowOcclusionTracker()->set_window_has_content_callback(
+ base::BindLambdaForTesting([window_b](const Window* window) -> bool {
+ return window == window_b;
+ }));
+
+ // Show window b to trigger a occlusion compute and window a is occluded.
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ window_b->Show();
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+
+ window_b->env()->GetWindowOcclusionTracker()->set_window_has_content_callback(
+ base::NullCallback());
+}
+
// Verify that when a tracked window is removed and re-added to a root,
// occlusion states are still tracked.
TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) {
@@ -869,7 +995,7 @@ TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) {
// Create window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -881,19 +1007,20 @@ TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) {
// Create untracked window d which covers window a. Expect window a to be
// occluded.
- delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_d = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_c->is_expecting_call());
// Move window d so that it doesn't cover window c.
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
window_d->SetBounds(gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_c->is_expecting_call());
// Stack window a on top of window c. Expect window c to be non-occluded. This
// won't work if WindowOcclusionTracked didn't register as an observer of
// window a when window c was made a child of root_window().
- delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_c->is_expecting_call());
}
@@ -916,7 +1043,6 @@ class ResizeWindowObserver : public WindowObserver {
Window* const window_to_resize_;
DISALLOW_COPY_AND_ASSIGN(ResizeWindowObserver);
- ;
};
} // namespace
@@ -926,14 +1052,14 @@ class ResizeWindowObserver : public WindowObserver {
TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded and to occlude window a.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -941,7 +1067,7 @@ TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {
// Create window c, which is a child of window b. Expect it to be non-
// occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c =
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b);
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -962,15 +1088,18 @@ TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {
TEST_F(WindowOcclusionTrackerTest, ScopedPause) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
- // Create window b which doesn't overlap window a. Expect it to be non-
+ // Create window b which doesn't overlap window a. Expect it to be non
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Change bounds multiple times. At the end of the scope, expect window a to
@@ -982,7 +1111,7 @@ TEST_F(WindowOcclusionTrackerTest, ScopedPause) {
window_a->SetBounds(gfx::Rect(0, 10, 5, 5));
window_b->SetBounds(window_a->bounds());
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
}
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -991,15 +1120,17 @@ TEST_F(WindowOcclusionTrackerTest, ScopedPause) {
TEST_F(WindowOcclusionTrackerTest, NestedScopedPause) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
-
// Create window b which doesn't overlap window a. Expect it to be non-
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Change bounds multiple times. At the end of the scope, expect window a to
@@ -1024,7 +1155,7 @@ TEST_F(WindowOcclusionTrackerTest, NestedScopedPause) {
window_b->SetBounds(window_a->bounds());
}
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
}
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -1044,17 +1175,19 @@ TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) {
// Effective bounds: x = 34, y = 36, height = 8, width = 10
CreateUntrackedWindow(gfx::Rect(15, 16, 4, 5), window_b);
-
MockWindowDelegate* delegate_d = new MockWindowDelegate();
- delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(34, 36, 8, 10));
EXPECT_FALSE(delegate_d->is_expecting_call());
- delegate_d->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_d->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtBottom(window_d);
EXPECT_FALSE(delegate_d->is_expecting_call());
- delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
+ SkRegion occluded_area = SkRegionFromSkIRects(
+ {SkIRect::MakeXYWH(2, 2, 10, 10), SkIRect::MakeXYWH(4, 4, 4, 4),
+ SkIRect::MakeXYWH(34, 36, 8, 10)});
+ delegate_d->set_expectation(Window::OcclusionState::VISIBLE, occluded_area);
window_d->SetBounds(gfx::Rect(35, 36, 8, 10));
EXPECT_FALSE(delegate_d->is_expecting_call());
@@ -1068,21 +1201,23 @@ TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) {
TEST_F(WindowOcclusionTrackerTest, Clipping) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeWH(5, 5)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetMasksToBounds(true);
-
// Create window c which has window b as parent. Don't expect it to occlude
// window a since its bounds are clipped by window b.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10), window_b);
EXPECT_FALSE(delegate_c->is_expecting_call());
}
@@ -1102,7 +1237,7 @@ TEST_F(WindowOcclusionTrackerTest, DestroyWindowWithPendingAnimation) {
layer_animation_settings.SetTransitionDuration(kTransitionDuration);
MockWindowDelegate* delegate = new MockWindowDelegate();
- delegate->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
window->layer()->SetAnimator(test_controller.animator());
@@ -1130,28 +1265,29 @@ TEST_F(WindowOcclusionTrackerTest, RecreateLayerOfAnimatedWindow) {
// Create 2 windows. Window b occludes window a.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(2, 2, 1, 1));
EXPECT_FALSE(delegate_a->is_expecting_call());
window_a->layer()->SetAnimator(test_controller.animator());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Start animating the bounds of window a. Window a should be non-occluded
// when the animation starts.
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_a->SetBounds(gfx::Rect(6, 6, 1, 1));
test_controller.Step(kTransitionDuration / 2);
EXPECT_FALSE(delegate_a->is_expecting_call());
// Recreate the layer of window b. Expect this to behave the same as if the
- // animation was abandoned.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ // animation was abandoned. Occlusion region should be half way between the
+ // animation bounds.
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
std::unique_ptr<ui::Layer> old_layer = window_a->RecreateLayer();
EXPECT_FALSE(delegate_a->is_expecting_call());
@@ -1181,7 +1317,7 @@ class ObserverChangingWindowBounds : public WindowObserver {
TEST_F(WindowOcclusionTrackerTest, ChangeTrackedWindowBeforeObserveAddToRoot) {
// Create a window. Expect it to be non-occluded.
MockWindowDelegate* delegate = new MockWindowDelegate();
- delegate->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
@@ -1243,7 +1379,7 @@ TEST_F(WindowOcclusionTrackerTest,
// Create a window. Expect it to be non-occluded.
MockWindowDelegate* delegate = new MockWindowDelegate();
- delegate->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
window->layer()->SetAnimator(test_controller.animator());
@@ -1275,20 +1411,27 @@ TEST_F(WindowOcclusionTrackerTest,
// Create a tracked window. Expect it to be non-occluded.
MockWindowDelegate* delegate = new MockWindowDelegate();
- delegate->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
// Create a non-tracked window and add an observer that deletes it when its
// stops being animated.
+ delegate->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
Window* window = CreateUntrackedWindow(gfx::Rect(10, 0, 10, 10));
+ EXPECT_FALSE(delegate->is_expecting_call());
+
window->layer()->SetAnimator(test_controller.animator());
ObserverDestroyingWindowOnAnimationEnded observer(window);
window->layer()->GetAnimator()->AddObserver(&observer);
// Animate the window. WindowOcclusionTracker should add itself as an observer
- // of its LayerAnimator (after |observer|).
+ // of its LayerAnimator (after |observer|). Upon beginning animation, the
+ // window should no longer affect the occluded region.
+ delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window->layer()->SetOpacity(0.5f);
+ EXPECT_FALSE(delegate->is_expecting_call());
// Remove the non-tracked window from its root. WindowOcclusionTracker should
// remove the window from its list of animated windows and stop observing it
@@ -1306,48 +1449,87 @@ namespace {
class WindowDelegateHidingWindowIfOccluded : public MockWindowDelegate {
public:
- WindowDelegateHidingWindowIfOccluded(Window* other_window,
- MockWindowDelegate* other_delegate)
- : other_window_(other_window), other_delegate_(other_delegate) {}
+ WindowDelegateHidingWindowIfOccluded(Window* other_window)
+ : other_window_(other_window) {}
// MockWindowDelegate:
- void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) override {
- MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
+ occluded_region);
if (occlusion_state == Window::OcclusionState::HIDDEN) {
other_window_->Hide();
- other_delegate_->set_expectation(Window::OcclusionState::HIDDEN);
}
}
private:
Window* other_window_;
- MockWindowDelegate* other_delegate_;
DISALLOW_COPY_AND_ASSIGN(WindowDelegateHidingWindowIfOccluded);
};
+class WindowDelegateWithQueuedExpectation : public MockWindowDelegate {
+ public:
+ WindowDelegateWithQueuedExpectation() = default;
+
+ void set_queued_expectation(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) {
+ queued_expected_occlusion_state_ = occlusion_state;
+ queued_expected_occluded_region_ = occluded_region;
+ }
+
+ // MockWindowDelegate:
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
+ occluded_region);
+ if (queued_expected_occlusion_state_ != Window::OcclusionState::UNKNOWN) {
+ set_expectation(queued_expected_occlusion_state_,
+ queued_expected_occluded_region_);
+ queued_expected_occlusion_state_ = Window::OcclusionState::UNKNOWN;
+ queued_expected_occluded_region_ = SkRegion();
+ }
+ }
+
+ private:
+ Window::OcclusionState queued_expected_occlusion_state_ =
+ Window::OcclusionState::UNKNOWN;
+ SkRegion queued_expected_occluded_region_ = SkRegion();
+
+ DISALLOW_COPY_AND_ASSIGN(WindowDelegateWithQueuedExpectation);
+};
+
} // namespace
// Verify that a window delegate can change the visibility of another window
// when it is notified that its occlusion changed.
TEST_F(WindowOcclusionTrackerTest, HideFromOnWindowOcclusionChanged) {
// Create a tracked window. Expect it to be visible.
- MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ WindowDelegateWithQueuedExpectation* delegate_a =
+ new WindowDelegateWithQueuedExpectation();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_b =
- new WindowDelegateHidingWindowIfOccluded(window_a, delegate_a);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
- Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(5, 5, 10, 10));
+ new WindowDelegateHidingWindowIfOccluded(window_a);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(10, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
- // Hide the tracked window. It should be able to hide |window_a|.
- delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
+ // Hide the tracked window. It should be able to hide |window_a|. Before
+ // |window_a| is hidden, it will notice that the occlusion region has changed
+ // now that |window_b| is hidden. Then, it will be hidden by |window_b|.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_a->set_queued_expectation(Window::OcclusionState::HIDDEN,
+ SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
+
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(window_a->IsVisible());
@@ -1363,9 +1545,10 @@ class WindowDelegateDeletingWindow : public MockWindowDelegate {
void set_other_window(Window* other_window) { other_window_ = other_window; }
// MockWindowDelegate:
- void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) override {
- MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
+ occluded_region);
if (occlusion_state == Window::OcclusionState::OCCLUDED) {
delete other_window_;
other_window_ = nullptr;
@@ -1386,29 +1569,42 @@ class WindowDelegateDeletingWindow : public MockWindowDelegate {
TEST_F(WindowOcclusionTrackerTest, DeleteFromOnWindowOcclusionChanged) {
// Create a tracked window. Expect it to be visible.
WindowDelegateDeletingWindow* delegate_a = new WindowDelegateDeletingWindow();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(10, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(
+ Window::OcclusionState::VISIBLE,
+ SkRegionFromSkIRects({SkIRect::MakeXYWH(10, 0, 10, 10),
+ SkIRect::MakeXYWH(20, 0, 10, 10)}));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(20, 0, 10, 10)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(20, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// |window_c| will be deleted when |window_a| is occluded.
delegate_a->set_other_window(window_c);
// Move |window_b| on top of |window_a|.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->SetBounds(window_a->bounds());
EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
}
namespace {
@@ -1420,9 +1616,10 @@ class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {
void set_window_to_update(Window* window) { window_to_update_ = window; }
// MockWindowDelegate:
- void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) override {
- MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
+ occluded_region);
if (!window_to_update_)
return;
@@ -1431,10 +1628,10 @@ class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {
if (window_to_update_->IsVisible()) {
window_to_update_->Hide();
if (num_occlusion_change_ <= 3)
- set_expectation(Window::OcclusionState::HIDDEN);
+ set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
} else {
window_to_update_->Show();
- set_expectation(Window::OcclusionState::VISIBLE);
+ set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
}
}
@@ -1450,34 +1647,41 @@ class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {
// Verify that if a window changes its visibility every time it is notified that
// its occlusion state changed, a DCHECK occurs.
TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
- test::WindowOcclusionTrackerTestApi test_api(root_window()->env());
+ test::WindowOcclusionTrackerTestApi test_api(
+ root_window()->env()->GetWindowOcclusionTracker());
// Create 2 superposed tracked windows.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create a hidden tracked window.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 10));
EXPECT_FALSE(delegate_c->is_expecting_call());
- delegate_c->set_expectation(Window::OcclusionState::HIDDEN);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_c->Hide();
EXPECT_FALSE(delegate_c->is_expecting_call());
// Create a tracked window. Expect it to be non-occluded.
auto* delegate_d = new WindowDelegateChangingWindowVisibility();
- delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(20, 0, 10, 10)));
+ delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(20, 0, 10, 10));
+ EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_d->is_expecting_call());
// Store a pointer to |window_d| in |delegate_d|. This will cause a call to
@@ -1489,8 +1693,9 @@ TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
// reached, the occlusion state of all IsVisible() windows should be set to
// VISIBLE.
EXPECT_DCHECK_DEATH({
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
- delegate_d->set_expectation(Window::OcclusionState::HIDDEN);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(20, 0, 10, 10)));
+ delegate_d->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_d->Hide();
});
}
@@ -1500,25 +1705,25 @@ TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {
// Create a branch of 3 tracked windows. Expect them to be visible.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b =
CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 20, 10, 10), window_b);
EXPECT_FALSE(delegate_c->is_expecting_call());
// Hide |window_b| (and hence |window_c|). Expect |window_b| and |window_c| to
// be hidden.
- delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
- delegate_c->set_expectation(Window::OcclusionState::HIDDEN);
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -1528,13 +1733,13 @@ TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {
TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {
// Create 2 superposed tracked windows.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
@@ -1543,13 +1748,14 @@ TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {
// occluded.
auto shape = std::make_unique<ui::Layer::ShapeRects>();
shape->emplace_back(0, 0, 5, 5);
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ // Shaped windows are not considered opaque, so the occluded region is empty.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetAlphaShape(std::move(shape));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Clear the shape for the top window. The window underneath should be
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetAlphaShape(nullptr);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -1559,18 +1765,21 @@ TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {
TEST_F(WindowOcclusionTrackerTest, WindowWithParentAlphaShape) {
// Create a child and parent that cover another window.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeWH(10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
- delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 20, 20), window_b);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
@@ -1579,13 +1788,13 @@ TEST_F(WindowOcclusionTrackerTest, WindowWithParentAlphaShape) {
// occluded.
auto shape = std::make_unique<ui::Layer::ShapeRects>();
shape->emplace_back(0, 0, 5, 5);
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetAlphaShape(std::move(shape));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Clear the shape for |window_b|. |window_a| and |window_b| should be
// occluded.
- delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetAlphaShape(nullptr);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
@@ -1599,9 +1808,10 @@ class WindowDelegateHidingWindow : public MockWindowDelegate {
void set_window_to_update(Window* window) { window_to_update_ = window; }
// MockWindowDelegate:
- void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) override {
- MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
+ occluded_region);
if (!window_to_update_)
return;
@@ -1616,15 +1826,28 @@ class WindowDelegateHidingWindow : public MockWindowDelegate {
class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {
public:
- WindowDelegateAddingAndHidingChild(WindowOcclusionTrackerTest* test)
+ explicit WindowDelegateAddingAndHidingChild(WindowOcclusionTrackerTest* test)
: test_(test) {}
+ void set_queued_expectation(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) {
+ queued_expected_occlusion_state_ = occlusion_state;
+ queued_expected_occluded_region_ = occluded_region;
+ }
+
void set_window_to_update(Window* window) { window_to_update_ = window; }
// MockWindowDelegate:
- void OnWindowOcclusionChanged(
- Window::OcclusionState occlusion_state) override {
- MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
+ void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
+ const SkRegion& occluded_region) override {
+ MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
+ occluded_region);
+ if (queued_expected_occlusion_state_ != Window::OcclusionState::UNKNOWN) {
+ set_expectation(queued_expected_occlusion_state_,
+ queued_expected_occluded_region_);
+ queued_expected_occlusion_state_ = Window::OcclusionState::UNKNOWN;
+ queued_expected_occluded_region_ = SkRegion();
+ }
if (!window_to_update_)
return;
@@ -1640,6 +1863,9 @@ class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {
private:
WindowOcclusionTrackerTest* test_;
Window* window_to_update_ = nullptr;
+ Window::OcclusionState queued_expected_occlusion_state_ =
+ Window::OcclusionState::UNKNOWN;
+ SkRegion queued_expected_occluded_region_ = SkRegion();
DISALLOW_COPY_AND_ASSIGN(WindowDelegateAddingAndHidingChild);
};
@@ -1650,25 +1876,31 @@ class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {
// to be recomputed.
TEST_F(WindowOcclusionTrackerTest,
HideWindowWithHiddenParentOnOcclusionChange) {
- test::WindowOcclusionTrackerTestApi test_api(root_window()->env());
+ test::WindowOcclusionTrackerTestApi test_api(
+ root_window()->env()->GetWindowOcclusionTracker());
auto* delegate_a = new WindowDelegateAddingAndHidingChild(this);
- delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
auto* delegate_b = new WindowDelegateHidingWindow();
- delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// When |window_b| is hidden, it will hide |window_a|. |window_a| will in turn
// add a child to itself and hide it.
delegate_a->set_window_to_update(window_a);
delegate_b->set_window_to_update(window_a);
-
- delegate_a->set_expectation(Window::OcclusionState::HIDDEN);
- delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
+ // Initially A is marked as visible with no potential occlusion.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_a->set_queued_expectation(Window::OcclusionState::HIDDEN,
+ SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
// Hiding a child to |window_a| and hiding it shouldn't cause occlusion to be
// recomputed too many times (i.e. the call below shouldn't DCHECK).
window_b->Hide();
@@ -1676,4 +1908,247 @@ TEST_F(WindowOcclusionTrackerTest,
EXPECT_FALSE(delegate_b->is_expecting_call());
}
+// Verify that hiding a window changes the occlusion region to show that the
+// window is fully occluded.
+TEST_F(WindowOcclusionTrackerTest,
+ HideWindowChangesOcclusionRegionToBeFullyOccluded) {
+ MockWindowDelegate* delegate_a = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ delegate_a->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
+ window_a->Hide();
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+}
+
+// Test partial occlusion, test partial occlusion changing hidden, alpha shape
+// occlusion from multiple windows
+
+// Verify that a window can occlude another one partially.
+TEST_F(WindowOcclusionTrackerTest, WindowOccludesWindowPartially) {
+ // Create window a. Expect it to be non-occluded.
+ MockWindowDelegate* delegate_a = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Create window b, occluding window a partially.
+ MockWindowDelegate* delegate_b = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(6, 7, 8, 9)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(6, 7, 8, 9));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+
+ // Hiding window b should stop occluding window a partially.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
+ window_b->Hide();
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+}
+
+// Verify that windows with alpha shape do not affect occlusion regions.
+TEST_F(WindowOcclusionTrackerTest,
+ WindowWithAlphaShapeDoesNotPartiallyOccludeOtherWindows) {
+ // Create window a. Expect it to be non-occluded.
+ MockWindowDelegate* delegate_a = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Create window b, occluding window a partially.
+ MockWindowDelegate* delegate_b = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(6, 7, 8, 9)));
+ delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(6, 7, 8, 9));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_b->is_expecting_call());
+
+ // Set a shape for window b. The window underneath should no longer be
+ // partially occluded.
+ auto shape = std::make_unique<ui::Layer::ShapeRects>();
+ shape->emplace_back(0, 0, 5, 5);
+ // Shaped windows are not considered opaque, so the occluded region is empty.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ window_b->layer()->SetAlphaShape(std::move(shape));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Clear the shape for the top window. The window underneath should be
+ // occluded.
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ SkRegion(SkIRect::MakeXYWH(6, 7, 8, 9)));
+ window_b->layer()->SetAlphaShape(nullptr);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+}
+
+// Verify that a window can be occluded by multiple other windows.
+TEST_F(WindowOcclusionTrackerTest, WindowCanBeOccludedByMultipleWindows) {
+ // Create window a. Expect it to be non-occluded.
+ MockWindowDelegate* delegate_a = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ SkRegion window_a_occlusion = SkRegion(SkIRect::MakeXYWH(9, 9, 5, 5));
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ CreateUntrackedWindow(gfx::Rect(9, 9, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ window_a_occlusion.op(SkIRect::MakeXYWH(-4, -4, 5, 5),
+ SkRegion::Op::kUnion_Op);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ CreateUntrackedWindow(gfx::Rect(-4, -4, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ window_a_occlusion.op(SkIRect::MakeXYWH(9, -4, 5, 5),
+ SkRegion::Op::kUnion_Op);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ CreateUntrackedWindow(gfx::Rect(9, -4, 5, 5));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ window_a_occlusion.op(SkIRect::MakeXYWH(5, 5, 2, 3), SkRegion::Op::kUnion_Op);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ CreateUntrackedWindow(gfx::Rect(5, 5, 2, 3));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+}
+
+// Verify that the excluded window is indeed ignored by occlusion tracking.
+TEST_F(WindowOcclusionTrackerTest, ExcludeWindow) {
+ MockWindowDelegate* delegate_a = new MockWindowDelegate();
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ delegate_a->SetName("WindowA");
+
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 100, 100), nullptr);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ MockWindowDelegate* delegate_bb = new MockWindowDelegate();
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ CreateTrackedWindow(delegate_bb, gfx::Rect(0, 0, 10, 10), window_b);
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+
+ delegate_bb->SetName("WindowBB");
+
+ delegate_bb->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ Window* window_c = CreateUntrackedWindow(gfx::Rect(0, 0, 100, 100), nullptr);
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+
+ {
+ // |window_b| is excluded, so its child's occlusion state becomes VISIBlE.
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ EXPECT_TRUE(delegate_bb->is_expecting_call());
+ WindowOcclusionTracker::ScopedExclude scoped(window_b);
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+
+ // Moving |window_c| out from |window_a| will make |window_a| visible
+ // because |window_b| is ignored.
+ SkRegion window_a_occlusion(SkIRect::MakeXYWH(100, 100, 100, 100));
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ SkRegion window_bb_occlusion;
+ window_bb_occlusion.op(SkIRect::MakeXYWH(100, 100, 100, 100),
+ SkRegion::kUnion_Op);
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE,
+ window_bb_occlusion);
+ window_c->SetBounds(gfx::Rect(100, 100, 100, 100));
+
+ // Un-excluding wil make |window_bb| OCCLUDED.
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE,
+ window_bb_occlusion);
+ }
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+
+ {
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ SkRegion window_a_occlusion(SkIRect::MakeXYWH(100, 100, 100, 100));
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ EXPECT_TRUE(delegate_bb->is_expecting_call());
+ WindowOcclusionTracker::ScopedExclude scoped(window_b);
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Moving |window_b| will not affect the occlusion status.
+ window_b->SetBounds(gfx::Rect(5, 5, 100, 100));
+
+ // Un-excluding will update the occlustion status.
+ // A's occlustion status includes all windows above a.
+ window_a_occlusion.setEmpty();
+ window_a_occlusion.op(SkIRect::MakeXYWH(5, 5, 100, 100),
+ SkRegion::kUnion_Op);
+ window_a_occlusion.op(SkIRect::MakeXYWH(100, 100, 100, 100),
+ SkRegion::kUnion_Op);
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+
+ SkRegion window_bb_occlusion(SkIRect::MakeXYWH(100, 100, 100, 100));
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE,
+ window_bb_occlusion);
+ }
+
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+
+ {
+ delegate_bb->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ SkRegion window_a_occlusion(SkIRect::MakeXYWH(100, 100, 100, 100));
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ EXPECT_TRUE(delegate_bb->is_expecting_call());
+ WindowOcclusionTracker::ScopedExclude scoped(window_b);
+ EXPECT_FALSE(delegate_bb->is_expecting_call());
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Deleting the excluded window will un-exclude itself and recomputes the
+ // occlustion state, but should not affect the state on existing windows
+ // because it's already excluded.
+ delete window_b;
+ EXPECT_FALSE(scoped.window());
+ }
+
+ MockWindowDelegate* delegate_d = new MockWindowDelegate();
+ delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+
+ auto* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(0, 0, 10, 10));
+ window_d->SetName("WindowD");
+
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ EXPECT_FALSE(delegate_d->is_expecting_call());
+
+ {
+ // Make sure excluding the tracked window also works.
+ SkRegion window_a_occlusion(SkIRect::MakeXYWH(100, 100, 100, 100));
+ delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
+ window_a_occlusion);
+ WindowOcclusionTracker::ScopedExclude scoped(window_d);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+
+ // Changing opacity/bounds shouldn't change the occlusion state.
+ window_d->layer()->SetOpacity(0.5f);
+ window_d->SetBounds(gfx::Rect(0, 0, 20, 20));
+
+ // A is now visible even if |window_d| is un-excluded becaues
+ // window_d is not fully opaque.
+ }
+
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+ delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
+ window_d->layer()->SetOpacity(1.f);
+ EXPECT_FALSE(delegate_a->is_expecting_call());
+}
+
} // namespace aura
diff --git a/chromium/ui/aura/window_port.cc b/chromium/ui/aura/window_port.cc
index 2c3b71651ba..80f9c4bcd14 100644
--- a/chromium/ui/aura/window_port.cc
+++ b/chromium/ui/aura/window_port.cc
@@ -16,7 +16,7 @@ WindowPort* WindowPort::Get(Window* window) {
}
// static
-base::ObserverList<WindowObserver, true>::Unchecked* WindowPort::GetObservers(
+base::ObserverList<WindowObserver, true>* WindowPort::GetObservers(
Window* window) {
return &(window->observers_);
}
diff --git a/chromium/ui/aura/window_port.h b/chromium/ui/aura/window_port.h
index 8e058542b48..4c4073afa92 100644
--- a/chromium/ui/aura/window_port.h
+++ b/chromium/ui/aura/window_port.h
@@ -13,6 +13,8 @@
#include "base/callback.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "ui/aura/aura_export.h"
@@ -105,10 +107,6 @@ class AURA_EXPORT WindowPort {
// that does not involve a resize or a device scale factor change.
virtual void AllocateLocalSurfaceId() = 0;
- // When a child-allocated viz::LocalSurfaceId is being processed, this returns
- // true.
- virtual bool IsLocalSurfaceIdAllocationSuppressed() const = 0;
-
// When a ScopedSurfaceIdAllocator is alive, it prevents the
// allocator from actually allocating. Instead, it triggers its
// |allocation_task| upon destruction. This allows us to issue only one
@@ -117,13 +115,18 @@ class AURA_EXPORT WindowPort {
virtual viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) = 0;
+ // Marks the current viz::LocalSurfaceId as invalid. AllocateLocalSurfaceId
+ // must be called before submitting new CompositorFrames.
+ virtual void InvalidateLocalSurfaceId() = 0;
+
virtual void UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) = 0;
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) = 0;
- // Gets the current viz::LocalSurfaceId. The viz::LocalSurfaceId is allocated
- // lazily on call, and will be updated on changes to size or device scale
- // factor.
- virtual const viz::LocalSurfaceId& GetLocalSurfaceId() = 0;
+ // Gets the current viz::LocalSurfaceIdAllocation which incorporates both
+ // the viz::LocalSurfaceId and its allocation time.
+ virtual const viz::LocalSurfaceIdAllocation&
+ GetLocalSurfaceIdAllocation() = 0;
virtual void OnEventTargetingPolicyChanged() = 0;
@@ -135,6 +138,9 @@ class AURA_EXPORT WindowPort {
virtual void RegisterFrameSinkId(const viz::FrameSinkId& frame_sink_id) {}
virtual void UnregisterFrameSinkId(const viz::FrameSinkId& frame_sink_id) {}
+ // Called to start occlusion state tracking.
+ virtual void TrackOcclusionState() {}
+
protected:
explicit WindowPort(Type type);
@@ -142,8 +148,7 @@ class AURA_EXPORT WindowPort {
static WindowPort* Get(Window* window);
// Returns the ObserverList of a Window.
- static base::ObserverList<WindowObserver, true>::Unchecked* GetObservers(
- Window* window);
+ static base::ObserverList<WindowObserver, true>* GetObservers(Window* window);
private:
const Type type_;
diff --git a/chromium/ui/aura/window_port_for_shutdown.cc b/chromium/ui/aura/window_port_for_shutdown.cc
index a30583c51cd..5ff4b043836 100644
--- a/chromium/ui/aura/window_port_for_shutdown.cc
+++ b/chromium/ui/aura/window_port_for_shutdown.cc
@@ -58,20 +58,19 @@ WindowPortForShutdown::CreateLayerTreeFrameSink() {
}
void WindowPortForShutdown::AllocateLocalSurfaceId() {}
+void WindowPortForShutdown::InvalidateLocalSurfaceId() {}
void WindowPortForShutdown::UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) {}
-
-bool WindowPortForShutdown::IsLocalSurfaceIdAllocationSuppressed() const {
- return false;
-}
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) {}
viz::ScopedSurfaceIdAllocator WindowPortForShutdown::GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) {
return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
}
-const viz::LocalSurfaceId& WindowPortForShutdown::GetLocalSurfaceId() {
- return local_surface_id_;
+const viz::LocalSurfaceIdAllocation&
+WindowPortForShutdown::GetLocalSurfaceIdAllocation() {
+ return local_surface_id_allocation_;
}
void WindowPortForShutdown::OnEventTargetingPolicyChanged() {}
diff --git a/chromium/ui/aura/window_port_for_shutdown.h b/chromium/ui/aura/window_port_for_shutdown.h
index 4e13a1f406e..4d7bd083a5e 100644
--- a/chromium/ui/aura/window_port_for_shutdown.h
+++ b/chromium/ui/aura/window_port_for_shutdown.h
@@ -7,7 +7,8 @@
#include "ui/aura/window_port.h"
-#include "components/viz/common/surfaces/local_surface_id.h"
+#include "base/time/time.h"
+#include "components/viz/common/surfaces/local_surface_id_allocation.h"
namespace aura {
@@ -40,17 +41,18 @@ class WindowPortForShutdown : public WindowPort {
std::unique_ptr<ui::PropertyData> data) override;
std::unique_ptr<cc::LayerTreeFrameSink> CreateLayerTreeFrameSink() override;
void AllocateLocalSurfaceId() override;
- bool IsLocalSurfaceIdAllocationSuppressed() const override;
viz::ScopedSurfaceIdAllocator GetSurfaceIdAllocator(
base::OnceCallback<void()> allocation_task) override;
+ void InvalidateLocalSurfaceId() override;
void UpdateLocalSurfaceIdFromEmbeddedClient(
- const viz::LocalSurfaceId& embedded_client_local_surface_id) override;
- const viz::LocalSurfaceId& GetLocalSurfaceId() override;
+ const viz::LocalSurfaceIdAllocation&
+ embedded_client_local_surface_id_allocation) override;
+ const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation() override;
void OnEventTargetingPolicyChanged() override;
bool ShouldRestackTransientChildren() override;
private:
- viz::LocalSurfaceId local_surface_id_;
+ viz::LocalSurfaceIdAllocation local_surface_id_allocation_;
DISALLOW_COPY_AND_ASSIGN(WindowPortForShutdown);
};
diff --git a/chromium/ui/aura/window_targeter.cc b/chromium/ui/aura/window_targeter.cc
index 19a77c27a51..14665e38eaf 100644
--- a/chromium/ui/aura/window_targeter.cc
+++ b/chromium/ui/aura/window_targeter.cc
@@ -190,7 +190,7 @@ ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
ui::Event* event) {
Window* window = static_cast<Window*>(root);
Window* target = event->IsKeyEvent()
- ? FindTargetForKeyEvent(window, *event->AsKeyEvent())
+ ? FindTargetForKeyEvent(window)
: FindTargetForNonKeyEvent(window, event);
if (target && !window->parent() &&
ProcessEventIfTargetsDifferentRootWindow(window, target, event)) {
@@ -205,6 +205,24 @@ ui::EventTarget* WindowTargeter::FindNextBestTarget(
return nullptr;
}
+Window* WindowTargeter::FindTargetForKeyEvent(Window* window) {
+ Window* root_window = window->GetRootWindow();
+ client::FocusClient* focus_client = client::GetFocusClient(root_window);
+ if (!focus_client)
+ return window;
+ Window* focused_window = focus_client->GetFocusedWindow();
+ if (!focused_window)
+ return window;
+
+ client::EventClient* event_client = client::GetEventClient(root_window);
+ if (event_client &&
+ !event_client->CanProcessEventsWithinSubtree(focused_window)) {
+ focus_client->FocusWindow(nullptr);
+ return nullptr;
+ }
+ return focused_window ? focused_window : window;
+}
+
void WindowTargeter::OnInstalled(Window* window) {
window_ = window;
UpdateMusIfNecessary();
@@ -328,25 +346,6 @@ void WindowTargeter::UpdateMusIfNecessary() {
}
}
-Window* WindowTargeter::FindTargetForKeyEvent(Window* window,
- const ui::KeyEvent& key) {
- Window* root_window = window->GetRootWindow();
- client::FocusClient* focus_client = client::GetFocusClient(root_window);
- if (!focus_client)
- return window;
- Window* focused_window = focus_client->GetFocusedWindow();
- if (!focused_window)
- return window;
-
- client::EventClient* event_client = client::GetEventClient(root_window);
- if (event_client &&
- !event_client->CanProcessEventsWithinSubtree(focused_window)) {
- focus_client->FocusWindow(nullptr);
- return nullptr;
- }
- return focused_window ? focused_window : window;
-}
-
Window* WindowTargeter::FindTargetForNonKeyEvent(Window* root_window,
ui::Event* event) {
if (!event->IsLocatedEvent())
diff --git a/chromium/ui/aura/window_targeter.h b/chromium/ui/aura/window_targeter.h
index 3d251b8a37e..3457bd84f7f 100644
--- a/chromium/ui/aura/window_targeter.h
+++ b/chromium/ui/aura/window_targeter.h
@@ -18,7 +18,6 @@ class Rect;
}
namespace ui {
-class KeyEvent;
class LocatedEvent;
} // namespace ui
@@ -87,6 +86,8 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
ui::Event* event) override;
+ Window* FindTargetForKeyEvent(Window* root_window);
+
protected:
aura::Window* window() { return window_; }
const aura::Window* window() const { return window_; }
@@ -131,7 +132,6 @@ class AURA_EXPORT WindowTargeter : public ui::EventTargeter {
void UpdateMusIfNecessary();
- Window* FindTargetForKeyEvent(Window* root_window, const ui::KeyEvent& event);
Window* FindTargetForNonKeyEvent(Window* root_window, ui::Event* event);
Window* FindTargetForLocatedEventRecursively(Window* root_window,
ui::LocatedEvent* event);
diff --git a/chromium/ui/aura/window_tree_host.cc b/chromium/ui/aura/window_tree_host.cc
index eb205785534..89ed4c6bb9b 100644
--- a/chromium/ui/aura/window_tree_host.cc
+++ b/chromium/ui/aura/window_tree_host.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
@@ -39,6 +40,10 @@
#include "ui/gfx/icc_profile.h"
#include "ui/platform_window/platform_window_init_properties.h"
+#if defined(OS_WIN)
+#include "ui/aura/native_window_occlusion_tracker_win.h"
+#endif // OS_WIN
+
namespace aura {
namespace {
@@ -58,11 +63,13 @@ class ScopedLocalSurfaceIdValidator {
public:
explicit ScopedLocalSurfaceIdValidator(Window* window)
: window_(window),
- local_surface_id_(window ? window->GetLocalSurfaceId()
- : viz::LocalSurfaceId()) {}
+ local_surface_id_(
+ window ? window->GetLocalSurfaceIdAllocation().local_surface_id()
+ : viz::LocalSurfaceId()) {}
~ScopedLocalSurfaceIdValidator() {
if (window_ && ShouldAllocateLocalSurfaceId(window_))
- DCHECK_EQ(local_surface_id_, window_->GetLocalSurfaceId());
+ DCHECK_EQ(local_surface_id_,
+ window_->GetLocalSurfaceIdAllocation().local_surface_id());
}
private:
@@ -78,6 +85,12 @@ class ScopedLocalSurfaceIdValidator {
};
#endif
+#if defined(OS_WIN)
+bool IsNativeWindowOcclusionEnabled() {
+ return base::FeatureList::IsEnabled(features::kCalculateNativeWinOcclusion);
+}
+#endif // OS_WIN
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -118,6 +131,10 @@ void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) {
observers_.RemoveObserver(observer);
}
+bool WindowTreeHost::HasObserver(const WindowTreeHostObserver* observer) const {
+ return observers_.HasObserver(observer);
+}
+
ui::EventSink* WindowTreeHost::event_sink() {
return dispatcher_.get();
}
@@ -288,11 +305,42 @@ std::unique_ptr<ScopedKeyboardHook> WindowTreeHost::CaptureSystemKeyEvents(
return nullptr;
}
+bool WindowTreeHost::ShouldSendKeyEventToIme() {
+ return true;
+}
+
+void WindowTreeHost::EnableNativeWindowOcclusionTracking() {
+#if defined(OS_WIN)
+ if (IsNativeWindowOcclusionEnabled()) {
+ NativeWindowOcclusionTrackerWin::GetOrCreateInstance()->Enable(window());
+ }
+#endif // OS_WIN
+}
+
+void WindowTreeHost::DisableNativeWindowOcclusionTracking() {
+#if defined(OS_WIN)
+ if (IsNativeWindowOcclusionEnabled()) {
+ occlusion_state_ = Window::OcclusionState::UNKNOWN;
+ NativeWindowOcclusionTrackerWin::GetOrCreateInstance()->Disable(window());
+ }
+#endif // OS_WIN
+}
+
+void WindowTreeHost::SetNativeWindowOcclusionState(
+ Window::OcclusionState state) {
+ if (occlusion_state_ != state) {
+ occlusion_state_ = state;
+ for (WindowTreeHostObserver& observer : observers_)
+ observer.OnOcclusionStateChanged(this, state);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// WindowTreeHost, protected:
WindowTreeHost::WindowTreeHost(std::unique_ptr<Window> window)
: window_(window.release()), // See header for details on ownership.
+ occlusion_state_(Window::OcclusionState::UNKNOWN),
last_cursor_(ui::CursorType::kNull),
input_method_(nullptr),
owned_input_method_(false),
@@ -300,6 +348,8 @@ WindowTreeHost::WindowTreeHost(std::unique_ptr<Window> window)
if (!window_)
window_ = new Window(nullptr);
display::Screen::GetScreen()->AddObserver(this);
+ auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
+ device_scale_factor_ = display.device_scale_factor();
}
void WindowTreeHost::IntializeDeviceScaleFactor(float device_scale_factor) {
@@ -332,7 +382,8 @@ void WindowTreeHost::DestroyDispatcher() {
void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
bool force_software_compositor,
bool external_begin_frames_enabled,
- bool are_events_in_pixels) {
+ bool are_events_in_pixels,
+ const char* trace_environment_name) {
DCHECK(window()->env());
Env* env = window()->env();
ui::ContextFactory* context_factory = env->context_factory();
@@ -342,14 +393,14 @@ void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
bool enable_surface_synchronization =
env->mode() == aura::Env::Mode::MUS ||
features::IsSurfaceSynchronizationEnabled();
- compositor_.reset(new ui::Compositor(
+ compositor_ = std::make_unique<ui::Compositor>(
(!context_factory_private || frame_sink_id.is_valid())
? frame_sink_id
: context_factory_private->AllocateFrameSinkId(),
context_factory, context_factory_private,
base::ThreadTaskRunnerHandle::Get(), enable_surface_synchronization,
ui::IsPixelCanvasRecordingEnabled(), external_begin_frames_enabled,
- force_software_compositor));
+ force_software_compositor, trace_environment_name);
#if defined(OS_CHROMEOS)
compositor_->AddObserver(this);
#endif
@@ -365,7 +416,7 @@ void WindowTreeHost::CreateCompositor(const viz::FrameSinkId& frame_sink_id,
void WindowTreeHost::InitCompositor() {
DCHECK(!compositor_->root_layer());
compositor_->SetScaleAndSize(device_scale_factor_, GetBoundsInPixels().size(),
- window()->GetLocalSurfaceId());
+ window()->GetLocalSurfaceIdAllocation());
compositor_->SetRootLayer(window()->layer());
display::Display display =
@@ -390,22 +441,25 @@ void WindowTreeHost::OnHostMovedInPixels(
void WindowTreeHost::OnHostResizedInPixels(
const gfx::Size& new_size_in_pixels,
- const viz::LocalSurfaceId& new_local_surface_id) {
+ const viz::LocalSurfaceIdAllocation& new_local_surface_id_allocation) {
+ // TODO(jonross) Unify all OnHostResizedInPixels to have both
+ // viz::LocalSurfaceId and allocation time as optional parameters.
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window());
device_scale_factor_ = display.device_scale_factor();
UpdateRootWindowSizeInPixels();
// Allocate a new LocalSurfaceId for the new state.
- auto local_surface_id = new_local_surface_id;
+ viz::LocalSurfaceIdAllocation local_surface_id_allocation(
+ new_local_surface_id_allocation);
if (ShouldAllocateLocalSurfaceId(window()) &&
- !new_local_surface_id.is_valid()) {
+ !new_local_surface_id_allocation.IsValid()) {
window_->AllocateLocalSurfaceId();
- local_surface_id = window_->GetLocalSurfaceId();
+ local_surface_id_allocation = window_->GetLocalSurfaceIdAllocation();
}
ScopedLocalSurfaceIdValidator lsi_validator(window());
compositor_->SetScaleAndSize(device_scale_factor_, new_size_in_pixels,
- local_surface_id);
+ local_surface_id_allocation);
for (WindowTreeHostObserver& observer : observers_)
observer.OnHostResized(this);
@@ -429,10 +483,6 @@ void WindowTreeHost::OnHostCloseRequested() {
observer.OnHostCloseRequested(this);
}
-void WindowTreeHost::OnHostActivated() {
- window()->env()->NotifyHostActivated(this);
-}
-
void WindowTreeHost::OnHostLostWindowCapture() {
// It is possible for this function to be called during destruction, after the
// root window has already been destroyed (e.g. when the ui::PlatformWindow is
diff --git a/chromium/ui/aura/window_tree_host.h b/chromium/ui/aura/window_tree_host.h
index 8eec7d205ea..e89644f9776 100644
--- a/chromium/ui/aura/window_tree_host.h
+++ b/chromium/ui/aura/window_tree_host.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
+#include "base/time/time.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "ui/aura/aura_export.h"
@@ -79,6 +80,7 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
void AddObserver(WindowTreeHostObserver* observer);
void RemoveObserver(WindowTreeHostObserver* observer);
+ bool HasObserver(const WindowTreeHostObserver* observer) const;
Window* window() { return window_; }
const Window* window() const { return window_; }
@@ -200,7 +202,8 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// when the size change takes effect.
virtual void SetBoundsInPixels(
const gfx::Rect& bounds_in_pixels,
- const viz::LocalSurfaceId& local_surface_id = viz::LocalSurfaceId()) = 0;
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation =
+ viz::LocalSurfaceIdAllocation()) = 0;
virtual gfx::Rect GetBoundsInPixels() const = 0;
// Sets the OS capture to the root window.
@@ -223,6 +226,22 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// Returns a map of KeyboardEvent code to KeyboardEvent key values.
virtual base::flat_map<std::string, std::string> GetKeyboardLayoutMap() = 0;
+ // Returns true if KeyEvents should be send to IME. This is called from
+ // WindowEventDispatcher during event dispatch.
+ virtual bool ShouldSendKeyEventToIme();
+
+ // Enables native window occlusion tracking for the native window this host
+ // represents.
+ virtual void EnableNativeWindowOcclusionTracking();
+
+ // Disables native window occlusion tracking for the native window this host
+ // represents.
+ virtual void DisableNativeWindowOcclusionTracking();
+
+ // Remembers the current occlusion state, and if it has changed, notifies
+ // observers of the change.
+ virtual void SetNativeWindowOcclusionState(Window::OcclusionState state);
+
protected:
friend class ScopedKeyboardHook;
friend class TestScreen; // TODO(beng): see if we can remove/consolidate.
@@ -239,12 +258,13 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// If frame_sink_id is not passed in, one will be grabbed from
// ContextFactoryPrivate. |are_events_in_pixels| indicates if events are
// received in pixels. If |are_events_in_pixels| is false, events are
- // received in DIPs.
+ // received in DIPs. See Compositor() for details on |trace_environment_name|.
void CreateCompositor(
const viz::FrameSinkId& frame_sink_id = viz::FrameSinkId(),
bool force_software_compositor = false,
bool external_begin_frames_enabled = false,
- bool are_events_in_pixels = true);
+ bool are_events_in_pixels = true,
+ const char* trace_environment_name = nullptr);
void InitCompositor();
void OnAcceleratedWidgetAvailable();
@@ -255,11 +275,11 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
void OnHostMovedInPixels(const gfx::Point& new_location_in_pixels);
void OnHostResizedInPixels(
const gfx::Size& new_size_in_pixels,
- const viz::LocalSurfaceId& local_surface_id = viz::LocalSurfaceId());
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation =
+ viz::LocalSurfaceIdAllocation());
void OnHostWorkspaceChanged();
void OnHostDisplayChanged();
void OnHostCloseRequested();
- void OnHostActivated();
void OnHostLostWindowCapture();
// Sets the currently displayed cursor.
@@ -325,6 +345,10 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
// the end of the dtor).
Window* window_; // Owning.
+ // Keeps track of the occlusion state of the host, and used to send
+ // notifications to observers when it changes.
+ Window::OcclusionState occlusion_state_;
+
base::ObserverList<WindowTreeHostObserver>::Unchecked observers_;
std::unique_ptr<WindowEventDispatcher> dispatcher_;
@@ -332,6 +356,11 @@ class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
std::unique_ptr<ui::Compositor> compositor_;
// The device scale factor is snapshotted in OnHostResizedInPixels.
+ // NOTE: this value is cached rather than looked up from the Display as it is
+ // entirely possible for the Display to be updated *after* |this|. For
+ // example, display changes on Windows first result in the HWND bounds
+ // changing and are then followed by changes to the set of displays
+ //
// TODO(ccameron): The size and location from OnHostResizedInPixels and
// OnHostMovedInPixels should be snapshotted here as well.
float device_scale_factor_ = 1.f;
diff --git a/chromium/ui/aura/window_tree_host_observer.h b/chromium/ui/aura/window_tree_host_observer.h
index e71455dc743..00fe3b42d60 100644
--- a/chromium/ui/aura/window_tree_host_observer.h
+++ b/chromium/ui/aura/window_tree_host_observer.h
@@ -6,6 +6,7 @@
#define UI_AURA_WINDOW_TREE_HOST_OBSERVER_H_
#include "ui/aura/aura_export.h"
+#include "ui/aura/window.h"
namespace gfx {
class Point;
@@ -29,6 +30,11 @@ class AURA_EXPORT WindowTreeHostObserver {
// Called when the native window system sends the host request to close.
virtual void OnHostCloseRequested(WindowTreeHost* host) {}
+ // Called when the occlusion status of the native window changes, iff
+ // occlusion tracking is enabled for a descendant of the root.
+ virtual void OnOcclusionStateChanged(WindowTreeHost* host,
+ Window::OcclusionState new_state) {}
+
protected:
virtual ~WindowTreeHostObserver() {}
};
diff --git a/chromium/ui/aura/window_tree_host_platform.cc b/chromium/ui/aura/window_tree_host_platform.cc
index c16bbb1477a..a116ba0b96c 100644
--- a/chromium/ui/aura/window_tree_host_platform.cc
+++ b/chromium/ui/aura/window_tree_host_platform.cc
@@ -53,10 +53,14 @@ std::unique_ptr<WindowTreeHost> WindowTreeHost::Create(
WindowTreeHostPlatform::WindowTreeHostPlatform(
ui::PlatformWindowInitProperties properties,
- std::unique_ptr<Window> window)
+ std::unique_ptr<Window> window,
+ const char* trace_environment_name)
: WindowTreeHost(std::move(window)) {
bounds_ = properties.bounds;
- CreateCompositor();
+ CreateCompositor(viz::FrameSinkId(),
+ /* force_software_compositor */ false,
+ /* external_begin_frames_enabled */ false,
+ /* are_events_in_pixels */ true, trace_environment_name);
CreateAndSetPlatformWindow(std::move(properties));
}
@@ -117,9 +121,9 @@ gfx::Rect WindowTreeHostPlatform::GetBoundsInPixels() const {
void WindowTreeHostPlatform::SetBoundsInPixels(
const gfx::Rect& bounds,
- const viz::LocalSurfaceId& local_surface_id) {
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
pending_size_ = bounds.size();
- pending_local_surface_id_ = local_surface_id;
+ pending_local_surface_id_allocation_ = local_surface_id_allocation;
platform_window_->SetBounds(bounds);
}
@@ -141,7 +145,7 @@ bool WindowTreeHostPlatform::CaptureSystemKeyEventsImpl(
// problems with event routing (i.e. which Hook takes precedence) and
// destruction ordering.
DCHECK(!keyboard_hook_);
- keyboard_hook_ = ui::KeyboardHook::Create(
+ keyboard_hook_ = ui::KeyboardHook::CreateModifierKeyboardHook(
std::move(dom_codes), GetAcceleratedWidget(),
base::BindRepeating(
[](ui::PlatformWindowDelegate* delegate, ui::KeyEvent* event) {
@@ -199,14 +203,14 @@ void WindowTreeHostPlatform::OnBoundsChanged(const gfx::Rect& new_bounds) {
bounds_ = new_bounds;
if (bounds_.origin() != old_bounds.origin())
OnHostMovedInPixels(bounds_.origin());
- if (pending_local_surface_id_.is_valid() ||
+ if (pending_local_surface_id_allocation_.IsValid() ||
bounds_.size() != old_bounds.size() || current_scale != new_scale) {
- auto local_surface_id = bounds_.size() == pending_size_
- ? pending_local_surface_id_
- : viz::LocalSurfaceId();
- pending_local_surface_id_ = viz::LocalSurfaceId();
+ viz::LocalSurfaceIdAllocation local_surface_id_allocation;
+ if (bounds_.size() == pending_size_)
+ local_surface_id_allocation = pending_local_surface_id_allocation_;
+ pending_local_surface_id_allocation_ = viz::LocalSurfaceIdAllocation();
pending_size_ = gfx::Size();
- OnHostResizedInPixels(bounds_.size(), local_surface_id);
+ OnHostResizedInPixels(bounds_.size(), local_surface_id_allocation);
}
}
@@ -269,8 +273,6 @@ void WindowTreeHostPlatform::OnAcceleratedWidgetDestroyed() {
}
void WindowTreeHostPlatform::OnActivationChanged(bool active) {
- if (active)
- OnHostActivated();
}
} // namespace aura
diff --git a/chromium/ui/aura/window_tree_host_platform.h b/chromium/ui/aura/window_tree_host_platform.h
index 91fde9bcf2a..354d7bef0c6 100644
--- a/chromium/ui/aura/window_tree_host_platform.h
+++ b/chromium/ui/aura/window_tree_host_platform.h
@@ -30,8 +30,10 @@ namespace aura {
class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost,
public ui::PlatformWindowDelegate {
public:
+ // See Compositor() for details on |trace_environment_name|.
explicit WindowTreeHostPlatform(ui::PlatformWindowInitProperties properties,
- std::unique_ptr<Window> = nullptr);
+ std::unique_ptr<Window> = nullptr,
+ const char* trace_environment_name = nullptr);
~WindowTreeHostPlatform() override;
// WindowTreeHost:
@@ -41,7 +43,8 @@ class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost,
void HideImpl() override;
gfx::Rect GetBoundsInPixels() const override;
void SetBoundsInPixels(const gfx::Rect& bounds,
- const viz::LocalSurfaceId& local_surface_id) override;
+ const viz::LocalSurfaceIdAllocation&
+ local_surface_id_allocation) override;
gfx::Point GetLocationOnScreenInPixels() const override;
void SetCapture() override;
void ReleaseCapture() override;
@@ -95,12 +98,12 @@ class AURA_EXPORT WindowTreeHostPlatform : public WindowTreeHost,
std::unique_ptr<ui::KeyboardHook> keyboard_hook_;
- // |pending_local_surface_id_| and |pending_size_| are set when the
- // PlatformWindow instance is requested to adopt a new size (in
+ // |pending_local_surface_id_allocation_|, and |pending_size_| are set when
+ // the PlatformWindow instance is requested to adopt a new size (in
// SetBoundsInPixels()). When the platform confirms the new size (by way of
- // OnBoundsChanged() callback), the LocalSurfaceId is set on the compositor,
- // by WindowTreeHost.
- viz::LocalSurfaceId pending_local_surface_id_;
+ // OnBoundsChanged() callback), the LocalSurfaceIdAllocation is set on the
+ // compositor, by WindowTreeHost.
+ viz::LocalSurfaceIdAllocation pending_local_surface_id_allocation_;
gfx::Size pending_size_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeHostPlatform);
diff --git a/chromium/ui/aura/window_tree_host_unittest.cc b/chromium/ui/aura/window_tree_host_unittest.cc
index 6d40482c6d6..abbe0b81e9c 100644
--- a/chromium/ui/aura/window_tree_host_unittest.cc
+++ b/chromium/ui/aura/window_tree_host_unittest.cc
@@ -14,40 +14,9 @@
#include "ui/events/base_event_utils.h"
#include "ui/events/event_rewriter.h"
#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/test/test_event_rewriter.h"
#include "ui/platform_window/stub/stub_window.h"
-namespace {
-
-// Counts number of events observed.
-class CounterEventRewriter : public ui::EventRewriter {
- public:
- CounterEventRewriter() : events_seen_(0) {}
- ~CounterEventRewriter() override {}
-
- int events_seen() const { return events_seen_; }
-
- private:
- // ui::EventRewriter:
- ui::EventRewriteStatus RewriteEvent(
- const ui::Event& event,
- std::unique_ptr<ui::Event>* new_event) override {
- events_seen_++;
- return ui::EVENT_REWRITE_CONTINUE;
- }
-
- ui::EventRewriteStatus NextDispatchEvent(
- const ui::Event& last_event,
- std::unique_ptr<ui::Event>* new_event) override {
- return ui::EVENT_REWRITE_CONTINUE;
- }
-
- int events_seen_;
-
- DISALLOW_COPY_AND_ASSIGN(CounterEventRewriter);
-};
-
-} // namespace
-
namespace aura {
using WindowTreeHostTest = test::AuraTestBase;
@@ -99,7 +68,7 @@ TEST_F(WindowTreeHostTest, HoldPointerMovesOnChildResizing) {
#endif
TEST_F(WindowTreeHostTest, NoRewritesPostIME) {
- CounterEventRewriter event_rewriter;
+ ui::test::TestEventRewriter event_rewriter;
host()->AddEventRewriter(&event_rewriter);
ui::KeyEvent key_event('A', ui::VKEY_A, ui::DomCode::NONE, 0);
diff --git a/chromium/ui/aura/window_unittest.cc b/chromium/ui/aura/window_unittest.cc
index 7edb1e5aced..c5cfcd400ac 100644
--- a/chromium/ui/aura/window_unittest.cc
+++ b/chromium/ui/aura/window_unittest.cc
@@ -424,7 +424,10 @@ TEST_P(WindowTest, RootWindowHasValidLocalSurfaceId) {
// When mus is hosting viz, the LocalSurfaceId is sent from mus.
if (GetParam() != Env::Mode::LOCAL)
return;
- EXPECT_TRUE(root_window()->GetLocalSurfaceId().is_valid());
+ EXPECT_TRUE(root_window()
+ ->GetLocalSurfaceIdAllocation()
+ .local_surface_id()
+ .is_valid());
}
TEST_P(WindowTest, WindowEmbeddingClientHasValidLocalSurfaceId) {
@@ -435,7 +438,8 @@ TEST_P(WindowTest, WindowEmbeddingClientHasValidLocalSurfaceId) {
SK_ColorWHITE, 1, gfx::Rect(10, 10, 300, 200), root_window()));
test::WindowTestApi(window.get()).DisableFrameSinkRegistration();
window->SetEmbedFrameSinkId(viz::FrameSinkId(0, 1));
- EXPECT_TRUE(window->GetLocalSurfaceId().is_valid());
+ EXPECT_TRUE(
+ window->GetLocalSurfaceIdAllocation().local_surface_id().is_valid());
}
// Test Window::ConvertPointToWindow() with transform to root_window.
@@ -3255,34 +3259,41 @@ TEST_P(WindowTest, LocalSurfaceIdChanges) {
window.Init(ui::LAYER_NOT_DRAWN);
window.SetBounds(gfx::Rect(300, 300));
+ root_window()->AddChild(&window);
+
std::unique_ptr<cc::LayerTreeFrameSink> frame_sink(
window.CreateLayerTreeFrameSink());
- viz::LocalSurfaceId local_surface_id1 = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id1 =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
EXPECT_NE(nullptr, frame_sink.get());
EXPECT_TRUE(local_surface_id1.is_valid());
// Resize 0x0 to make sure WindowPort* stores the correct window size before
// creating the frame sink.
window.SetBounds(gfx::Rect(0, 0));
- viz::LocalSurfaceId local_surface_id2 = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id2 =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
EXPECT_TRUE(local_surface_id2.is_valid());
EXPECT_NE(local_surface_id1, local_surface_id2);
window.SetBounds(gfx::Rect(300, 300));
- viz::LocalSurfaceId local_surface_id3 = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id3 =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
EXPECT_TRUE(local_surface_id3.is_valid());
EXPECT_NE(local_surface_id1, local_surface_id3);
EXPECT_NE(local_surface_id2, local_surface_id3);
window.OnDeviceScaleFactorChanged(1.0f, 3.0f);
- viz::LocalSurfaceId local_surface_id4 = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id4 =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
EXPECT_TRUE(local_surface_id4.is_valid());
EXPECT_NE(local_surface_id1, local_surface_id4);
EXPECT_NE(local_surface_id2, local_surface_id4);
EXPECT_NE(local_surface_id3, local_surface_id4);
window.RecreateLayer();
- viz::LocalSurfaceId local_surface_id5 = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id5 =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
EXPECT_TRUE(local_surface_id5.is_valid());
EXPECT_NE(local_surface_id1, local_surface_id5);
EXPECT_NE(local_surface_id2, local_surface_id5);
@@ -3290,7 +3301,8 @@ TEST_P(WindowTest, LocalSurfaceIdChanges) {
EXPECT_NE(local_surface_id4, local_surface_id5);
window.AllocateLocalSurfaceId();
- viz::LocalSurfaceId local_surface_id6 = window.GetLocalSurfaceId();
+ viz::LocalSurfaceId local_surface_id6 =
+ window.GetLocalSurfaceIdAllocation().local_surface_id();
EXPECT_TRUE(local_surface_id6.is_valid());
EXPECT_NE(local_surface_id1, local_surface_id6);
EXPECT_NE(local_surface_id2, local_surface_id6);
diff --git a/chromium/ui/aura_extra/BUILD.gn b/chromium/ui/aura_extra/BUILD.gn
index f66afd10ffb..75962dc069c 100644
--- a/chromium/ui/aura_extra/BUILD.gn
+++ b/chromium/ui/aura_extra/BUILD.gn
@@ -28,3 +28,18 @@ component("aura_extra") {
"//ui/gfx/geometry",
]
}
+
+source_set("vector_resource") {
+ sources = [
+ "skia_vector_resource.cc",
+ "skia_vector_resource.h",
+ ]
+
+ deps = [
+ "//base",
+ "//cc/paint",
+ "//third_party/zlib/google:compression_utils",
+ "//ui/base",
+ "//ui/display",
+ ]
+}
diff --git a/chromium/ui/aura_extra/DEPS b/chromium/ui/aura_extra/DEPS
index 28d322e7a5a..42c02372b96 100644
--- a/chromium/ui/aura_extra/DEPS
+++ b/chromium/ui/aura_extra/DEPS
@@ -1,8 +1,11 @@
include_rules = [
+ "+cc/paint",
"+third_party/skia",
+ "+third_party/zlib/google/compression_utils.h",
"+ui/aura",
"+ui/base",
"+ui/compositor",
+ "+ui/display",
"+ui/events",
"+ui/gfx",
"+ui/platform_window",
diff --git a/chromium/ui/aura_extra/skia_vector_resource.cc b/chromium/ui/aura_extra/skia_vector_resource.cc
new file mode 100644
index 00000000000..fcb823b9874
--- /dev/null
+++ b/chromium/ui/aura_extra/skia_vector_resource.cc
@@ -0,0 +1,83 @@
+// 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/aura_extra/skia_vector_resource.h"
+
+#include <map>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "cc/paint/skottie_wrapper.h"
+#include "third_party/zlib/google/compression_utils.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/skia_vector_animation.h"
+
+#if defined(OS_WIN)
+#include "ui/display/win/dpi.h"
+#endif
+
+namespace aura_extra {
+namespace {
+
+// Cached vector graphics. Each resource is loaded and unzipped only once.
+// TODO(malaykeshav): Investigate if this needs to be an MRU cache with a size
+// limit as the usage increases.
+using VectorAssetCache = std::map<int, scoped_refptr<cc::SkottieWrapper>>;
+VectorAssetCache& GetVectorAssetCache() {
+ static base::NoDestructor<VectorAssetCache> vector_graphic_cache;
+ return *vector_graphic_cache;
+}
+
+} // namespace
+
+std::unique_ptr<gfx::SkiaVectorAnimation> GetVectorAnimationNamed(
+ int resource_id) {
+ auto found = GetVectorAssetCache().find(resource_id);
+ if (found != GetVectorAssetCache().end())
+ return std::make_unique<gfx::SkiaVectorAnimation>(found->second);
+
+ auto& rb = ui::ResourceBundle::GetSharedInstance();
+#if defined(OS_CHROMEOS)
+ ui::ScaleFactor scale_factor_to_load = rb.GetMaxScaleFactor();
+#elif defined(OS_WIN)
+ ui::ScaleFactor scale_factor_to_load = display::win::GetDPIScale() > 1.25
+ ? rb.GetMaxScaleFactor()
+ : ui::SCALE_FACTOR_100P;
+#else
+ ui::ScaleFactor scale_factor_to_load = ui::SCALE_FACTOR_100P;
+#endif
+ // Clamp the scale factor to 2x. At most we will only be needing 2 versions
+ // for a given file.
+ if (scale_factor_to_load > ui::SCALE_FACTOR_200P)
+ scale_factor_to_load = ui::SCALE_FACTOR_200P;
+
+ auto compressed_raw_data =
+ rb.GetRawDataResourceForScale(resource_id, scale_factor_to_load);
+ auto* uncompressed_bytes = new base::RefCountedBytes(
+ compression::GetUncompressedSize(compressed_raw_data));
+ base::StringPiece uncompressed_str_piece(
+ reinterpret_cast<const char*>(uncompressed_bytes->front()),
+ uncompressed_bytes->size());
+
+ TRACE_EVENT1("ui", "GetVectorAnimationNamed uncompress and parse",
+ "zip size bytes", uncompressed_bytes->size());
+ base::TimeTicks start_timestamp = base::TimeTicks::Now();
+ CHECK(
+ compression::GzipUncompress(compressed_raw_data, uncompressed_str_piece));
+
+ auto skottie = base::MakeRefCounted<cc::SkottieWrapper>(uncompressed_bytes);
+
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ "UncompressAndParseSkiaVectorAsset",
+ base::TimeTicks::Now() - start_timestamp,
+ base::TimeDelta::FromMicroseconds(1),
+ base::TimeDelta::FromMilliseconds(50), 100);
+ auto inserted = GetVectorAssetCache().emplace(resource_id, skottie);
+ DCHECK(inserted.second);
+ return std::make_unique<gfx::SkiaVectorAnimation>(inserted.first->second);
+}
+
+} // namespace aura_extra
diff --git a/chromium/ui/aura_extra/skia_vector_resource.h b/chromium/ui/aura_extra/skia_vector_resource.h
new file mode 100644
index 00000000000..d3fa1ffbfce
--- /dev/null
+++ b/chromium/ui/aura_extra/skia_vector_resource.h
@@ -0,0 +1,24 @@
+// 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_AURA_EXTRA_SKIA_VECTOR_RESOURCE_H_
+#define UI_AURA_EXTRA_SKIA_VECTOR_RESOURCE_H_
+
+#include <memory>
+
+namespace gfx {
+class SkiaVectorAnimation;
+} // namespace gfx
+
+namespace aura_extra {
+
+// Gets a vector graphic resource specified by |resource_id| from the current
+// module data and returns it as a SkiaVectorAnimation object. This expects the
+// resource to be gzipped.
+std::unique_ptr<gfx::SkiaVectorAnimation> GetVectorAnimationNamed(
+ int resource_id);
+
+} // namespace aura_extra
+
+#endif // UI_AURA_EXTRA_SKIA_VECTOR_RESOURCE_H_
diff --git a/chromium/ui/base/BUILD.gn b/chromium/ui/base/BUILD.gn
index 1e2170ec644..0364813ec74 100644
--- a/chromium/ui/base/BUILD.gn
+++ b/chromium/ui/base/BUILD.gn
@@ -91,6 +91,8 @@ jumbo_component("base") {
"clipboard/clipboard_win.cc",
"clipboard/clipboard_win.h",
"clipboard/custom_data_helper_mac.mm",
+ "cocoa/accessibility_focus_overrider.h",
+ "cocoa/accessibility_focus_overrider.mm",
"cocoa/animation_utils.h",
"cocoa/appkit_utils.h",
"cocoa/appkit_utils.mm",
@@ -116,10 +118,6 @@ jumbo_component("base") {
"cocoa/focus_tracker.mm",
"cocoa/focus_window_set.h",
"cocoa/focus_window_set.mm",
- "cocoa/hover_button.h",
- "cocoa/hover_button.mm",
- "cocoa/hover_image_button.h",
- "cocoa/hover_image_button.mm",
"cocoa/menu_controller.h",
"cocoa/menu_controller.mm",
"cocoa/nib_loading.h",
@@ -128,6 +126,8 @@ jumbo_component("base") {
"cocoa/ns_view_ids.mm",
"cocoa/quartz_util.h",
"cocoa/quartz_util.mm",
+ "cocoa/remote_accessibility_api.h",
+ "cocoa/remote_accessibility_api.mm",
"cocoa/remote_layer_api.h",
"cocoa/remote_layer_api.mm",
"cocoa/secure_password_input.h",
@@ -298,8 +298,6 @@ jumbo_component("base") {
"win/message_box_win.h",
"win/mouse_wheel_util.cc",
"win/mouse_wheel_util.h",
- "win/open_file_name_win.cc",
- "win/open_file_name_win.h",
"win/scoped_ole_initializer.cc",
"win/scoped_ole_initializer.h",
"win/shell.cc",
@@ -310,7 +308,6 @@ jumbo_component("base") {
"win/window_event_target.h",
"window_open_disposition.cc",
"window_open_disposition.h",
- "work_area_watcher_observer.h",
]
if (is_posix) {
@@ -354,12 +351,12 @@ jumbo_component("base") {
"idle/idle_linux.cc",
"idle/idle_mac.mm",
"idle/idle_win.cc",
+ "pointer/pointer_device.h",
+ "pointer/pointer_device_util.cc",
+ "pointer/touch_editing_controller.cc",
+ "pointer/touch_editing_controller.h",
"text/bytes_formatting.cc",
"text/bytes_formatting.h",
- "touch/touch_device.h",
- "touch/touch_device_util.cc",
- "touch/touch_editing_controller.cc",
- "touch/touch_editing_controller.h",
]
}
@@ -381,17 +378,17 @@ jumbo_component("base") {
}
if (is_win) {
- sources += [ "touch/touch_device_win.cc" ]
+ sources += [ "pointer/pointer_device_win.cc" ]
} else if (is_android) {
- sources += [ "touch/touch_device_android.cc" ]
+ sources += [ "pointer/pointer_device_android.cc" ]
} else if (is_ios) {
- sources += [ "touch/touch_device_ios.cc" ]
+ sources += [ "pointer/pointer_device_ios.cc" ]
} else if (is_linux) {
- sources += [ "touch/touch_device_linux.cc" ]
+ sources += [ "pointer/pointer_device_linux.cc" ]
} else {
# Empty implementation for all other cases.
- sources += [ "touch/touch_device.cc" ]
- sources -= [ "touch/touch_device_util.cc" ]
+ sources += [ "pointer/pointer_device.cc" ]
+ sources -= [ "pointer/pointer_device_util.cc" ]
}
if (is_fuchsia) {
@@ -590,8 +587,6 @@ jumbo_component("base") {
"cursor/cursor_ozone.cc",
"cursor/ozone/bitmap_cursor_factory_ozone.cc",
"cursor/ozone/bitmap_cursor_factory_ozone.h",
- "cursor/ozone/cursor_data_factory_ozone.cc",
- "cursor/ozone/cursor_data_factory_ozone.h",
]
deps += [
@@ -630,8 +625,8 @@ jumbo_component("base") {
"l10n/l10n_font_util.cc",
"models/button_menu_item_model.cc",
"models/dialog_model.cc",
+ "pointer/touch_editing_controller.cc",
"theme_provider.cc",
- "touch/touch_editing_controller.cc",
"ui_base_types.cc",
]
}
@@ -710,8 +705,6 @@ jumbo_static_library("test_support") {
"test/ios/keyboard_appearance_listener.mm",
"test/ios/ui_image_test_utils.h",
"test/ios/ui_image_test_utils.mm",
- "test/ios/ui_view_test_utils.h",
- "test/ios/ui_view_test_utils.mm",
]
}
@@ -856,8 +849,6 @@ test("ui_base_unittests") {
"cocoa/cocoa_base_utils_unittest.mm",
"cocoa/constrained_window/constrained_window_animation_unittest.mm",
"cocoa/focus_tracker_unittest.mm",
- "cocoa/hover_button_unittest.mm",
- "cocoa/hover_image_button_unittest.mm",
"cocoa/menu_controller_unittest.mm",
"cocoa/touch_bar_util_unittest.mm",
"cocoa/tracking_area_unittest.mm",
@@ -940,7 +931,6 @@ test("ui_base_unittests") {
"dragdrop/os_exchange_data_win_unittest.cc",
"win/direct_manipulation_unittest.cc",
"win/hwnd_subclass_unittest.cc",
- "win/open_file_name_win_unittest.cc",
]
ldflags = [
diff --git a/chromium/ui/base/accelerators/accelerator.cc b/chromium/ui/base/accelerators/accelerator.cc
index d56e87be04c..bf214d0b04e 100644
--- a/chromium/ui/base/accelerators/accelerator.cc
+++ b/chromium/ui/base/accelerators/accelerator.cc
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event.h"
+#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/strings/grit/ui_strings.h"
#if defined(OS_WIN)
@@ -161,7 +162,7 @@ base::string16 Accelerator::GetShortcutText() const {
else
key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
shortcut += key;
-#elif defined(USE_AURA) || defined(OS_MACOSX)
+#elif defined(USE_AURA) || defined(OS_MACOSX) || defined(OS_ANDROID)
const uint16_t c = DomCodeToUsLayoutCharacter(
UsLayoutKeyboardCodeToDomCode(key_code_), false);
if (c != 0)
diff --git a/chromium/ui/base/accelerators/accelerator_unittest.cc b/chromium/ui/base/accelerators/accelerator_unittest.cc
index c286581f38c..f86c3caa634 100644
--- a/chromium/ui/base/accelerators/accelerator_unittest.cc
+++ b/chromium/ui/base/accelerators/accelerator_unittest.cc
@@ -35,13 +35,7 @@ TEST(AcceleratorTest, TimeStamp) {
EXPECT_EQ(event_time, accelerator_b.time_stamp());
}
-#if defined(OS_ANDROID)
-// Keyboard shortcuts don't have meaningful text on Android.
-#define MAYBE_GetShortcutText DISABLED_GetShortcutText
-#else
-#define MAYBE_GetShortcutText GetShortcutText
-#endif
-TEST(AcceleratorTest, MAYBE_GetShortcutText) {
+TEST(AcceleratorTest, GetShortcutText) {
struct {
KeyboardCode code;
int modifiers;
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util.cc b/chromium/ui/base/accelerators/menu_label_accelerator_util.cc
index 45c2bb61d4f..4be00ab2309 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util.cc
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util.cc
@@ -5,6 +5,7 @@
#include "ui/base/accelerators/menu_label_accelerator_util.h"
#include "base/i18n/case_conversion.h"
+#include "base/strings/string_util.h"
namespace ui {
@@ -31,4 +32,12 @@ base::char16 GetMnemonic(const base::string16& label) {
return 0;
}
+base::string16 EscapeMenuLabelAmpersands(const base::string16& label) {
+ base::string16 ret;
+ static const base::char16 kAmps[] = {'&', 0};
+ static const base::char16 kTwoAmps[] = {'&', '&', 0};
+ base::ReplaceChars(label, kAmps, kTwoAmps, &ret);
+ return ret;
+}
+
} // namespace ui
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util.h b/chromium/ui/base/accelerators/menu_label_accelerator_util.h
index 9344acb99ec..d70b21b6a34 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util.h
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util.h
@@ -14,6 +14,11 @@ namespace ui {
UI_BASE_EXPORT base::char16 GetMnemonic(const base::string16& label);
+// This function escapes every '&' in label by replacing it with '&&', to avoid
+// having single ampersands in user-provided strings treated as accelerators.
+UI_BASE_EXPORT base::string16 EscapeMenuLabelAmpersands(
+ const base::string16& label);
+
} // namespace ui
#endif // UI_BASE_ACCELERATORS_MENU_LABEL_ACCELERATOR_UTIL_H_
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.cc b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.cc
index 1213ec1dc7a..fd18abc737d 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.cc
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.cc
@@ -6,8 +6,6 @@
#include <stddef.h>
-#include "base/strings/string_util.h"
-
namespace {
// Common implementation of ConvertAcceleratorsFromWindowsStyle() and
@@ -51,14 +49,4 @@ std::string RemoveWindowsStyleAccelerators(const std::string& label) {
return ConvertAmpersandsTo(label, std::string());
}
-// Replaces all ampersands in |label| with two ampersands. This effectively
-// escapes strings for later processing by ConvertAmpersandsTo(), so that
-// ConvertAmpersandsTo(EscapeWindowsStyleAccelerators(x), *) is |x| with
-// underscores doubled, making the string that appears to the user just |x|.
-std::string EscapeWindowsStyleAccelerators(const std::string& label) {
- std::string ret;
- base::ReplaceChars(label, "&", "&&", &ret);
- return ret;
-}
-
} // namespace ui
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h
index bd8d3cf14aa..3d1c5d073f5 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux.h
@@ -20,12 +20,6 @@ UI_BASE_EXPORT std::string ConvertAcceleratorsFromWindowsStyle(
UI_BASE_EXPORT std::string RemoveWindowsStyleAccelerators(
const std::string& label);
-// Escapes "&" characters by doubling them so that later calling
-// ConvertAcceleratorsFromWindowsStyle() will return the original string (except
-// with "_" characters doubled, to escape them for GTK).
-UI_BASE_EXPORT std::string EscapeWindowsStyleAccelerators(
- const std::string& label);
-
} // namespace ui
#endif // UI_BASE_ACCELERATORS_MENU_LABEL_ACCELERATOR_UTIL_LINUX_H_
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux_unittest.cc b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux_unittest.cc
index d704ef5ce51..969b5245b1b 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util_linux_unittest.cc
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util_linux_unittest.cc
@@ -49,29 +49,4 @@ TEST(MenuLabelAcceleratorTest, RemoveWindowsStyleAccelerators) {
}
}
-TEST(MenuLabelAcceleratorTest, EscapeWindowsStyleAccelerators) {
- static const struct {
- const char* input;
- const char* output;
- } cases[] = {
- { "nothing", "nothing" },
- { "foo &bar", "foo &&bar" },
- { "foo &&bar", "foo &&&&bar" },
- { "foo &&&bar", "foo &&&&&&bar" },
- { "&foo bar", "&&foo bar" },
- { "&&foo bar", "&&&&foo bar" },
- { "&&&foo bar", "&&&&&&foo bar" },
- { "&foo &bar", "&&foo &&bar" },
- { "&&foo &&bar", "&&&&foo &&&&bar" },
- { "f&o&o ba&r", "f&&o&&o ba&&r" },
- { "foo_&_bar", "foo_&&_bar" },
- { "&_foo_bar_&", "&&_foo_bar_&&" },
- };
-
- for (size_t i = 0; i < arraysize(cases); ++i) {
- std::string result = EscapeWindowsStyleAccelerators(cases[i].input);
- EXPECT_EQ(cases[i].output, result);
- }
-}
-
} // namespace ui
diff --git a/chromium/ui/base/accelerators/menu_label_accelerator_util_unittest.cc b/chromium/ui/base/accelerators/menu_label_accelerator_util_unittest.cc
index 5f788cd8586..8d4b64d8ec2 100644
--- a/chromium/ui/base/accelerators/menu_label_accelerator_util_unittest.cc
+++ b/chromium/ui/base/accelerators/menu_label_accelerator_util_unittest.cc
@@ -22,4 +22,30 @@ TEST(MenuLabelAcceleratorTest, GetMnemonic) {
EXPECT_EQ(GetMnemonic(test.label), test.mneumonic);
}
+TEST(MenuLabelAcceleratorTest, EscapeMenuLabelAmpersands) {
+ static const struct {
+ const char* input;
+ const char* output;
+ } cases[] = {
+ {"nothing", "nothing"},
+ {"foo &bar", "foo &&bar"},
+ {"foo &&bar", "foo &&&&bar"},
+ {"foo &&&bar", "foo &&&&&&bar"},
+ {"&foo bar", "&&foo bar"},
+ {"&&foo bar", "&&&&foo bar"},
+ {"&&&foo bar", "&&&&&&foo bar"},
+ {"&foo &bar", "&&foo &&bar"},
+ {"&&foo &&bar", "&&&&foo &&&&bar"},
+ {"f&o&o ba&r", "f&&o&&o ba&&r"},
+ {"foo_&_bar", "foo_&&_bar"},
+ {"&_foo_bar_&", "&&_foo_bar_&&"},
+ };
+
+ for (const auto& test : cases) {
+ base::string16 in = base::ASCIIToUTF16(test.input);
+ base::string16 out = base::ASCIIToUTF16(test.output);
+ EXPECT_EQ(out, EscapeMenuLabelAmpersands(in));
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/base/base_window.h b/chromium/ui/base/base_window.h
index 8d4dd05dfae..bbb7e280451 100644
--- a/chromium/ui/base/base_window.h
+++ b/chromium/ui/base/base_window.h
@@ -10,15 +10,6 @@
#include "ui/base/ui_base_types.h" // WindowShowState
#include "ui/gfx/native_widget_types.h"
-#if defined(OS_WIN)
-// Names used in this class are also windows.h macros. That the names
-// are the same as in the Windows API is no coincidence but for now we
-// don't want the Windows macros to interfere so we undef them.
-#undef IsMinimized
-#undef IsMaximized
-#undef IsRestored
-#endif // OS_WIN
-
namespace gfx {
class Rect;
}
diff --git a/chromium/ui/base/class_property.cc b/chromium/ui/base/class_property.cc
index 01941edfd31..4aea304135b 100644
--- a/chromium/ui/base/class_property.cc
+++ b/chromium/ui/base/class_property.cc
@@ -67,4 +67,4 @@ std::set<const void*> PropertyHandler::GetAllPropertyKeys() const {
return keys;
}
-} // namespace ui \ No newline at end of file
+} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard.cc b/chromium/ui/base/clipboard/clipboard.cc
index 38665261399..a621d64fa9e 100644
--- a/chromium/ui/base/clipboard/clipboard.cc
+++ b/chromium/ui/base/clipboard/clipboard.cc
@@ -64,6 +64,24 @@ Clipboard* Clipboard::GetForCurrentThread() {
}
// static
+std::unique_ptr<Clipboard> Clipboard::TakeForCurrentThread() {
+ base::AutoLock lock(clipboard_map_lock_.Get());
+
+ ClipboardMap* clipboard_map = clipboard_map_.Pointer();
+ base::PlatformThreadId id = base::PlatformThread::CurrentId();
+
+ Clipboard* clipboard = nullptr;
+
+ auto it = clipboard_map->find(id);
+ if (it != clipboard_map->end()) {
+ clipboard = it->second.release();
+ clipboard_map->erase(it);
+ }
+
+ return base::WrapUnique(clipboard);
+}
+
+// static
void Clipboard::OnPreShutdownForCurrentThread() {
base::AutoLock lock(clipboard_map_lock_.Get());
base::PlatformThreadId id = GetAndValidateThreadID();
diff --git a/chromium/ui/base/clipboard/clipboard.h b/chromium/ui/base/clipboard/clipboard.h
index d76a66d657b..60410973f82 100644
--- a/chromium/ui/base/clipboard/clipboard.h
+++ b/chromium/ui/base/clipboard/clipboard.h
@@ -142,6 +142,10 @@ class UI_BASE_EXPORT Clipboard : public base::ThreadChecker {
// the IO thread.
static Clipboard* GetForCurrentThread();
+ // Removes and transfers ownership of the current thread's clipboard to the
+ // caller. If the clipboard was never initialized, returns nullptr.
+ static std::unique_ptr<Clipboard> TakeForCurrentThread();
+
// Does any work necessary prior to Chrome shutdown for the current thread.
// All platforms but Windows have a single clipboard shared accross all
// threads. This function is a no-op on Windows. On Desktop Linux, if Chrome
diff --git a/chromium/ui/base/clipboard/clipboard_android.cc b/chromium/ui/base/clipboard/clipboard_android.cc
index c1fada750f6..6fe4940555d 100644
--- a/chromium/ui/base/clipboard/clipboard_android.cc
+++ b/chromium/ui/base/clipboard/clipboard_android.cc
@@ -497,10 +497,8 @@ void ClipboardAndroid::WriteObjects(ClipboardType type,
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
g_map.Get().Clear();
- for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
- ++iter) {
- DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
- }
+ for (const auto& object : objects)
+ DispatchObject(static_cast<ObjectType>(object.first), object.second);
g_map.Get().CommitToAndroidClipboard();
}
diff --git a/chromium/ui/base/clipboard/clipboard_aura.cc b/chromium/ui/base/clipboard/clipboard_aura.cc
index f185182cb36..202a1963b0d 100644
--- a/chromium/ui/base/clipboard/clipboard_aura.cc
+++ b/chromium/ui/base/clipboard/clipboard_aura.cc
@@ -17,6 +17,7 @@
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
+#include "skia/ext/skia_utils_base.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/custom_data_helper.h"
@@ -92,9 +93,9 @@ class ClipboardData {
const SkBitmap& bitmap() const { return bitmap_; }
void SetBitmapData(const SkBitmap& bitmap) {
- if (bitmap_.tryAllocPixels(bitmap.info())) {
- bitmap.readPixels(bitmap_.info(), bitmap_.getPixels(), bitmap_.rowBytes(),
- 0, 0);
+ if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &bitmap_)) {
+ NOTREACHED() << "Unable to convert bitmap for clipboard";
+ return;
}
format_ |= BITMAP;
}
@@ -152,6 +153,8 @@ class ClipboardData {
DISALLOW_COPY_AND_ASSIGN(ClipboardData);
};
+} // namespace
+
// Platform clipboard implementation for Aura. This handles things like format
// conversion, versioning of clipboard items etc. The goal is to roughly provide
// a substitute to platform clipboards on other platforms such as GtkClipboard
@@ -330,24 +333,11 @@ class AuraClipboard {
DISALLOW_COPY_AND_ASSIGN(AuraClipboard);
};
-AuraClipboard* g_aura_clipboard = NULL;
-
-AuraClipboard* GetClipboard() {
- if (!g_aura_clipboard)
- g_aura_clipboard = new AuraClipboard();
- return g_aura_clipboard;
-}
-
-void DeleteClipboard() {
- delete g_aura_clipboard;
- g_aura_clipboard = NULL;
-}
-
// Helper class to build a ClipboardData object and write it to clipboard.
class ClipboardDataBuilder {
public:
- static void CommitToClipboard() {
- GetClipboard()->WriteData(TakeCurrentData());
+ static void CommitToClipboard(AuraClipboard* clipboard) {
+ clipboard->WriteData(TakeCurrentData());
}
static void WriteText(const char* text_data, size_t text_len) {
@@ -414,8 +404,6 @@ class ClipboardDataBuilder {
ClipboardData* ClipboardDataBuilder::current_data_ = nullptr;
-} // namespace
-
// Clipboard::FormatType implementation.
Clipboard::FormatType::FormatType() {
}
@@ -533,49 +521,45 @@ Clipboard* Clipboard::Create() {
}
// ClipboardAura implementation.
-ClipboardAura::ClipboardAura() {
+ClipboardAura::ClipboardAura()
+ : clipboard_internal_(std::make_unique<AuraClipboard>()) {
DCHECK(CalledOnValidThread());
- // Make sure clipboard is created.
- GetClipboard();
}
ClipboardAura::~ClipboardAura() {
DCHECK(CalledOnValidThread());
- DeleteClipboard();
}
void ClipboardAura::OnPreShutdown() {}
uint64_t ClipboardAura::GetSequenceNumber(ClipboardType type) const {
DCHECK(CalledOnValidThread());
- return GetClipboard()->sequence_number();
+ return clipboard_internal_->sequence_number();
}
bool ClipboardAura::IsFormatAvailable(const FormatType& format,
ClipboardType type) const {
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardType(type));
- AuraClipboard* clipboard = GetClipboard();
if (GetPlainTextFormatType().Equals(format) ||
GetUrlFormatType().Equals(format))
- return clipboard->IsFormatAvailable(TEXT);
+ return clipboard_internal_->IsFormatAvailable(TEXT);
if (GetHtmlFormatType().Equals(format))
- return clipboard->IsFormatAvailable(HTML);
+ return clipboard_internal_->IsFormatAvailable(HTML);
if (GetRtfFormatType().Equals(format))
- return clipboard->IsFormatAvailable(RTF);
+ return clipboard_internal_->IsFormatAvailable(RTF);
if (GetBitmapFormatType().Equals(format))
- return clipboard->IsFormatAvailable(BITMAP);
+ return clipboard_internal_->IsFormatAvailable(BITMAP);
if (GetWebKitSmartPasteFormatType().Equals(format))
- return clipboard->IsFormatAvailable(WEB);
- const ClipboardData* data = clipboard->GetData();
+ return clipboard_internal_->IsFormatAvailable(WEB);
+ const ClipboardData* data = clipboard_internal_->GetData();
return data && data->custom_data_format() == format.ToString();
}
void ClipboardAura::Clear(ClipboardType type) {
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardType(type));
- AuraClipboard* clipboard = GetClipboard();
- clipboard->Clear();
+ clipboard_internal_->Clear();
}
void ClipboardAura::ReadAvailableTypes(ClipboardType type,
@@ -598,22 +582,23 @@ void ClipboardAura::ReadAvailableTypes(ClipboardType type,
if (IsFormatAvailable(GetBitmapFormatType(), type))
types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
- AuraClipboard* clipboard = GetClipboard();
- if (clipboard->IsFormatAvailable(CUSTOM) && clipboard->GetData()) {
- ui::ReadCustomDataTypes(clipboard->GetData()->custom_data_data().c_str(),
- clipboard->GetData()->custom_data_data().size(), types);
+ if (clipboard_internal_->IsFormatAvailable(CUSTOM) &&
+ clipboard_internal_->GetData()) {
+ ui::ReadCustomDataTypes(
+ clipboard_internal_->GetData()->custom_data_data().c_str(),
+ clipboard_internal_->GetData()->custom_data_data().size(), types);
}
}
void ClipboardAura::ReadText(ClipboardType type, base::string16* result) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadText(result);
+ clipboard_internal_->ReadText(result);
}
void ClipboardAura::ReadAsciiText(ClipboardType type,
std::string* result) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadAsciiText(result);
+ clipboard_internal_->ReadAsciiText(result);
}
void ClipboardAura::ReadHTML(ClipboardType type,
@@ -622,46 +607,44 @@ void ClipboardAura::ReadHTML(ClipboardType type,
uint32_t* fragment_start,
uint32_t* fragment_end) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadHTML(markup, src_url, fragment_start, fragment_end);
+ clipboard_internal_->ReadHTML(markup, src_url, fragment_start, fragment_end);
}
void ClipboardAura::ReadRTF(ClipboardType type, std::string* result) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadRTF(result);
+ clipboard_internal_->ReadRTF(result);
}
SkBitmap ClipboardAura::ReadImage(ClipboardType type) const {
DCHECK(CalledOnValidThread());
- return GetClipboard()->ReadImage();
+ return clipboard_internal_->ReadImage();
}
void ClipboardAura::ReadCustomData(ClipboardType clipboard_type,
const base::string16& type,
base::string16* result) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadCustomData(type, result);
+ clipboard_internal_->ReadCustomData(type, result);
}
void ClipboardAura::ReadBookmark(base::string16* title,
std::string* url) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadBookmark(title, url);
+ clipboard_internal_->ReadBookmark(title, url);
}
void ClipboardAura::ReadData(const FormatType& format,
std::string* result) const {
DCHECK(CalledOnValidThread());
- GetClipboard()->ReadData(format.ToString(), result);
+ clipboard_internal_->ReadData(format.ToString(), result);
}
void ClipboardAura::WriteObjects(ClipboardType type, const ObjectMap& objects) {
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardType(type));
- for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
- ++iter) {
- DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
- }
- ClipboardDataBuilder::CommitToClipboard();
+ for (const auto& object : objects)
+ DispatchObject(static_cast<ObjectType>(object.first), object.second);
+ ClipboardDataBuilder::CommitToClipboard(clipboard_internal_.get());
}
void ClipboardAura::WriteText(const char* text_data, size_t text_len) {
diff --git a/chromium/ui/base/clipboard/clipboard_aura.h b/chromium/ui/base/clipboard/clipboard_aura.h
index dc65413435c..1d3b2083309 100644
--- a/chromium/ui/base/clipboard/clipboard_aura.h
+++ b/chromium/ui/base/clipboard/clipboard_aura.h
@@ -13,10 +13,11 @@
namespace ui {
+class AuraClipboard;
+
class ClipboardAura : public Clipboard {
private:
friend class Clipboard;
-
ClipboardAura();
~ClipboardAura() override;
@@ -60,6 +61,8 @@ class ClipboardAura : public Clipboard {
const char* data_data,
size_t data_len) override;
+ const std::unique_ptr<AuraClipboard> clipboard_internal_;
+
DISALLOW_COPY_AND_ASSIGN(ClipboardAura);
};
diff --git a/chromium/ui/base/clipboard/clipboard_aurax11.cc b/chromium/ui/base/clipboard/clipboard_aurax11.cc
index 4e767fcd9d9..447beb5bc09 100644
--- a/chromium/ui/base/clipboard/clipboard_aurax11.cc
+++ b/chromium/ui/base/clipboard/clipboard_aurax11.cc
@@ -147,9 +147,8 @@ TargetList::TargetList(const AtomVector& target_list)
bool TargetList::ContainsText() const {
std::vector<::Atom> atoms = GetTextAtomsFrom();
- for (std::vector< ::Atom>::const_iterator it = atoms.begin();
- it != atoms.end(); ++it) {
- if (ContainsAtom(*it))
+ for (const auto& atom : atoms) {
+ if (ContainsAtom(atom))
return true;
}
@@ -379,8 +378,8 @@ SelectionData ClipboardAuraX11::AuraX11Details::RequestAndWaitForTypes(
// with the X server.
const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
- for (auto it = types.begin(); it != types.end(); ++it) {
- auto format_map_it = format_map.find(*it);
+ for (const auto& type : types) {
+ auto format_map_it = format_map.find(type);
if (format_map_it != format_map.end())
return SelectionData(format_map_it->first, format_map_it->second);
}
@@ -405,9 +404,8 @@ TargetList ClipboardAuraX11::AuraX11Details::WaitAndGetTargetsList(
// We can local fastpath and return the list of local targets.
const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name);
- for (auto it = format_map.begin(); it != format_map.end(); ++it) {
- out.push_back(it->first);
- }
+ for (const auto& format : format_map)
+ out.push_back(format.first);
} else {
scoped_refptr<base::RefCountedMemory> data;
size_t out_data_items = 0;
@@ -431,16 +429,12 @@ TargetList ClipboardAuraX11::AuraX11Details::WaitAndGetTargetsList(
// copy the data to see if it is available, but at least this path
// shouldn't be hit for conforming programs.
std::vector< ::Atom> types = GetTextAtoms();
- for (std::vector< ::Atom>::const_iterator it = types.begin();
- it != types.end(); ++it) {
+ for (const auto& text_atom : types) {
::Atom type = x11::None;
- if (selection_requestor_.PerformBlockingConvertSelection(selection_name,
- *it,
- NULL,
- NULL,
- &type) &&
- type == *it) {
- out.push_back(*it);
+ if (selection_requestor_.PerformBlockingConvertSelection(
+ selection_name, text_atom, NULL, NULL, &type) &&
+ type == text_atom) {
+ out.push_back(text_atom);
}
}
}
@@ -812,9 +806,8 @@ void ClipboardAuraX11::WriteObjects(ClipboardType type,
DCHECK(IsSupportedClipboardType(type));
aurax11_details_->CreateNewClipboardData();
- for (auto iter = objects.begin(); iter != objects.end(); ++iter) {
- DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
- }
+ for (const auto& object : objects)
+ DispatchObject(static_cast<ObjectType>(object.first), object.second);
aurax11_details_->TakeOwnershipOfSelection(type);
if (type == CLIPBOARD_TYPE_COPY_PASTE) {
diff --git a/chromium/ui/base/clipboard/clipboard_mac.mm b/chromium/ui/base/clipboard/clipboard_mac.mm
index e9abab846ec..267743860ce 100644
--- a/chromium/ui/base/clipboard/clipboard_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_mac.mm
@@ -18,6 +18,7 @@
#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "skia/ext/skia_utils_base.h"
#include "skia/ext/skia_utils_mac.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -214,7 +215,7 @@ void ClipboardMac::Clear(ClipboardType type) {
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
NSPasteboard* pb = GetPasteboard();
- [pb declareTypes:[NSArray array] owner:nil];
+ [pb declareTypes:@[] owner:nil];
}
void ClipboardMac::ReadAvailableTypes(ClipboardType type,
@@ -277,15 +278,15 @@ void ClipboardMac::ReadHTML(ClipboardType type,
src_url->clear();
NSPasteboard* pb = GetPasteboard();
- NSArray* supportedTypes = [NSArray arrayWithObjects:NSHTMLPboardType,
- NSRTFPboardType,
- NSPasteboardTypeString,
- nil];
+ NSArray* supportedTypes =
+ @[ NSHTMLPboardType, NSRTFPboardType, NSPasteboardTypeString ];
NSString* bestType = [pb availableTypeFromArray:supportedTypes];
if (bestType) {
- NSString* contents = [pb stringForType:bestType];
+ NSString* contents;
if ([bestType isEqualToString:NSRTFPboardType])
- contents = [pb htmlFromRtf];
+ contents = ClipboardUtil::GetHTMLFromRTFOnPasteboard(pb);
+ else
+ contents = [pb stringForType:bestType];
*markup = base::SysNSStringToUTF16(contents);
}
@@ -337,7 +338,7 @@ SkBitmap ClipboardMac::ReadImage(ClipboardType type, NSPasteboard* pb) const {
// the way through to the web, but the clipboard API doesn't support the
// additional metainformation.
if ([[image representations] count] == 1u) {
- NSImageRep* rep = [[image representations] objectAtIndex:0];
+ NSImageRep* rep = [image representations][0];
NSInteger width = [rep pixelsWide];
NSInteger height = [rep pixelsHigh];
if (width != 0 && height != 0) {
@@ -400,7 +401,7 @@ void ClipboardMac::WriteObjects(ClipboardType type, const ObjectMap& objects) {
DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
NSPasteboard* pb = GetPasteboard();
- [pb declareTypes:[NSArray array] owner:nil];
+ [pb declareTypes:@[] owner:nil];
for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
++iter) {
@@ -412,7 +413,7 @@ void ClipboardMac::WriteText(const char* text_data, size_t text_len) {
std::string text_str(text_data, text_len);
NSString* text = base::SysUTF8ToNSString(text_str);
NSPasteboard* pb = GetPasteboard();
- [pb addTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
+ [pb addTypes:@[ NSPasteboardTypeString ] owner:nil];
[pb setString:text forType:NSPasteboardTypeString];
}
@@ -427,7 +428,7 @@ void ClipboardMac::WriteHTML(const char* markup_data,
// TODO(avi): url_data?
NSPasteboard* pb = GetPasteboard();
- [pb addTypes:[NSArray arrayWithObject:NSHTMLPboardType] owner:nil];
+ [pb addTypes:@[ NSHTMLPboardType ] owner:nil];
[pb setString:html_fragment forType:NSHTMLPboardType];
}
@@ -451,12 +452,22 @@ void ClipboardMac::WriteBookmark(const char* title_data,
}
void ClipboardMac::WriteBitmap(const SkBitmap& bitmap) {
+ SkBitmap out_bitmap;
+ if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &out_bitmap)) {
+ NOTREACHED() << "Unable to convert bitmap for clipboard";
+ return;
+ }
+
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
- bitmap, base::mac::GetSystemColorSpace());
+ out_bitmap, base::mac::GetSystemColorSpace());
+ if (!image) {
+ NOTREACHED() << "SkBitmapToNSImageWithColorSpace failed";
+ return;
+ }
// An API to ask the NSImage to write itself to the clipboard comes in 10.6 :(
// For now, spit out the image as a TIFF.
NSPasteboard* pb = GetPasteboard();
- [pb addTypes:[NSArray arrayWithObject:NSTIFFPboardType] owner:nil];
+ [pb addTypes:@[ NSTIFFPboardType ] owner:nil];
NSData* tiff_data = [image TIFFRepresentation];
LOG_IF(ERROR, tiff_data == NULL) << "Failed to allocate image for clipboard";
if (tiff_data) {
@@ -468,7 +479,7 @@ void ClipboardMac::WriteData(const FormatType& format,
const char* data_data,
size_t data_len) {
NSPasteboard* pb = GetPasteboard();
- [pb addTypes:[NSArray arrayWithObject:format.ToNSString()] owner:nil];
+ [pb addTypes:@[ format.ToNSString() ] owner:nil];
[pb setData:[NSData dataWithBytes:data_data length:data_len]
forType:format.ToNSString()];
}
@@ -478,7 +489,7 @@ void ClipboardMac::WriteData(const FormatType& format,
void ClipboardMac::WriteWebSmartPaste() {
NSPasteboard* pb = GetPasteboard();
NSString* format = GetWebKitSmartPasteFormatType().ToNSString();
- [pb addTypes:[NSArray arrayWithObject:format] owner:nil];
+ [pb addTypes:@[ format ] owner:nil];
[pb setData:nil forType:format];
}
diff --git a/chromium/ui/base/clipboard/clipboard_test_template.h b/chromium/ui/base/clipboard/clipboard_test_template.h
index 65270477f08..fd0dcc60cf9 100644
--- a/chromium/ui/base/clipboard/clipboard_test_template.h
+++ b/chromium/ui/base/clipboard/clipboard_test_template.h
@@ -12,6 +12,9 @@
// TODO(dcheng): This is really horrible. In general, all tests should run on
// all platforms, to avoid this mess.
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_
+
#include <stdint.h>
#include <memory>
@@ -34,6 +37,7 @@
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/test/test_clipboard.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/half_float.h"
#if defined(OS_WIN)
#include "ui/base/clipboard/clipboard_util_win.h"
@@ -376,14 +380,20 @@ TYPED_TEST(ClipboardTest, URLTest) {
#endif
}
+namespace {
+
+using U8x4 = std::array<uint8_t, 4>;
+using F16x4 = std::array<gfx::HalfFloat, 4>;
+
+template <typename T>
static void TestBitmapWrite(Clipboard* clipboard,
- const gfx::Size& size,
- const uint32_t* bitmap_data) {
+ const SkImageInfo& info,
+ const T* bitmap_data,
+ const U8x4* expect_data) {
{
ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE);
SkBitmap bitmap;
- ASSERT_TRUE(bitmap.setInfo(
- SkImageInfo::MakeN32Premul(size.width(), size.height())));
+ ASSERT_TRUE(bitmap.setInfo(info));
bitmap.setPixels(
const_cast<void*>(reinterpret_cast<const void*>(bitmap_data)));
scw.WriteImage(bitmap);
@@ -392,43 +402,120 @@ static void TestBitmapWrite(Clipboard* clipboard,
EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(),
CLIPBOARD_TYPE_COPY_PASTE));
const SkBitmap& image = clipboard->ReadImage(CLIPBOARD_TYPE_COPY_PASTE);
- EXPECT_EQ(size, gfx::Size(image.width(), image.height()));
- for (int j = 0; j < image.height(); ++j) {
- const uint32_t* row_address = image.getAddr32(0, j);
- for (int i = 0; i < image.width(); ++i) {
- int offset = i + j * image.width();
- EXPECT_EQ(bitmap_data[offset], row_address[i]) << "i = " << i
- << ", j = " << j;
+ ASSERT_EQ(image.info().colorType(), kN32_SkColorType);
+ ASSERT_NE(image.info().alphaType(), kUnpremul_SkAlphaType);
+ EXPECT_EQ(gfx::Size(info.width(), info.height()),
+ gfx::Size(image.width(), image.height()));
+ for (int y = 0; y < image.height(); ++y) {
+ const U8x4* actual_row =
+ reinterpret_cast<const U8x4*>(image.getAddr32(0, y));
+ const U8x4* expect_row = &expect_data[y * info.width()];
+ for (int x = 0; x < image.width(); ++x) {
+ EXPECT_EQ(expect_row[x], actual_row[x]) << "x = " << x << ", y = " << y;
}
}
}
-TYPED_TEST(ClipboardTest, SharedBitmapTest) {
- const uint32_t fake_bitmap_1[] = {
- 0x46061626, 0xf69f5988, 0x793f2937, 0xfa55b986,
- 0x78772152, 0x87692a30, 0x36322a25, 0x4320401b,
- 0x91848c21, 0xc3177b3c, 0x6946155c, 0x64171952,
- };
- {
- SCOPED_TRACE("first bitmap");
- TestBitmapWrite(&this->clipboard(), gfx::Size(4, 3), fake_bitmap_1);
- }
+constexpr U8x4 kRGBAUnpremul = {0x8a, 0x50, 0x15, 0x46};
+constexpr U8x4 kRGBAPremul = {0x26, 0x16, 0x06, 0x46};
+constexpr U8x4 kRGBAOpaque = {0x26, 0x16, 0x06, 0xff};
+constexpr U8x4 kBGRAUnpremul = {0x15, 0x50, 0x8a, 0x46};
+constexpr U8x4 kBGRAPremul = {0x06, 0x16, 0x26, 0x46};
+constexpr U8x4 kBGRAOpaque = {0x06, 0x16, 0x26, 0xff};
+constexpr F16x4 kRGBAF16Unpremul = {0x3854, 0x3505, 0x2d45, 0x3464};
+constexpr F16x4 kRGBAF16Premul = {0x30c5, 0x2d86, 0x2606, 0x3464};
+constexpr F16x4 kRGBAF16Opaque = {0x30c5, 0x2d86, 0x2606, 0x3c00};
+
+constexpr U8x4 kN32 =
+ (kN32_SkColorType == kRGBA_8888_SkColorType) ? kRGBAPremul : kBGRAPremul;
+constexpr U8x4 kN32Opaque =
+ (kN32_SkColorType == kRGBA_8888_SkColorType) ? kRGBAOpaque : kBGRAOpaque;
+
+// Either RGBA_8888 or BGRA_8888 will be equivalent to N32, but the other
+// won't be.
+TYPED_TEST(ClipboardTest, Bitmap_RGBA_Premul) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
+ &kRGBAPremul, &kN32);
+}
+TYPED_TEST(ClipboardTest, Bitmap_RGBA_Unpremul) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType),
+ &kRGBAUnpremul, &kN32);
+}
+TYPED_TEST(ClipboardTest, Bitmap_RGBA_Opaque) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kOpaque_SkAlphaType),
+ &kRGBAOpaque, &kN32Opaque);
+}
+TYPED_TEST(ClipboardTest, Bitmap_BGRA_Premul) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType),
+ &kBGRAPremul, &kN32);
+}
+TYPED_TEST(ClipboardTest, Bitmap_BGRA_Unpremul) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType),
+ &kBGRAUnpremul, &kN32);
+}
+TYPED_TEST(ClipboardTest, Bitmap_BGRA_Opaque) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kOpaque_SkAlphaType),
+ &kBGRAOpaque, &kN32Opaque);
+}
+
+// Used by HTMLCanvasElement.
+TYPED_TEST(ClipboardTest, Bitmap_F16_Premul) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType),
+ &kRGBAF16Premul, &kN32);
+}
+TYPED_TEST(ClipboardTest, Bitmap_F16_Unpremul) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType),
+ &kRGBAF16Unpremul, &kN32);
+}
+TYPED_TEST(ClipboardTest, Bitmap_F16_Opaque) {
+ TestBitmapWrite(
+ &this->clipboard(),
+ SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kOpaque_SkAlphaType),
+ &kRGBAF16Opaque, &kN32Opaque);
+}
- const uint32_t fake_bitmap_2[] = {
- 0x46061626, 0xf69f5988,
- 0x793f2937, 0xfa55b986,
- 0x78772152, 0x87692a30,
- 0x36322a25, 0x4320401b,
- 0x91848c21, 0xc3177b3c,
- 0x6946155c, 0x64171952,
- 0xa6910313, 0x8302323e,
+TYPED_TEST(ClipboardTest, Bitmap_N32_Premul) {
+ constexpr U8x4 b[4 * 3] = {
+ {0x26, 0x16, 0x06, 0x46}, {0x88, 0x59, 0x9f, 0xf6},
+ {0x37, 0x29, 0x3f, 0x79}, {0x86, 0xb9, 0x55, 0xfa},
+ {0x52, 0x21, 0x77, 0x78}, {0x30, 0x2a, 0x69, 0x87},
+ {0x25, 0x2a, 0x32, 0x36}, {0x1b, 0x40, 0x20, 0x43},
+ {0x21, 0x8c, 0x84, 0x91}, {0x3c, 0x7b, 0x17, 0xc3},
+ {0x5c, 0x15, 0x46, 0x69}, {0x52, 0x19, 0x17, 0x64},
};
- {
- SCOPED_TRACE("second bitmap");
- TestBitmapWrite(&this->clipboard(), gfx::Size(2, 7), fake_bitmap_2);
- }
+ TestBitmapWrite(&this->clipboard(), SkImageInfo::MakeN32Premul(4, 3), b, b);
+}
+TYPED_TEST(ClipboardTest, Bitmap_N32_Premul_2x7) {
+ constexpr U8x4 b[2 * 7] = {
+ {0x26, 0x16, 0x06, 0x46}, {0x88, 0x59, 0x9f, 0xf6},
+ {0x37, 0x29, 0x3f, 0x79}, {0x86, 0xb9, 0x55, 0xfa},
+ {0x52, 0x21, 0x77, 0x78}, {0x30, 0x2a, 0x69, 0x87},
+ {0x25, 0x2a, 0x32, 0x36}, {0x1b, 0x40, 0x20, 0x43},
+ {0x21, 0x8c, 0x84, 0x91}, {0x3c, 0x7b, 0x17, 0xc3},
+ {0x5c, 0x15, 0x46, 0x69}, {0x52, 0x19, 0x17, 0x64},
+ {0x13, 0x03, 0x91, 0xa6}, {0x3e, 0x32, 0x02, 0x83},
+ };
+ TestBitmapWrite(&this->clipboard(), SkImageInfo::MakeN32Premul(2, 7), b, b);
}
+} // namespace
+
TYPED_TEST(ClipboardTest, DataTest) {
const ui::Clipboard::FormatType kFormat =
ui::Clipboard::GetFormatType("chromium/x-test-format");
@@ -674,3 +761,5 @@ TYPED_TEST(ClipboardTest, WriteImageEmptyParams) {
}
} // namespace ui
+
+#endif // UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_ \ No newline at end of file
diff --git a/chromium/ui/base/clipboard/clipboard_util_mac.h b/chromium/ui/base/clipboard/clipboard_util_mac.h
index 31c459b1b08..29f927c3f31 100644
--- a/chromium/ui/base/clipboard/clipboard_util_mac.h
+++ b/chromium/ui/base/clipboard/clipboard_util_mac.h
@@ -63,16 +63,21 @@ class UI_BASE_EXPORT ClipboardUtil {
// and its associated data.
static void AddDataToPasteboard(NSPasteboard* pboard, NSPasteboardItem* item);
- // Returns whether the operation was succesful. On success, the two arrays are
- // guaranteed to be equal length, and are populated with strings of |urls| and
- // |titles|.
+ // Returns whether the operation was successful. On success, the two arrays
+ // are guaranteed to be equal length, and are populated with strings of |urls|
+ // and |titles|.
static bool URLsAndTitlesFromPasteboard(NSPasteboard* pboard,
NSArray** urls,
NSArray** titles);
// Gets the NSPasteboard specified from the clipboard type.
static NSPasteboard* PasteboardFromType(ui::ClipboardType type);
+
+ // If there is RTF data on the pasteboard, returns an HTML version of it.
+ // Otherwise returns nil.
+ static NSString* GetHTMLFromRTFOnPasteboard(NSPasteboard* pboard);
};
-}
+
+} // namespace ui
#endif // UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_MAC_H_
diff --git a/chromium/ui/base/clipboard/clipboard_util_mac.mm b/chromium/ui/base/clipboard/clipboard_util_mac.mm
index b7bf6229dda..3611b997d66 100644
--- a/chromium/ui/base/clipboard/clipboard_util_mac.mm
+++ b/chromium/ui/base/clipboard/clipboard_util_mac.mm
@@ -150,10 +150,8 @@ bool ClipboardUtil::URLsAndTitlesFromPasteboard(NSPasteboard* pboard,
if ([bookmarkPairs count] != 2)
return false;
- NSArray* urlsArr =
- base::mac::ObjCCast<NSArray>([bookmarkPairs objectAtIndex:0]);
- NSArray* titlesArr =
- base::mac::ObjCCast<NSArray>([bookmarkPairs objectAtIndex:1]);
+ NSArray* urlsArr = base::mac::ObjCCast<NSArray>(bookmarkPairs[0]);
+ NSArray* titlesArr = base::mac::ObjCCast<NSArray>(bookmarkPairs[1]);
if (!urlsArr || !titlesArr)
return false;
@@ -195,4 +193,25 @@ NSPasteboard* ClipboardUtil::PasteboardFromType(ui::ClipboardType type) {
return [NSPasteboard pasteboardWithName:type_string];
}
+// static
+NSString* ClipboardUtil::GetHTMLFromRTFOnPasteboard(NSPasteboard* pboard) {
+ NSData* rtfData = [pboard dataForType:NSRTFPboardType];
+ if (!rtfData)
+ return nil;
+
+ NSAttributedString* attributed =
+ [[[NSAttributedString alloc] initWithRTF:rtfData
+ documentAttributes:nil] autorelease];
+ NSData* htmlData =
+ [attributed dataFromRange:NSMakeRange(0, [attributed length])
+ documentAttributes:@{
+ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType
+ }
+ error:nil];
+
+ // According to the docs, NSHTMLTextDocumentType is UTF8.
+ return [[[NSString alloc] initWithData:htmlData
+ encoding:NSUTF8StringEncoding] autorelease];
+}
+
} // namespace ui
diff --git a/chromium/ui/base/clipboard/clipboard_util_mac_unittest.mm b/chromium/ui/base/clipboard/clipboard_util_mac_unittest.mm
index 9981d3c0e2f..a03f88e1eb7 100644
--- a/chromium/ui/base/clipboard/clipboard_util_mac_unittest.mm
+++ b/chromium/ui/base/clipboard/clipboard_util_mac_unittest.mm
@@ -21,7 +21,7 @@ class ClipboardUtilMacTest : public PlatformTest {
NSArray* types = [pboard types];
NSMutableDictionary* data = [NSMutableDictionary dictionary];
for (NSString* type in types) {
- [data setObject:[pboard dataForType:type] forKey:type];
+ data[type] = [pboard dataForType:type];
}
return data;
}
@@ -46,9 +46,9 @@ TEST_F(ClipboardUtilMacTest, PasteboardItemFromUrl) {
convertingTextToURL:NO];
ASSERT_EQ(1u, [urls count]);
- EXPECT_NSEQ(urlString, [urls objectAtIndex:0]);
+ EXPECT_NSEQ(urlString, urls[0]);
ASSERT_EQ(1u, [titles count]);
- EXPECT_NSEQ(urlString, [titles objectAtIndex:0]);
+ EXPECT_NSEQ(urlString, titles[0]);
NSURL* url = [NSURL URLFromPasteboard:pasteboard->get()];
EXPECT_NSEQ([url absoluteString], urlString);
@@ -71,9 +71,9 @@ TEST_F(ClipboardUtilMacTest, PasteboardItemWithTitle) {
convertingTextToURL:NO];
ASSERT_EQ(1u, [urls count]);
- EXPECT_NSEQ(urlString, [urls objectAtIndex:0]);
+ EXPECT_NSEQ(urlString, urls[0]);
ASSERT_EQ(1u, [titles count]);
- EXPECT_NSEQ(title, [titles objectAtIndex:0]);
+ EXPECT_NSEQ(title, titles[0]);
NSURL* url = [NSURL URLFromPasteboard:pasteboard->get()];
EXPECT_NSEQ([url absoluteString], urlString);
@@ -97,9 +97,9 @@ TEST_F(ClipboardUtilMacTest, PasteboardItemWithFilePath) {
convertingTextToURL:NO];
ASSERT_EQ(1u, [urls count]);
- EXPECT_NSEQ(urlString, [urls objectAtIndex:0]);
+ EXPECT_NSEQ(urlString, urls[0]);
ASSERT_EQ(1u, [titles count]);
- EXPECT_NSEQ(urlString, [titles objectAtIndex:0]);
+ EXPECT_NSEQ(urlString, titles[0]);
NSURL* urlFromPasteboard = [NSURL URLFromPasteboard:pasteboard->get()];
EXPECT_NSEQ(urlFromPasteboard, url);
diff --git a/chromium/ui/base/clipboard/clipboard_win.cc b/chromium/ui/base/clipboard/clipboard_win.cc
index e49dd8c8127..1857bfa07ce 100644
--- a/chromium/ui/base/clipboard/clipboard_win.cc
+++ b/chromium/ui/base/clipboard/clipboard_win.cc
@@ -25,6 +25,7 @@
#include "base/win/message_window.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
+#include "skia/ext/skia_utils_base.h"
#include "skia/ext/skia_utils_win.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_util_win.h"
@@ -422,7 +423,7 @@ Clipboard* Clipboard::Create() {
// ClipboardWin implementation.
ClipboardWin::ClipboardWin() {
- if (base::MessageLoopForUI::IsCurrent())
+ if (base::MessageLoopCurrentForUI::IsSet())
clipboard_owner_.reset(new base::win::MessageWindow());
}
@@ -805,9 +806,16 @@ void ClipboardWin::WriteWebSmartPaste() {
NULL);
}
-void ClipboardWin::WriteBitmap(const SkBitmap& bitmap) {
+void ClipboardWin::WriteBitmap(const SkBitmap& in_bitmap) {
HDC dc = ::GetDC(NULL);
+ SkBitmap bitmap;
+ // Either points bitmap at in_bitmap, or allocates and converts pixels.
+ if (!skia::SkBitmapToN32OpaqueOrPremul(in_bitmap, &bitmap)) {
+ NOTREACHED() << "Unable to convert bitmap for clipboard";
+ return;
+ }
+
// This doesn't actually cost us a memcpy when the bitmap comes from the
// renderer as we load it into the bitmap using setPixels which just sets a
// pointer. Someone has to memcpy it into GDI, it might as well be us here.
diff --git a/chromium/ui/base/cocoa/accessibility_focus_overrider.h b/chromium/ui/base/cocoa/accessibility_focus_overrider.h
new file mode 100644
index 00000000000..ad4de67f938
--- /dev/null
+++ b/chromium/ui/base/cocoa/accessibility_focus_overrider.h
@@ -0,0 +1,48 @@
+// 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_BASE_COCOA_ACCESSIBILITY_FOCUS_OVERRIDER_H_
+#define UI_BASE_COCOA_ACCESSIBILITY_FOCUS_OVERRIDER_H_
+
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// This object will swizzle -[NSApplication accessibilityFocusedUIElement] to
+// return the value of its client's GetAccessibilityFocusedUIElement method
+// whenever both |window_is_key_| is true and |view_is_first_responder_| is
+// true. If two instances both claim that their window is key and their view
+// is first responder at the same time, then the more recent instance to have
+// made that claim will "win". This mechanism is used for accessibility in
+// RemoteMacViews.
+class UI_BASE_EXPORT AccessibilityFocusOverrider {
+ public:
+ class Client {
+ public:
+ virtual id GetAccessibilityFocusedUIElement() = 0;
+ };
+
+ AccessibilityFocusOverrider(Client* client);
+ ~AccessibilityFocusOverrider();
+
+ // Indicate whether or not the view's window is currently key. This object
+ // will override the application's focused accessibility element only if its
+ // window is key (and the view is the window's first responder).
+ void SetWindowIsKey(bool window_is_key);
+
+ // Indicate whether or not the view is its window's first responder. This
+ // object will override the application's focused accessibility element only
+ // if the view is the window's first responder (and its window is key).
+ void SetViewIsFirstResponder(bool view_is_first_responder);
+
+ private:
+ void UpdateOverriddenKeyElement();
+ bool window_is_key_ = false;
+ bool view_is_first_responder_ = false;
+ Client* const client_;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_COCOA_ACCESSIBILITY_FOCUS_OVERRIDER_H_
diff --git a/chromium/ui/base/cocoa/accessibility_focus_overrider.mm b/chromium/ui/base/cocoa/accessibility_focus_overrider.mm
new file mode 100644
index 00000000000..fe3992c93b0
--- /dev/null
+++ b/chromium/ui/base/cocoa/accessibility_focus_overrider.mm
@@ -0,0 +1,62 @@
+// 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/base/cocoa/accessibility_focus_overrider.h"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+namespace ui {
+
+namespace {
+bool g_has_swizzled_method = false;
+AccessibilityFocusOverrider::Client* g_overridden_focused_element = nil;
+
+// Swizzled method for -[NSApplication accessibilityFocusedUIElement]. This
+// will return the overridden element if one is present. Otherwise, it will
+// return the key window.
+id SwizzledAccessibilityFocusedUIElement(NSApplication* app, SEL) {
+ if (g_overridden_focused_element)
+ return g_overridden_focused_element->GetAccessibilityFocusedUIElement();
+ return [[app keyWindow] accessibilityFocusedUIElement];
+}
+} // namespace
+
+AccessibilityFocusOverrider::AccessibilityFocusOverrider(Client* client)
+ : client_(client) {
+ if (!g_has_swizzled_method) {
+ Method method = class_getInstanceMethod(
+ [NSApplication class], @selector(accessibilityFocusedUIElement));
+ method_setImplementation(method,
+ (IMP)SwizzledAccessibilityFocusedUIElement);
+ g_has_swizzled_method = true;
+ }
+}
+
+AccessibilityFocusOverrider::~AccessibilityFocusOverrider() {
+ if (g_overridden_focused_element == client_)
+ g_overridden_focused_element = nullptr;
+}
+
+void AccessibilityFocusOverrider::SetWindowIsKey(bool window_is_key) {
+ window_is_key_ = window_is_key;
+ UpdateOverriddenKeyElement();
+}
+
+void AccessibilityFocusOverrider::SetViewIsFirstResponder(
+ bool view_is_first_responder) {
+ view_is_first_responder_ = view_is_first_responder;
+ UpdateOverriddenKeyElement();
+}
+
+void AccessibilityFocusOverrider::UpdateOverriddenKeyElement() {
+ if (window_is_key_ && view_is_first_responder_) {
+ g_overridden_focused_element = client_;
+ } else if (g_overridden_focused_element == client_) {
+ g_overridden_focused_element = nullptr;
+ }
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cocoa/bubble_closer.h b/chromium/ui/base/cocoa/bubble_closer.h
index 608d117b848..39a2f450d5a 100644
--- a/chromium/ui/base/cocoa/bubble_closer.h
+++ b/chromium/ui/base/cocoa/bubble_closer.h
@@ -22,8 +22,7 @@ class UI_BASE_EXPORT BubbleCloser {
public:
// Installs an event monitor watching for mouse clicks outside of |window| or
// any of its child windows. Invokes |on_click_outside| on each event.
- BubbleCloser(gfx::NativeWindow window,
- base::RepeatingClosure on_click_outside);
+ BubbleCloser(NSWindow* window, base::RepeatingClosure on_click_outside);
~BubbleCloser();
private:
diff --git a/chromium/ui/base/cocoa/bubble_closer.mm b/chromium/ui/base/cocoa/bubble_closer.mm
index 399bb46fd68..8587e504fd2 100644
--- a/chromium/ui/base/cocoa/bubble_closer.mm
+++ b/chromium/ui/base/cocoa/bubble_closer.mm
@@ -8,7 +8,7 @@
namespace ui {
-BubbleCloser::BubbleCloser(gfx::NativeWindow window,
+BubbleCloser::BubbleCloser(NSWindow* window,
base::RepeatingClosure on_click_outside)
: on_click_outside_(std::move(on_click_outside)), factory_(this) {
// Capture a WeakPtr via NSObject. This allows the block to detect another
diff --git a/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.h b/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.h
index 02962f8ae53..a73320ca2b1 100644
--- a/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.h
+++ b/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.h
@@ -17,7 +17,7 @@ UI_BASE_EXPORT
base::scoped_nsobject<NSWindow> window_;
}
-- (id)initWithWindow:(NSWindow*)window;
+- (instancetype)initWithWindow:(NSWindow*)window;
@end
diff --git a/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm b/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm
index b681b77ca68..c755c4f6a39 100644
--- a/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm
+++ b/chromium/ui/base/cocoa/constrained_window/constrained_window_animation.mm
@@ -84,7 +84,7 @@ NSPoint GetCGSWindowScreenOrigin(NSWindow* window) {
// Origin is relative to the screen with the menu bar (the screen at index 0).
// Note, this is not the same as mainScreen which is the screen with the key
// window.
- NSScreen* main_screen = [screens objectAtIndex:0];
+ NSScreen* main_screen = screens[0];
NSRect window_frame = [window frame];
NSRect screen_frame = [main_screen frame];
@@ -211,7 +211,7 @@ bool AreWindowServerEffectsDisabled() {
@implementation ConstrainedWindowAnimationBase
-- (id)initWithWindow:(NSWindow*)window {
+- (instancetype)initWithWindow:(NSWindow*)window {
if ((self = [self initWithDuration:kAnimationDuration
animationCurve:NSAnimationEaseInOut])) {
window_.reset([window retain]);
diff --git a/chromium/ui/base/cocoa/find_pasteboard.mm b/chromium/ui/base/cocoa/find_pasteboard.mm
index 536d8ccd767..6f27806b904 100644
--- a/chromium/ui/base/cocoa/find_pasteboard.mm
+++ b/chromium/ui/base/cocoa/find_pasteboard.mm
@@ -20,7 +20,7 @@ NSString* kFindPasteboardChangedNotification =
return instance;
}
-- (id)init {
+- (instancetype)init {
if ((self = [super init])) {
findText_.reset([[NSString alloc] init]);
@@ -66,8 +66,7 @@ NSString* kFindPasteboardChangedNotification =
if (needToSendNotification) {
findText_.reset([newText copy]);
NSPasteboard* findPboard = [self findPboard];
- [findPboard declareTypes:[NSArray arrayWithObject:NSStringPboardType]
- owner:nil];
+ [findPboard declareTypes:@[ NSStringPboardType ] owner:nil];
[findPboard setString:findText_.get() forType:NSStringPboardType];
[[NSNotificationCenter defaultCenter]
postNotificationName:kFindPasteboardChangedNotification
diff --git a/chromium/ui/base/cocoa/focus_tracker.h b/chromium/ui/base/cocoa/focus_tracker.h
index 301a48f37fd..439c7bab1f0 100644
--- a/chromium/ui/base/cocoa/focus_tracker.h
+++ b/chromium/ui/base/cocoa/focus_tracker.h
@@ -20,7 +20,7 @@ UI_BASE_EXPORT
// |window| is the window that we are saving focus for. This
// method snapshots the currently focused view.
-- (id)initWithWindow:(NSWindow*)window;
+- (instancetype)initWithWindow:(NSWindow*)window;
// Attempts to restore focus to the snapshotted view. Returns YES if
// focus was restored. Will not restore focus if the view is no
diff --git a/chromium/ui/base/cocoa/focus_tracker.mm b/chromium/ui/base/cocoa/focus_tracker.mm
index bf74b1a985c..8ec3498e912 100644
--- a/chromium/ui/base/cocoa/focus_tracker.mm
+++ b/chromium/ui/base/cocoa/focus_tracker.mm
@@ -7,7 +7,7 @@
@implementation FocusTracker
-- (id)initWithWindow:(NSWindow*)window {
+- (instancetype)initWithWindow:(NSWindow*)window {
if ((self = [super init])) {
NSResponder* current_focus = [window firstResponder];
diff --git a/chromium/ui/base/cocoa/focus_window_set.mm b/chromium/ui/base/cocoa/focus_window_set.mm
index a12b5503ee0..498df6e2951 100644
--- a/chromium/ui/base/cocoa/focus_window_set.mm
+++ b/chromium/ui/base/cocoa/focus_window_set.mm
@@ -13,7 +13,7 @@ namespace {
// This attempts to match OS X's native behavior, namely that a window
// is only ever deminiaturized if ALL windows on ALL workspaces are
// miniaturized.
-void FocusWindowSetHelper(const std::set<NSWindow*>& windows,
+void FocusWindowSetHelper(const std::set<gfx::NativeWindow>& windows,
bool allow_workspace_switch,
bool visible_windows_only) {
NSArray* ordered_windows = [NSApp orderedWindows];
@@ -22,7 +22,7 @@ void FocusWindowSetHelper(const std::set<NSWindow*>& windows,
NSWindow* frontmost_miniaturized_window = nil;
bool all_miniaturized = true;
for (int i = [ordered_windows count] - 1; i >= 0; i--) {
- NSWindow* win = [ordered_windows objectAtIndex:i];
+ NSWindow* win = ordered_windows[i];
if (windows.find(win) == windows.end())
continue;
if ([win isMiniaturized]) {
@@ -55,11 +55,11 @@ void FocusWindowSetHelper(const std::set<NSWindow*>& windows,
} // namespace
-void FocusWindowSet(const std::set<NSWindow*>& windows) {
+void FocusWindowSet(const std::set<gfx::NativeWindow>& windows) {
FocusWindowSetHelper(windows, true, true);
}
-void FocusWindowSetOnCurrentSpace(const std::set<NSWindow*>& windows) {
+void FocusWindowSetOnCurrentSpace(const std::set<gfx::NativeWindow>& windows) {
// This callback runs before AppKit picks its own window to
// deminiaturize, so we get to pick one from the right set. Limit to
// the windows on the current workspace. Otherwise we jump spaces
diff --git a/chromium/ui/base/cocoa/hover_button.h b/chromium/ui/base/cocoa/hover_button.h
deleted file mode 100644
index 9249a305a55..00000000000
--- a/chromium/ui/base/cocoa/hover_button.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_COCOA_HOVER_BUTTON_
-#define UI_BASE_COCOA_HOVER_BUTTON_
-
-#import <Cocoa/Cocoa.h>
-
-#import "ui/base/cocoa/tracking_area.h"
-#import "ui/base/ui_base_export.h"
-
-@class HoverButtonCocoa;
-
-// Assign an object which conforms to this protocol to a HoverButtonCocoa's
-// dragDelegate property to make the button draggable.
-UI_BASE_EXPORT
-@protocol HoverButtonDragDelegate
-
-// When the user performs a drag on the HoverButtonCocoa, this method will be
-// called with the button and the mouse down event. The delegate is expected to
-// begin a drag by calling -[NSView beginDraggingSessionWithItems:event:source:]
-// with the event or run a nested tracking loop. When it returns, the
-// HoverButtonCocoa returns to kHoverStateNone and stops tracking the mouse.
-- (void)beginDragFromHoverButton:(HoverButtonCocoa*)button
- event:(NSEvent*)event;
-
-@end
-
-// A button that changes when you hover over it and click it.
-UI_BASE_EXPORT
-@interface HoverButtonCocoa : NSButton {
- @protected
- // Enumeration of the hover states that the close button can be in at any one
- // time. The button cannot be in more than one hover state at a time.
- enum CloseButtonHoverState {
- kHoverStateNone = 0,
- kHoverStateMouseOver = 1,
- kHoverStateMouseDown = 2
- };
-
- CloseButtonHoverState hoverState_;
-
- @private
- // Tracking area for button mouseover states. Nil if not enabled.
- ui::ScopedCrTrackingArea trackingArea_;
- BOOL mouseDown_;
- BOOL sendActionOnMouseDown_;
-}
-
-@property(nonatomic) CloseButtonHoverState hoverState;
-
-// Enables or disables the tracking for the button.
-@property(nonatomic) BOOL trackingEnabled;
-
-// Assign an object to make the button a drag source.
-@property(nonatomic, assign) id<HoverButtonDragDelegate> dragDelegate;
-
-// Enables or disables sending the action on mouse down event.
-@property(nonatomic) BOOL sendActionOnMouseDown;
-
-// An NSRect in the view's coordinate space which is used for hover and hit
-// testing. Default value is NSZeroRect, which makes the hitbox equal to the
-// view's bounds. May be overridden by subclasses. Example: A button in the
-// corner of a fullscreen window might extend its hitbox to the edges of the
-// window so that it can be clicked more easily (Fitts's law).
-@property(readonly, nonatomic) NSRect hitbox;
-
-// Common initialization called from initWithFrame: and awakeFromNib.
-// Subclassers should call [super commonInit].
-- (void)commonInit;
-
-// Text that would be announced by screen readers.
-- (void)setAccessibilityTitle:(NSString*)accessibilityTitle;
-
-// Checks to see whether the mouse is in the button's bounds and update
-// the image in case it gets out of sync. This occurs to the close button
-// when you close a tab so the tab to the left of it takes its place, and
-// drag the button without moving the mouse before you press the button down.
-- (void)checkImageState;
-
-@end
-
-#endif // UI_BASE_COCOA_HOVER_BUTTON_
diff --git a/chromium/ui/base/cocoa/hover_button.mm b/chromium/ui/base/cocoa/hover_button.mm
deleted file mode 100644
index 42b3703de2b..00000000000
--- a/chromium/ui/base/cocoa/hover_button.mm
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright (c) 2010 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/base/cocoa/hover_button.h"
-
-#include <cmath>
-
-namespace {
-
-// Distance to start a drag when a dragDelegate is assigned.
-constexpr CGFloat kDragDistance = 5;
-
-} // namespace
-
-@implementation HoverButtonCocoa
-
-@synthesize hoverState = hoverState_;
-@synthesize trackingEnabled = trackingEnabled_;
-@synthesize dragDelegate = dragDelegate_;
-@synthesize sendActionOnMouseDown = sendActionOnMouseDown_;
-
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- [self commonInit];
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [self commonInit];
-}
-
-- (void)commonInit {
- self.hoverState = kHoverStateNone;
- self.trackingEnabled = YES;
-}
-
-- (void)dealloc {
- self.trackingEnabled = NO;
- [super dealloc];
-}
-
-- (NSRect)hitbox {
- return NSZeroRect;
-}
-
-- (void)setTrackingEnabled:(BOOL)trackingEnabled {
- if (trackingEnabled == trackingEnabled_)
- return;
- trackingEnabled_ = trackingEnabled;
- [self updateTrackingAreas];
-}
-
-- (void)setEnabled:(BOOL)enabled {
- if (enabled == self.enabled)
- return;
- super.enabled = enabled;
- [self updateTrackingAreas];
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
- if (trackingArea_.get())
- self.hoverState = kHoverStateMouseOver;
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
- [self checkImageState];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
- if (trackingArea_.get())
- self.hoverState = kHoverStateNone;
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
- if (!self.enabled)
- return;
- mouseDown_ = YES;
- self.hoverState = kHoverStateMouseDown;
-
- if (sendActionOnMouseDown_)
- [self sendAction:self.action to:self.target];
-
- // The hover button needs to hold onto itself here for a bit. Otherwise,
- // it can be freed while in the tracking loop below.
- // http://crbug.com/28220
- base::scoped_nsobject<HoverButtonCocoa> myself([self retain]);
-
- // Begin tracking the mouse.
- if ([theEvent type] == NSLeftMouseDown) {
- NSWindow* window = [self window];
- NSEvent* nextEvent = nil;
-
- // For the tracking loop ignore key events so that they don't pile up in
- // the queue and get processed after the user releases the mouse.
- const NSEventMask eventMask = (NSLeftMouseDraggedMask | NSLeftMouseUpMask |
- NSKeyDownMask | NSKeyUpMask);
-
- while ((nextEvent = [window nextEventMatchingMask:eventMask])) {
- if ([nextEvent type] == NSLeftMouseUp)
- break;
- // Update the image state, which will change if the user moves the mouse
- // into or out of the button.
- [self checkImageState];
- if (dragDelegate_ && [nextEvent type] == NSLeftMouseDragged) {
- const NSPoint startPos = [theEvent locationInWindow];
- const NSPoint pos = [nextEvent locationInWindow];
- if (std::abs(startPos.x - pos.x) > kDragDistance ||
- std::abs(startPos.y - pos.y) > kDragDistance) {
- [dragDelegate_ beginDragFromHoverButton:self event:nextEvent];
- mouseDown_ = NO;
- self.hoverState = kHoverStateNone;
- return;
- }
- }
- }
- }
-
- // If the mouse is still over the button, it means the user clicked the
- // button.
- if (!sendActionOnMouseDown_ && self.hoverState == kHoverStateMouseDown) {
- [self sendAction:self.action to:self.target];
- }
-
- // Clean up.
- mouseDown_ = NO;
- [self checkImageState];
-}
-
-- (void)setAccessibilityTitle:(NSString*)accessibilityTitle {
- NSCell* cell = [self cell];
- [cell accessibilitySetOverrideValue:accessibilityTitle
- forAttribute:NSAccessibilityTitleAttribute];
-}
-
-- (void)updateTrackingAreas {
- if (trackingEnabled_ && self.enabled) {
- NSRect hitbox = self.hitbox;
- if (CrTrackingArea* trackingArea = trackingArea_.get()) {
- if (NSEqualRects(trackingArea.rect, hitbox))
- return;
- [self removeTrackingArea:trackingArea];
- }
- trackingArea_.reset([[CrTrackingArea alloc]
- initWithRect:hitbox
- options:NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveAlways |
- (NSIsEmptyRect(hitbox) ? NSTrackingInVisibleRect : 0)
- owner:self
- userInfo:nil]);
- [self addTrackingArea:trackingArea_.get()];
-
- // If you have a separate window that overlaps the close button, and you
- // move the mouse directly over the close button without entering another
- // part of the tab strip, we don't get any mouseEntered event since the
- // tracking area was disabled when we entered.
- // Done with a delay of 0 because sometimes an event appears to be missed
- // between the activation of the tracking area and the call to
- // checkImageState resulting in the button state being incorrect.
- [self performSelector:@selector(checkImageState)
- withObject:nil
- afterDelay:0];
- } else {
- if (trackingArea_.get()) {
- self.hoverState = kHoverStateNone;
- [self removeTrackingArea:trackingArea_.get()];
- trackingArea_.reset(nil);
- }
- }
- [super updateTrackingAreas];
- [self checkImageState];
-}
-
-- (void)checkImageState {
- if (!trackingArea_.get())
- return;
-
- NSEvent* currentEvent = [NSApp currentEvent];
- if (!currentEvent || currentEvent.window != self.window)
- return;
-
- // Update the button's state if the button has moved.
- const NSPoint mouseLoc =
- [self.superview convertPoint:currentEvent.locationInWindow fromView:nil];
- BOOL mouseInBounds = [self hitTest:mouseLoc] != nil;
- if (mouseDown_ && mouseInBounds) {
- self.hoverState = kHoverStateMouseDown;
- } else {
- self.hoverState = mouseInBounds ? kHoverStateMouseOver : kHoverStateNone;
- }
-}
-
-- (void)setHoverState:(CloseButtonHoverState)hoverState {
- if (hoverState == hoverState_)
- return;
- hoverState_ = hoverState;
- self.needsDisplay = YES;
-}
-
-- (NSView*)hitTest:(NSPoint)point {
- if (NSPointInRect([self.superview convertPoint:point toView:self],
- self.hitbox)) {
- return self;
- }
- return [super hitTest:point];
-}
-
-@end
diff --git a/chromium/ui/base/cocoa/hover_button_unittest.mm b/chromium/ui/base/cocoa/hover_button_unittest.mm
deleted file mode 100644
index 10a8472d4e3..00000000000
--- a/chromium/ui/base/cocoa/hover_button_unittest.mm
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2017 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/base/cocoa/hover_button.h"
-
-#import <Cocoa/Cocoa.h>
-
-#import "ui/base/test/cocoa_helper.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-@interface TestHoverButton : HoverButtonCocoa
-@property(readwrite, nonatomic) NSRect hitbox;
-@end
-
-@implementation TestHoverButton
-@synthesize hitbox = hitbox_;
-
-- (void)setHitbox:(NSRect)hitbox {
- hitbox_ = hitbox;
- [self updateTrackingAreas];
-}
-@end
-
-@interface HoverButtonTestTarget : NSObject
-@property(nonatomic, copy) void (^actionHandler)(id);
-@end
-
-@implementation HoverButtonTestTarget
-@synthesize actionHandler = actionHandler_;
-
-- (void)dealloc {
- [actionHandler_ release];
- [super dealloc];
-}
-
-- (IBAction)action:(id)sender {
- actionHandler_(sender);
-}
-@end
-
-@interface HoverButtonTestDragDelegate : NSObject<HoverButtonDragDelegate>
-@property(nonatomic, copy) void (^dragHandler)(HoverButtonCocoa*, NSEvent*);
-@end
-
-@implementation HoverButtonTestDragDelegate
-@synthesize dragHandler = dragHandler_;
-
-- (void)dealloc {
- [dragHandler_ release];
- [super dealloc];
-}
-
-- (void)beginDragFromHoverButton:(HoverButtonCocoa*)button
- event:(NSEvent*)event {
- dragHandler_(button, event);
-}
-@end
-
-namespace {
-
-class HoverButtonTest : public ui::CocoaTest {
- public:
- HoverButtonTest() {
- NSRect frame = NSMakeRect(0, 0, 20, 20);
- base::scoped_nsobject<TestHoverButton> button(
- [[TestHoverButton alloc] initWithFrame:frame]);
- button_ = button;
- target_.reset([[HoverButtonTestTarget alloc] init]);
- button_.target = target_;
- button_.action = @selector(action:);
- [[test_window() contentView] addSubview:button_];
- }
-
- protected:
- void HoverAndExpect(CloseButtonHoverState hoverState) {
- EXPECT_EQ(kHoverStateNone, button_.hoverState);
- [button_ mouseEntered:cocoa_test_event_utils::EnterEvent()];
- EXPECT_EQ(hoverState, button_.hoverState);
- [button_ mouseExited:cocoa_test_event_utils::ExitEvent()];
- EXPECT_EQ(kHoverStateNone, button_.hoverState);
- }
-
- bool HandleMouseDown(NSEvent* mouseDownEvent) {
- __block bool action_sent = false;
- target_.get().actionHandler = ^(id sender) {
- action_sent = true;
- EXPECT_EQ(kHoverStateMouseDown, button_.hoverState);
- };
- [NSApp sendEvent:mouseDownEvent];
- target_.get().actionHandler = nil;
- return action_sent;
- }
-
- TestHoverButton* button_; // Weak, owned by test_window().
- base::scoped_nsobject<HoverButtonTestTarget> target_;
-};
-
-TEST_VIEW(HoverButtonTest, button_)
-
-TEST_F(HoverButtonTest, Hover) {
- EXPECT_EQ(kHoverStateNone, button_.hoverState);
-
- // Default
- HoverAndExpect(kHoverStateMouseOver);
-
- // Tracking disabled
- button_.trackingEnabled = NO;
- HoverAndExpect(kHoverStateNone);
- button_.trackingEnabled = YES;
-
- // Button disabled
- button_.enabled = NO;
- HoverAndExpect(kHoverStateNone);
- button_.enabled = YES;
-
- // Back to normal
- HoverAndExpect(kHoverStateMouseOver);
-}
-
-TEST_F(HoverButtonTest, Click) {
- EXPECT_EQ(kHoverStateNone, button_.hoverState);
- const auto click = cocoa_test_event_utils::MouseClickInView(button_, 1);
-
- [NSApp postEvent:click.second atStart:YES];
- EXPECT_TRUE(HandleMouseDown(click.first));
-
- button_.enabled = NO;
- EXPECT_FALSE(HandleMouseDown(click.first));
-
- EXPECT_EQ(kHoverStateNone, button_.hoverState);
-}
-
-TEST_F(HoverButtonTest, CustomHitbox) {
- NSRect hitbox = button_.frame;
- hitbox.size.width += 10;
-
- NSPoint inside_hit_point =
- NSMakePoint(NSMaxX(button_.frame) + 5, NSMidY(button_.frame));
- NSPoint outside_hit_point =
- NSMakePoint(inside_hit_point.x + 10, inside_hit_point.y);
-
- {
- NSRect trackingRect = button_.trackingAreas[0].rect;
- EXPECT_FALSE(NSPointInRect(inside_hit_point, trackingRect));
- EXPECT_FALSE(NSPointInRect(outside_hit_point, trackingRect));
- EXPECT_NE(button_, [button_ hitTest:inside_hit_point]);
- EXPECT_EQ(nil, [button_ hitTest:outside_hit_point]);
- }
-
- button_.hitbox = hitbox;
- {
- NSRect trackingRect = button_.trackingAreas[0].rect;
- EXPECT_TRUE(NSPointInRect(inside_hit_point, trackingRect));
- EXPECT_FALSE(NSPointInRect(outside_hit_point, trackingRect));
- EXPECT_EQ(button_, [button_ hitTest:inside_hit_point]);
- EXPECT_EQ(nil, [button_ hitTest:outside_hit_point]);
- }
-
- button_.hitbox = NSZeroRect;
- {
- NSRect trackingRect = button_.trackingAreas[0].rect;
- EXPECT_FALSE(NSPointInRect(inside_hit_point, trackingRect));
- EXPECT_FALSE(NSPointInRect(outside_hit_point, trackingRect));
- EXPECT_NE(button_, [button_ hitTest:inside_hit_point]);
- EXPECT_EQ(nil, [button_ hitTest:outside_hit_point]);
- }
-}
-
-TEST_F(HoverButtonTest, DragDelegate) {
- base::scoped_nsobject<HoverButtonTestDragDelegate> dragDelegate(
- [[HoverButtonTestDragDelegate alloc] init]);
-
- __block bool dragged = false;
- dragDelegate.get().dragHandler = ^(HoverButtonCocoa* button, NSEvent* event) {
- dragged = true;
- };
- button_.dragDelegate = dragDelegate;
-
- const auto click = cocoa_test_event_utils::MouseClickInView(button_, 1);
- NSPoint targetPoint = click.first.locationInWindow;
- targetPoint.x += 5; // *Not* enough to trigger a drag.
- [NSApp postEvent:cocoa_test_event_utils::MouseEventAtPointInWindow(
- targetPoint, NSEventTypeLeftMouseDragged,
- [button_ window], 1)
- atStart:NO];
- [NSApp postEvent:click.second atStart:NO];
- EXPECT_TRUE(HandleMouseDown(click.first));
- EXPECT_FALSE(dragged);
-
- targetPoint.x += 1; // Now it's enough to trigger a drag.
- [NSApp postEvent:cocoa_test_event_utils::MouseEventAtPointInWindow(
- targetPoint, NSEventTypeLeftMouseDragged,
- [button_ window], 1)
- atStart:NO];
- [NSApp postEvent:click.second atStart:NO];
- EXPECT_FALSE(HandleMouseDown(click.first));
- EXPECT_TRUE(dragged);
-}
-} // namespace
diff --git a/chromium/ui/base/cocoa/hover_image_button.h b/chromium/ui/base/cocoa/hover_image_button.h
deleted file mode 100644
index 789ecd63d63..00000000000
--- a/chromium/ui/base/cocoa/hover_image_button.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_COCOA_HOVER_IMAGE_BUTTON_H_
-#define UI_BASE_COCOA_HOVER_IMAGE_BUTTON_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#import "ui/base/cocoa/hover_button.h"
-#include "ui/base/ui_base_export.h"
-
-// A button that changes images when you hover over it and click it.
-UI_BASE_EXPORT
-@interface HoverImageButton : HoverButtonCocoa {
- @private
- base::scoped_nsobject<NSImage> defaultImage_;
- base::scoped_nsobject<NSImage> hoverImage_;
- base::scoped_nsobject<NSImage> pressedImage_;
-}
-
-// Disables a click within the button from activating the application.
-@property(nonatomic) BOOL disableActivationOnClick;
-
-// Sets the default image.
-- (void)setDefaultImage:(NSImage*)image;
-
-// Sets the hover image.
-- (void)setHoverImage:(NSImage*)image;
-
-// Sets the pressed image.
-- (void)setPressedImage:(NSImage*)image;
-
-@end
-
-#endif // UI_BASE_COCOA_HOVER_IMAGE_BUTTON_H_
diff --git a/chromium/ui/base/cocoa/hover_image_button.mm b/chromium/ui/base/cocoa/hover_image_button.mm
deleted file mode 100644
index 75eea36a158..00000000000
--- a/chromium/ui/base/cocoa/hover_image_button.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/base/cocoa/hover_image_button.h"
-
-@implementation HoverImageButton
-
-@synthesize disableActivationOnClick = disableActivationOnClick_;
-
-- (void)drawRect:(NSRect)rect {
- if (hoverState_ == kHoverStateMouseDown && pressedImage_) {
- [super setImage:pressedImage_.get()];
- } else if (hoverState_ == kHoverStateMouseOver && hoverImage_) {
- [super setImage:hoverImage_.get()];
- } else {
- [super setImage:defaultImage_.get()];
- }
-
- [super drawRect:rect];
-}
-
-- (void)setDefaultImage:(NSImage*)image {
- defaultImage_.reset([image retain]);
-}
-
-- (void)setHoverImage:(NSImage*)image {
- hoverImage_.reset([image retain]);
-}
-
-- (void)setPressedImage:(NSImage*)image {
- pressedImage_.reset([image retain]);
-}
-
-- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent*)theEvent {
- // To avoid activating the app on a click inside the button, first tell
- // the Appkit not to immediately order the HoverImageButton's window front in
- // response to theEvent.
- return disableActivationOnClick_;
-}
-
-- (void)mouseDown:(NSEvent*)mouseDownEvent {
- // If disabling activation on click, tell the Appkit to cancel window ordering
- // for this mouse down.
- if (disableActivationOnClick_) {
- [[NSApplication sharedApplication] preventWindowOrdering];
- }
-
- [super mouseDown:mouseDownEvent];
-}
-
-@end
diff --git a/chromium/ui/base/cocoa/hover_image_button_unittest.mm b/chromium/ui/base/cocoa/hover_image_button_unittest.mm
deleted file mode 100644
index 8f6c19a026a..00000000000
--- a/chromium/ui/base/cocoa/hover_image_button_unittest.mm
+++ /dev/null
@@ -1,48 +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.
-
-#import "ui/base/cocoa/hover_image_button.h"
-
-#import "base/mac/scoped_nsobject.h"
-#import "ui/base/test/cocoa_helper.h"
-#include "ui/events/test/cocoa_test_event_utils.h"
-
-namespace {
-
-class HoverImageButtonTest : public ui::CocoaTest {
- public:
- HoverImageButtonTest() {
- NSRect content_frame = [[test_window() contentView] frame];
- base::scoped_nsobject<HoverImageButton> button(
- [[HoverImageButton alloc] initWithFrame:content_frame]);
- button_ = button.get();
- [[test_window() contentView] addSubview:button_];
- }
-
- void DrawRect() {
- [button_ lockFocus];
- [button_ drawRect:[button_ bounds]];
- [button_ unlockFocus];
- }
-
- HoverImageButton* button_;
-};
-
-// Test mouse events.
-TEST_F(HoverImageButtonTest, ImageSwap) {
- NSImage* image = [NSImage imageNamed:NSImageNameStatusAvailable];
- NSImage* hover = [NSImage imageNamed:NSImageNameStatusNone];
- [button_ setDefaultImage:image];
- [button_ setHoverImage:hover];
-
- [button_ mouseEntered:cocoa_test_event_utils::EnterEvent()];
- DrawRect();
- EXPECT_EQ([button_ image], hover);
- [button_ mouseExited:cocoa_test_event_utils::ExitEvent()];
- DrawRect();
- EXPECT_NE([button_ image], hover);
- EXPECT_EQ([button_ image], image);
-}
-
-} // namespace
diff --git a/chromium/ui/base/cocoa/menu_controller.h b/chromium/ui/base/cocoa/menu_controller.h
index 56cdd4a63a7..69bea169266 100644
--- a/chromium/ui/base/cocoa/menu_controller.h
+++ b/chromium/ui/base/cocoa/menu_controller.h
@@ -38,21 +38,18 @@ UI_BASE_EXPORT
// |-initWithModel:useWithPopUpButtonCell:| or after the first call to |-menu|.
@property(nonatomic, assign) BOOL useWithPopUpButtonCell;
-+ (base::string16)elideMenuTitle:(const base::string16&)title
- toWidth:(int)width;
-
// NIB-based initializer. This does not create a menu. Clients can set the
// properties of the object and the menu will be created upon the first call to
// |-menu|. Note that the menu will be immutable after creation.
-- (id)init;
+- (instancetype)init;
// Builds a NSMenu from the pre-built model (must not be nil). Changes made
// to the contents of the model after calling this will not be noticed. If
// the menu will be displayed by a NSPopUpButtonCell, it needs to be of a
// slightly different form (0th item is empty). Note this attribute of the menu
// cannot be changed after it has been created.
-- (id)initWithModel:(ui::MenuModel*)model
- useWithPopUpButtonCell:(BOOL)useWithCell;
+- (instancetype)initWithModel:(ui::MenuModel*)model
+ useWithPopUpButtonCell:(BOOL)useWithCell;
// Programmatically close the constructed menu.
- (void)cancel;
diff --git a/chromium/ui/base/cocoa/menu_controller.mm b/chromium/ui/base/cocoa/menu_controller.mm
index 7462cfc934f..2dfefc53f9c 100644
--- a/chromium/ui/base/cocoa/menu_controller.mm
+++ b/chromium/ui/base/cocoa/menu_controller.mm
@@ -16,7 +16,6 @@
#import "ui/events/event_utils.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/image/image.h"
-#include "ui/gfx/text_elider.h"
#include "ui/strings/grit/ui_strings.h"
namespace {
@@ -96,20 +95,13 @@ bool MenuHasVisibleItems(const ui::MenuModel* model) {
@synthesize useWithPopUpButtonCell = useWithPopUpButtonCell_;
@synthesize postItemSelectedAsTask = postItemSelectedAsTask_;
-+ (base::string16)elideMenuTitle:(const base::string16&)title
- toWidth:(int)width {
- NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default"
- return gfx::ElideText(title, gfx::FontList(gfx::Font(nsfont)), width,
- gfx::ELIDE_TAIL, gfx::Typesetter::NATIVE);
-}
-
-- (id)init {
+- (instancetype)init {
self = [super init];
return self;
}
-- (id)initWithModel:(ui::MenuModel*)model
- useWithPopUpButtonCell:(BOOL)useWithCell {
+- (instancetype)initWithModel:(ui::MenuModel*)model
+ useWithPopUpButtonCell:(BOOL)useWithCell {
if ((self = [super init])) {
model_ = model;
useWithPopUpButtonCell_ = useWithCell;
@@ -237,10 +229,8 @@ bool MenuHasVisibleItems(const ui::MenuModel* model) {
}
const gfx::FontList* font_list = model->GetLabelFontListAt(modelIndex);
if (font_list) {
- NSDictionary *attributes =
- [NSDictionary dictionaryWithObject:font_list->GetPrimaryFont().
- GetNativeFont()
- forKey:NSFontAttributeName];
+ NSDictionary* attributes =
+ @{NSFontAttributeName : font_list->GetPrimaryFont().GetNativeFont()};
base::scoped_nsobject<NSAttributedString> title(
[[NSAttributedString alloc] initWithString:[(id)item title]
attributes:attributes]);
diff --git a/chromium/ui/base/cocoa/menu_controller_unittest.mm b/chromium/ui/base/cocoa/menu_controller_unittest.mm
index ba5807f2868..6a3647306b9 100644
--- a/chromium/ui/base/cocoa/menu_controller_unittest.mm
+++ b/chromium/ui/base/cocoa/menu_controller_unittest.mm
@@ -140,8 +140,7 @@ class Delegate : public SimpleMenuModel::Delegate {
EXPECT_FALSE(did_close_);
did_show_ = true;
if (auto_close_) {
- NSArray* modes = [NSArray arrayWithObjects:NSEventTrackingRunLoopMode,
- NSDefaultRunLoopMode, nil];
+ NSArray* modes = @[ NSEventTrackingRunLoopMode, NSDefaultRunLoopMode ];
[menu_to_close_ performSelector:@selector(cancelTracking)
withObject:nil
afterDelay:0.1
@@ -555,7 +554,8 @@ TEST_F(MenuControllerTest, Dynamic) {
base::string16 second = ASCIIToUTF16("second");
delegate.SetDynamicLabel(second);
const gfx::Image& icon =
- ResourceBundle::GetSharedInstance().GetNativeImageNamed(IDR_THROBBER);
+ ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+ IDR_EMOJI_FAVICON);
delegate.SetDynamicIcon(icon);
// Simulate opening the menu and validate that the item label + icon changes.
Validate(menu.get(), [menu menu]);
diff --git a/chromium/ui/base/cocoa/remote_accessibility_api.h b/chromium/ui/base/cocoa/remote_accessibility_api.h
new file mode 100644
index 00000000000..2a58aebabb2
--- /dev/null
+++ b/chromium/ui/base/cocoa/remote_accessibility_api.h
@@ -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.
+
+#ifndef UI_BASE_COCOA_REMOTE_ACCESSIBILITY_API_H_
+#define UI_BASE_COCOA_REMOTE_ACCESSIBILITY_API_H_
+
+#import <Cocoa/Cocoa.h>
+#include <vector>
+
+#include "base/mac/scoped_nsobject.h"
+#include "ui/base/ui_base_export.h"
+
+@interface NSAccessibilityRemoteUIElement : NSObject
++ (void)registerRemoteUIProcessIdentifier:(int)pid;
++ (NSData*)remoteTokenForLocalUIElement:(id)element;
+- (id)initWithRemoteToken:(NSData*)token;
+@property(retain) id windowUIElement;
+@property(retain) id topLevelUIElement;
+@end
+
+namespace ui {
+
+// Helper functions to implement the above functions using std::vectors intsead
+// of NSData.
+class UI_BASE_EXPORT RemoteAccessibility {
+ public:
+ static std::vector<uint8_t> GetTokenForLocalElement(id element);
+ static base::scoped_nsobject<NSAccessibilityRemoteUIElement>
+ GetRemoteElementFromToken(const std::vector<uint8_t>& token);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_COCOA_REMOTE_ACCESSIBILITY_API_H_
diff --git a/chromium/ui/base/cocoa/remote_accessibility_api.mm b/chromium/ui/base/cocoa/remote_accessibility_api.mm
new file mode 100644
index 00000000000..8a6d9d1f2ab
--- /dev/null
+++ b/chromium/ui/base/cocoa/remote_accessibility_api.mm
@@ -0,0 +1,27 @@
+// 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/base/cocoa/remote_accessibility_api.h"
+
+namespace ui {
+
+// static
+std::vector<uint8_t> RemoteAccessibility::GetTokenForLocalElement(id element) {
+ NSData* data =
+ [NSAccessibilityRemoteUIElement remoteTokenForLocalUIElement:element];
+ const uint8_t* bytes = reinterpret_cast<const uint8_t*>([data bytes]);
+ return std::vector<uint8_t>(bytes, bytes + [data length]);
+}
+
+// static
+base::scoped_nsobject<NSAccessibilityRemoteUIElement>
+RemoteAccessibility::GetRemoteElementFromToken(
+ const std::vector<uint8_t>& token) {
+ base::scoped_nsobject<NSData> data(
+ [[NSData alloc] initWithBytes:token.data() length:token.size()]);
+ return base::scoped_nsobject<NSAccessibilityRemoteUIElement>(
+ [[NSAccessibilityRemoteUIElement alloc] initWithRemoteToken:data]);
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/cocoa/remote_layer_api.h b/chromium/ui/base/cocoa/remote_layer_api.h
index 7b97c7e5eb1..291a11b4d13 100644
--- a/chromium/ui/base/cocoa/remote_layer_api.h
+++ b/chromium/ui/base/cocoa/remote_layer_api.h
@@ -33,8 +33,8 @@ typedef uint32_t CAContextID;
// content displayed by that CALayerHost will be the content of the CALayer
// that is set as the |layer| property on the CAContext.
@interface CAContext : NSObject
-+ (id)contextWithCGSConnection:(CAContextID)contextId
- options:(NSDictionary*)optionsDict;
++ (instancetype)contextWithCGSConnection:(CAContextID)contextId
+ options:(NSDictionary*)optionsDict;
@property(readonly) CAContextID contextId;
@property(retain) CALayer *layer;
@end
diff --git a/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm b/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm
index 489054ca7fe..d9e592c47f4 100644
--- a/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm
+++ b/chromium/ui/base/cocoa/underlay_opengl_hosting_window.mm
@@ -8,10 +8,10 @@
@implementation UnderlayOpenGLHostingWindow
-- (id)initWithContentRect:(NSRect)contentRect
- styleMask:(NSUInteger)windowStyle
- backing:(NSBackingStoreType)bufferingType
- defer:(BOOL)deferCreation {
+- (instancetype)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType
+ defer:(BOOL)deferCreation {
// It is invalid to create windows with zero width or height. It screws things
// up royally:
// - It causes console spew: <http://crbug.com/78973>
diff --git a/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.cc b/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.cc
deleted file mode 100644
index 72df892d4c7..00000000000
--- a/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2017 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/base/cursor/ozone/cursor_data_factory_ozone.h"
-
-#include "ui/base/cursor/cursor.h"
-
-namespace ui {
-
-namespace {
-
-// A magic value that we store at the start of an instance.
-const uint32_t kCookie = 0xF60D214C;
-
-const uint32_t kBadCookie = 0xBADBADCC;
-
-CursorDataOzone* ToCursorDataOzone(PlatformCursor cursor) {
- CursorDataOzone* ozone = static_cast<CursorDataOzone*>(cursor);
-#if DCHECK_IS_ON()
- ozone->AssertIsACursorDataOzone();
-#endif
- return ozone;
-}
-
-PlatformCursor ToPlatformCursor(CursorDataOzone* cursor) {
- return static_cast<PlatformCursor>(cursor);
-}
-
-} // namespace
-
-CursorDataOzone::CursorDataOzone(const ui::CursorData& data)
- : magic_cookie_(kCookie), data_(data) {}
-
-void CursorDataOzone::AssertIsACursorDataOzone() {
- CHECK_EQ(magic_cookie_, kCookie);
-}
-
-CursorDataOzone::~CursorDataOzone() {
- magic_cookie_ = kBadCookie;
-}
-
-CursorDataFactoryOzone::CursorDataFactoryOzone() {}
-
-CursorDataFactoryOzone::~CursorDataFactoryOzone() {}
-
-// static
-const ui::CursorData& CursorDataFactoryOzone::GetCursorData(
- PlatformCursor platform_cursor) {
- return ToCursorDataOzone(platform_cursor)->data();
-}
-
-PlatformCursor CursorDataFactoryOzone::GetDefaultCursor(CursorType type) {
- // Unlike BitmapCursorFactoryOzone, we aren't making heavyweight bitmaps, but
- // we still have to cache these forever because objects that come out of the
- // GetDefaultCursor() method aren't treated as refcounted by the ozone
- // interfaces.
- return GetDefaultCursorInternal(type).get();
-}
-
-PlatformCursor CursorDataFactoryOzone::CreateImageCursor(
- const SkBitmap& bitmap,
- const gfx::Point& hotspot,
- float bitmap_dpi) {
- CursorDataOzone* cursor = new CursorDataOzone(
- ui::CursorData(hotspot, {bitmap}, bitmap_dpi, base::TimeDelta()));
- cursor->AddRef(); // Balanced by UnrefImageCursor.
- return ToPlatformCursor(cursor);
-}
-
-PlatformCursor CursorDataFactoryOzone::CreateAnimatedCursor(
- const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms,
- float bitmap_dpi) {
- CursorDataOzone* cursor = new CursorDataOzone(
- ui::CursorData(hotspot, bitmaps, bitmap_dpi,
- base::TimeDelta::FromMilliseconds(frame_delay_ms)));
- cursor->AddRef(); // Balanced by UnrefImageCursor.
- return ToPlatformCursor(cursor);
-}
-
-void CursorDataFactoryOzone::RefImageCursor(PlatformCursor cursor) {
- ToCursorDataOzone(cursor)->AddRef();
-}
-
-void CursorDataFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
- ToCursorDataOzone(cursor)->Release();
-}
-
-scoped_refptr<CursorDataOzone> CursorDataFactoryOzone::GetDefaultCursorInternal(
- CursorType type) {
- if (type == CursorType::kNone)
- return nullptr; // nullptr is used for hidden cursor.
-
- if (!default_cursors_.count(type)) {
- // We hold a ref forever because clients do not do refcounting for default
- // cursors.
- scoped_refptr<CursorDataOzone> cursor =
- base::MakeRefCounted<CursorDataOzone>(ui::CursorData(type));
- default_cursors_[type] = std::move(cursor);
- }
-
- // Returned owned default cursor for this type.
- return default_cursors_[type];
-}
-
-} // namespace ui
diff --git a/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h b/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h
deleted file mode 100644
index b5cba38833a..00000000000
--- a/chromium/ui/base/cursor/ozone/cursor_data_factory_ozone.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2017 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_BASE_CURSOR_OZONE_CURSORD_DATA_FACTORY_OZONE_H_
-#define UI_BASE_CURSOR_OZONE_CURSORD_DATA_FACTORY_OZONE_H_
-
-#include <map>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/cursor/cursor_data.h"
-#include "ui/base/ui_base_export.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/ozone/public/cursor_factory_ozone.h"
-
-namespace ui {
-
-// A refcounted wrapper around a ui::CursorData to obey CursorFactoryOzone's
-// refcounting interface while building ui::CursorData objects for transport
-// over mojo pipes.
-//
-// TODO(erg): In the long term, this should go away. When //content/ switches
-// from webcursor.h to use ui::CursorData directly, we should be able to get
-// rid of this class which is an adaptor for the existing ozone code.
-class UI_BASE_EXPORT CursorDataOzone
- : public base::RefCounted<CursorDataOzone> {
- public:
- explicit CursorDataOzone(const ui::CursorData& data);
-
- const ui::CursorData& data() const { return data_; }
-
- // Instances of CursorDataOzone are passed around as void* because of the low
- // level CursorFactoryOzone interface. Even worse, there can be multiple
- // subclasses that map to this void* type. This asserts that a magic cookie
- // that we put at the start of valid CursorDataOzone objects is correct.
- void AssertIsACursorDataOzone();
-
- private:
- friend class base::RefCounted<CursorDataOzone>;
- ~CursorDataOzone();
-
- // This is always a magic constant value. This is set in the constructor and
- // unset in the destructor.
- uint32_t magic_cookie_;
-
- ui::CursorData data_;
-
- DISALLOW_COPY_AND_ASSIGN(CursorDataOzone);
-};
-
-// CursorFactoryOzone implementation for processes which use ui::CursorDatas.
-//
-// Inside some sandboxed processes, we need to save all source data so it can
-// be processed in a remote process. This plugs into the current ozone cursor
-// creating code, and builds the cross platform mojo data structure.
-class UI_BASE_EXPORT CursorDataFactoryOzone : public CursorFactoryOzone {
- public:
- CursorDataFactoryOzone();
- ~CursorDataFactoryOzone() override;
-
- // Converts a PlatformCursor back to a ui::CursorData.
- static const ui::CursorData& GetCursorData(PlatformCursor platform_cursor);
-
- // CursorFactoryOzone:
- PlatformCursor GetDefaultCursor(CursorType type) override;
- PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
- const gfx::Point& hotspot,
- float bitmap_dpi) override;
- PlatformCursor CreateAnimatedCursor(const std::vector<SkBitmap>& bitmaps,
- const gfx::Point& hotspot,
- int frame_delay_ms,
- float bitmap_dpi) override;
- void RefImageCursor(PlatformCursor cursor) override;
- void UnrefImageCursor(PlatformCursor cursor) override;
-
- private:
- // Get cached BitmapCursorOzone for a default cursor.
- scoped_refptr<CursorDataOzone> GetDefaultCursorInternal(CursorType type);
-
- // Default cursors are cached & owned by the factory.
- std::map<CursorType, scoped_refptr<CursorDataOzone>> default_cursors_;
-
- DISALLOW_COPY_AND_ASSIGN(CursorDataFactoryOzone);
-};
-
-} // namespace ui
-
-#endif // UI_BASE_CURSOR_OZONE_CURSORD_DATA_FACTORY_OZONE_H_
diff --git a/chromium/ui/base/dragdrop/cocoa_dnd_util.mm b/chromium/ui/base/dragdrop/cocoa_dnd_util.mm
index 9a0648e2ebb..dcf71da4fe3 100644
--- a/chromium/ui/base/dragdrop/cocoa_dnd_util.mm
+++ b/chromium/ui/base/dragdrop/cocoa_dnd_util.mm
@@ -37,7 +37,7 @@ BOOL PopulateURLAndTitleFromPasteboard(GURL* url,
// It's possible that no URLs were actually provided!
if (![url_array count])
return NO;
- NSString* url_string = [url_array objectAtIndex:0];
+ NSString* url_string = url_array[0];
if ([url_string length]) {
// Check again just to make sure to not assign NULL into a std::string,
// which throws an exception.
@@ -46,7 +46,7 @@ BOOL PopulateURLAndTitleFromPasteboard(GURL* url,
*url = GURL(utf8_url);
// Extra paranoia check.
if (title && [title_array count])
- *title = base::SysNSStringToUTF16([title_array objectAtIndex:0]);
+ *title = base::SysNSStringToUTF16(title_array[0]);
}
}
return YES;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
index 6666737fd2d..144c8babf50 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
@@ -173,8 +173,8 @@ void OSExchangeDataProviderAuraX11::SetFilename(const base::FilePath& path) {
void OSExchangeDataProviderAuraX11::SetFilenames(
const std::vector<FileInfo>& filenames) {
std::vector<std::string> paths;
- for (auto it = filenames.begin(); it != filenames.end(); ++it) {
- std::string url_spec = net::FilePathToFileURL(it->path).spec();
+ for (const auto& filename : filenames) {
+ std::string url_spec = net::FilePathToFileURL(filename.path).spec();
if (!url_spec.empty())
paths.push_back(url_spec);
}
@@ -254,9 +254,8 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
}
} else if (data.GetType() == gfx::GetAtom(Clipboard::kMimeTypeURIList)) {
std::vector<std::string> tokens = ui::ParseURIList(data);
- for (std::vector<std::string>::const_iterator it = tokens.begin();
- it != tokens.end(); ++it) {
- GURL test_url(*it);
+ for (const std::string& token : tokens) {
+ GURL test_url(token);
if (!test_url.SchemeIsFile() ||
policy == OSExchangeData::CONVERT_FILENAMES) {
*url = test_url;
@@ -290,9 +289,8 @@ bool OSExchangeDataProviderAuraX11::GetFilenames(
ui::SelectionData data(format_map_.GetFirstOf(requested_types));
if (data.IsValid()) {
std::vector<std::string> tokens = ui::ParseURIList(data);
- for (std::vector<std::string>::const_iterator it = tokens.begin();
- it != tokens.end(); ++it) {
- GURL url(*it);
+ for (const std::string& token : tokens) {
+ GURL url(token);
base::FilePath file_path;
if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) {
filenames->push_back(FileInfo(file_path, base::FilePath()));
@@ -347,9 +345,8 @@ bool OSExchangeDataProviderAuraX11::HasURL(
} else if (data.GetType() ==
gfx::GetAtom(ui::Clipboard::kMimeTypeURIList)) {
std::vector<std::string> tokens = ui::ParseURIList(data);
- for (std::vector<std::string>::const_iterator it = tokens.begin();
- it != tokens.end(); ++it) {
- if (!GURL(*it).SchemeIsFile() ||
+ for (const std::string& token : tokens) {
+ if (!GURL(token).SchemeIsFile() ||
policy == OSExchangeData::CONVERT_FILENAMES)
return true;
}
@@ -375,9 +372,8 @@ bool OSExchangeDataProviderAuraX11::HasFile() const {
ui::SelectionData data(format_map_.GetFirstOf(requested_types));
if (data.IsValid()) {
std::vector<std::string> tokens = ui::ParseURIList(data);
- for (std::vector<std::string>::const_iterator it = tokens.begin();
- it != tokens.end(); ++it) {
- GURL url(*it);
+ for (const std::string& token : tokens) {
+ GURL url(token);
base::FilePath file_path;
if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path))
return true;
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
index c55c78ca720..4a626b30093 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_mac.mm
@@ -141,7 +141,7 @@ bool OSExchangeDataProviderMac::GetFilename(base::FilePath* path) const {
if ([paths count] == 0)
return false;
- *path = base::FilePath([[paths objectAtIndex:0] UTF8String]);
+ *path = base::FilePath(base::SysNSStringToUTF8(paths[0]));
return true;
}
diff --git a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
index 7f7270b6319..83f6da002e8 100644
--- a/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
+++ b/chromium/ui/base/dragdrop/os_exchange_data_provider_win.cc
@@ -451,9 +451,9 @@ bool OSExchangeDataProviderWin::GetFilenames(
bool success =
ClipboardUtil::GetFilenames(source_object_.Get(), &filenames_local);
if (success) {
- for (size_t i = 0; i < filenames_local.size(); ++i)
+ for (const base::string16& filename_local : filenames_local)
filenames->push_back(
- FileInfo(base::FilePath(filenames_local[i]), base::FilePath()));
+ FileInfo(base::FilePath(filename_local), base::FilePath()));
}
return success;
}
diff --git a/chromium/ui/base/idle/idle_mac.mm b/chromium/ui/base/idle/idle_mac.mm
index 4d9e37a7f73..65d7a1ce0d8 100644
--- a/chromium/ui/base/idle/idle_mac.mm
+++ b/chromium/ui/base/idle/idle_mac.mm
@@ -25,7 +25,7 @@
@synthesize screensaverRunning = screensaverRunning_;
@synthesize screenLocked = screenLocked_;
-- (id)init {
+- (instancetype)init {
if ((self = [super init])) {
NSDistributedNotificationCenter* distCenter =
[NSDistributedNotificationCenter defaultCenter];
diff --git a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc b/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
index b2f5b9fd580..3f268bc0144 100644
--- a/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
+++ b/chromium/ui/base/ime/fuchsia/input_method_keyboard_controller_fuchsia.cc
@@ -28,7 +28,7 @@ InputMethodKeyboardControllerFuchsia::InputMethodKeyboardControllerFuchsia(
DCHECK(ime_service_);
DCHECK(input_method_);
- ime_service_.set_error_handler([this]() {
+ ime_service_.set_error_handler([this](zx_status_t status) {
LOG(ERROR) << "Lost connection to IME service.";
ime_.Unbind();
ime_client_binding_.Unbind();
diff --git a/chromium/ui/base/ime/ime_text_span.h b/chromium/ui/base/ime/ime_text_span.h
index 52011f3c067..ba45d095e92 100644
--- a/chromium/ui/base/ime/ime_text_span.h
+++ b/chromium/ui/base/ime/ime_text_span.h
@@ -65,6 +65,8 @@ struct UI_BASE_IME_TYPES_EXPORT ImeTextSpan {
(this->background_color == rhs.background_color) &&
(this->suggestion_highlight_color ==
rhs.suggestion_highlight_color) &&
+ (this->remove_on_finish_composing ==
+ rhs.remove_on_finish_composing) &&
(this->suggestions == rhs.suggestions);
}
@@ -77,6 +79,7 @@ struct UI_BASE_IME_TYPES_EXPORT ImeTextSpan {
Thickness thickness;
SkColor background_color;
SkColor suggestion_highlight_color;
+ bool remove_on_finish_composing = false;
std::vector<std::string> suggestions;
};
diff --git a/chromium/ui/base/ime/text_input_flags.h b/chromium/ui/base/ime/text_input_flags.h
index ed3c851107b..ba70ea1b971 100644
--- a/chromium/ui/base/ime/text_input_flags.h
+++ b/chromium/ui/base/ime/text_input_flags.h
@@ -20,7 +20,8 @@ enum TextInputFlags {
TEXT_INPUT_FLAG_AUTOCAPITALIZE_NONE = 1 << 6,
TEXT_INPUT_FLAG_AUTOCAPITALIZE_CHARACTERS = 1 << 7,
TEXT_INPUT_FLAG_AUTOCAPITALIZE_WORDS = 1 << 8,
- TEXT_INPUT_FLAG_AUTOCAPITALIZE_SENTENCES = 1 << 9
+ TEXT_INPUT_FLAG_AUTOCAPITALIZE_SENTENCES = 1 << 9,
+ TEXT_INPUT_FLAG_HAS_BEEN_PASSWORD = 1 << 12
};
} // namespace ui
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
index ed7c451a710..80899eec38e 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc
@@ -5,6 +5,7 @@
#include "ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
#include "base/win/com_init_util.h"
#include "base/win/core_winrt_util.h"
#include "base/win/windows_version.h"
@@ -12,30 +13,206 @@
namespace ui {
+// VirtualKeyboardInputPane class is used to store all the COM objects and
+// control their lifetime, so all the COM processing is on a background
+// thread.
+class OnScreenKeyboardDisplayManagerInputPane::VirtualKeyboardInputPane
+ : public base::RefCountedThreadSafe<VirtualKeyboardInputPane> {
+ public:
+ explicit VirtualKeyboardInputPane(
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : main_task_runner_(task_runner) {}
+
+ void InitVirtualKeyboardInputPaneInstance(
+ base::WeakPtr<OnScreenKeyboardDisplayManagerInputPane>
+ input_pane_weak_ptr) {
+ keyboard_input_pane_weak_ptr_ = input_pane_weak_ptr;
+ }
+
+ // Set the virtual keyboard input pane for |OnScreenKeyboardTest| tests.
+ void SetInputPaneForTestingInBackgroundThread(
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane>
+ pane) {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ DCHECK(!input_pane_);
+ input_pane_ = pane;
+ HRESULT hr = input_pane_.As(&input_pane2_);
+ DCHECK(SUCCEEDED(hr));
+
+ AddCallbacksOnInputPaneShownOrHiddenInBackgroundThread();
+ }
+
+ void TryShowInBackgroundThread(HWND hwnd) {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ if (!EnsureInputPanePointersInBackgroundThread(hwnd))
+ return;
+ boolean res;
+ input_pane2_->TryShow(&res);
+ }
+
+ void TryHideInBackgroundThread() {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ if (!input_pane2_)
+ return;
+ boolean res;
+ input_pane2_->TryHide(&res);
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<VirtualKeyboardInputPane>;
+
+ ~VirtualKeyboardInputPane() {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ }
+
+ bool EnsureInputPanePointersInBackgroundThread(HWND hwnd) {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ if (input_pane2_)
+ return true;
+ if (!base::win::ResolveCoreWinRTDelayload() ||
+ !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) {
+ return false;
+ }
+
+ base::win::AssertComApartmentType(base::win::ComApartmentType::STA);
+
+ base::win::ScopedHString input_pane_guid = base::win::ScopedHString::Create(
+ RuntimeClass_Windows_UI_ViewManagement_InputPane);
+ Microsoft::WRL::ComPtr<IInputPaneInterop> input_pane_interop;
+ HRESULT hr = base::win::RoGetActivationFactory(
+ input_pane_guid.get(), IID_PPV_ARGS(&input_pane_interop));
+ if (FAILED(hr))
+ return false;
+
+ hr = input_pane_interop->GetForWindow(hwnd, IID_PPV_ARGS(&input_pane_));
+ if (FAILED(hr))
+ return false;
+
+ if (FAILED(input_pane_.As(&input_pane2_)))
+ return false;
+
+ AddCallbacksOnInputPaneShownOrHiddenInBackgroundThread();
+ return true;
+ }
+
+ // Add callbacks to notify virtual keyboard observers when the virtual
+ // keyboard is visible or hidden.
+ void AddCallbacksOnInputPaneShownOrHiddenInBackgroundThread() {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ input_pane_->add_Showing(
+ Microsoft::WRL::Callback<
+ OnScreenKeyboardDisplayManagerInputPane::VirtualKeyboardInputPane::
+ InputPaneEventHandler>(
+ this, &OnScreenKeyboardDisplayManagerInputPane::
+ VirtualKeyboardInputPane::OnInputPaneShown)
+ .Get(),
+ &show_event_token_);
+
+ input_pane_->add_Hiding(
+ Microsoft::WRL::Callback<
+ OnScreenKeyboardDisplayManagerInputPane::VirtualKeyboardInputPane::
+ InputPaneEventHandler>(
+ this, &OnScreenKeyboardDisplayManagerInputPane::
+ VirtualKeyboardInputPane::OnInputPaneHidden)
+ .Get(),
+ &hide_event_token_);
+ }
+
+ HRESULT OnInputPaneShown(
+ ABI::Windows::UI::ViewManagement::IInputPane* pane,
+ ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs* args) {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ ABI::Windows::Foundation::Rect rect;
+ input_pane_->get_OccludedRect(&rect);
+ gfx::Rect dip_rect(rect.X, rect.Y, rect.Width, rect.Height);
+
+ main_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::
+ NotifyObserversOnKeyboardShown,
+ keyboard_input_pane_weak_ptr_, dip_rect));
+ return S_OK;
+ }
+
+ HRESULT OnInputPaneHidden(
+ ABI::Windows::UI::ViewManagement::IInputPane* pane,
+ ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs* args) {
+ DCHECK(!main_task_runner_->BelongsToCurrentThread());
+ main_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::
+ NotifyObserversOnKeyboardHidden,
+ keyboard_input_pane_weak_ptr_));
+ return S_OK;
+ }
+
+ using InputPaneEventHandler = ABI::Windows::Foundation::ITypedEventHandler<
+ ABI::Windows::UI::ViewManagement::InputPane*,
+ ABI::Windows::UI::ViewManagement::InputPaneVisibilityEventArgs*>;
+
+ // InputPane objects are owned by VirtualKeyboardInputPane class and their
+ // functions are ran on a background thread.
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane>
+ input_pane_;
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane2>
+ input_pane2_;
+
+ EventRegistrationToken show_event_token_;
+ EventRegistrationToken hide_event_token_;
+
+ // |main_task_runner_| and |keyboard_input_pane_weak_ptr_| are owned by
+ // OnScreenKeyboardDisplayManagerInputPane class, and they are running on the
+ // main thread, which are used to post task to the main thread from the
+ // background thread.
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ base::WeakPtr<OnScreenKeyboardDisplayManagerInputPane>
+ keyboard_input_pane_weak_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardInputPane);
+};
+
OnScreenKeyboardDisplayManagerInputPane::
OnScreenKeyboardDisplayManagerInputPane(HWND hwnd)
: hwnd_(hwnd),
main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ background_task_runner_(
+ base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()})),
+ virtual_keyboard_input_pane_(
+ base::MakeRefCounted<OnScreenKeyboardDisplayManagerInputPane::
+ VirtualKeyboardInputPane>(
+ main_task_runner_)),
+ is_keyboard_visible_(false),
weak_factory_(this) {
DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN10_RS1);
-}
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
-OnScreenKeyboardDisplayManagerInputPane::
- ~OnScreenKeyboardDisplayManagerInputPane() = default;
+ // We post the initiation of |virtual_keyboard_input_pane_| to the background
+ // thread first, and any other tasks posted to the background thread are
+ // executed after its initiation.
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &OnScreenKeyboardDisplayManagerInputPane::VirtualKeyboardInputPane::
+ InitVirtualKeyboardInputPaneInstance,
+ base::RetainedRef(virtual_keyboard_input_pane_),
+ weak_factory_.GetWeakPtr()));
+}
bool OnScreenKeyboardDisplayManagerInputPane::DisplayVirtualKeyboard() {
- main_task_runner_->PostTask(
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ background_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::TryShow,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::
+ VirtualKeyboardInputPane::TryShowInBackgroundThread,
+ base::RetainedRef(virtual_keyboard_input_pane_), hwnd_));
return true;
}
void OnScreenKeyboardDisplayManagerInputPane::DismissVirtualKeyboard() {
- main_task_runner_->PostTask(
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ background_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::TryHide,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::
+ VirtualKeyboardInputPane::TryHideInBackgroundThread,
+ base::RetainedRef(virtual_keyboard_input_pane_)));
}
void OnScreenKeyboardDisplayManagerInputPane::AddObserver(
@@ -51,102 +228,26 @@ void OnScreenKeyboardDisplayManagerInputPane::RemoveObserver(
}
bool OnScreenKeyboardDisplayManagerInputPane::IsKeyboardVisible() {
- if (!EnsureInputPanePointers())
- return false;
- ABI::Windows::Foundation::Rect rect;
- input_pane_->get_OccludedRect(&rect);
- // Height == 0 is special indicating it is floating on only check width.
- return rect.Width != 0;
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ return is_keyboard_visible_;
}
void OnScreenKeyboardDisplayManagerInputPane::SetInputPaneForTesting(
- ABI::Windows::UI::ViewManagement::IInputPane* input_pane) {
- DCHECK(!input_pane_);
- input_pane_ = input_pane;
- HRESULT hr = input_pane_.As(&input_pane2_);
- DCHECK(SUCCEEDED(hr));
-
- input_pane_->add_Showing(
- Microsoft::WRL::Callback<InputPaneEventHandler>(
- this, &OnScreenKeyboardDisplayManagerInputPane::InputPaneShown)
- .Get(),
- &show_event_token_);
- input_pane_->add_Hiding(
- Microsoft::WRL::Callback<InputPaneEventHandler>(
- this, &OnScreenKeyboardDisplayManagerInputPane::InputPaneHidden)
- .Get(),
- &hide_event_token_);
-}
-
-bool OnScreenKeyboardDisplayManagerInputPane::EnsureInputPanePointers() {
- if (input_pane2_)
- return true;
- if (!base::win::ResolveCoreWinRTDelayload() ||
- !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) {
- return false;
- }
-
- // TODO(dtapuska): https://crbug.com/852386. Use TaskScheduler to access the
- // WinRT APIs.
- base::win::AssertComApartmentType(base::win::ComApartmentType::STA);
-
- base::win::ScopedHString input_pane_guid = base::win::ScopedHString::Create(
- RuntimeClass_Windows_UI_ViewManagement_InputPane);
- Microsoft::WRL::ComPtr<IInputPaneInterop> input_pane_interop;
- HRESULT hr = base::win::RoGetActivationFactory(
- input_pane_guid.get(), IID_PPV_ARGS(&input_pane_interop));
- if (FAILED(hr))
- return false;
-
- hr = input_pane_interop->GetForWindow(hwnd_, IID_PPV_ARGS(&input_pane_));
- if (FAILED(hr))
- return false;
-
- hr = input_pane_.As(&input_pane2_);
- if (FAILED(hr))
- return false;
-
- input_pane_->add_Showing(
- Microsoft::WRL::Callback<InputPaneEventHandler>(
- this, &OnScreenKeyboardDisplayManagerInputPane::InputPaneShown)
- .Get(),
- &show_event_token_);
- input_pane_->add_Hiding(
- Microsoft::WRL::Callback<InputPaneEventHandler>(
- this, &OnScreenKeyboardDisplayManagerInputPane::InputPaneHidden)
- .Get(),
- &hide_event_token_);
- return true;
-}
-
-HRESULT OnScreenKeyboardDisplayManagerInputPane::InputPaneShown(
- ABI::Windows::UI::ViewManagement::IInputPane* pane,
- ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs* args) {
- // get_OccludedRect is in DIPs already.
- ABI::Windows::Foundation::Rect rect;
- input_pane_->get_OccludedRect(&rect);
- gfx::Rect dip_rect(rect.X, rect.Y, rect.Width, rect.Height);
-
- main_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::
- NotifyObserversOnKeyboardShown,
- weak_factory_.GetWeakPtr(), dip_rect));
- return S_OK;
-}
-
-HRESULT OnScreenKeyboardDisplayManagerInputPane::InputPaneHidden(
- ABI::Windows::UI::ViewManagement::IInputPane* pane,
- ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs* args) {
- main_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&OnScreenKeyboardDisplayManagerInputPane::
- NotifyObserversOnKeyboardHidden,
- weak_factory_.GetWeakPtr()));
- return S_OK;
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane> pane) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()})
+ ->PostTask(FROM_HERE,
+ base::BindOnce(
+ &OnScreenKeyboardDisplayManagerInputPane::
+ VirtualKeyboardInputPane::
+ SetInputPaneForTestingInBackgroundThread,
+ base::RetainedRef(virtual_keyboard_input_pane_), pane));
}
void OnScreenKeyboardDisplayManagerInputPane::NotifyObserversOnKeyboardShown(
gfx::Rect dip_rect) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
+ is_keyboard_visible_ = true;
for (InputMethodKeyboardControllerObserver& observer : observers_)
observer.OnKeyboardVisible(dip_rect);
}
@@ -154,22 +255,18 @@ void OnScreenKeyboardDisplayManagerInputPane::NotifyObserversOnKeyboardShown(
void OnScreenKeyboardDisplayManagerInputPane::
NotifyObserversOnKeyboardHidden() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
+ is_keyboard_visible_ = false;
for (InputMethodKeyboardControllerObserver& observer : observers_)
observer.OnKeyboardHidden();
}
-void OnScreenKeyboardDisplayManagerInputPane::TryShow() {
- if (!EnsureInputPanePointers())
- return;
- boolean res;
- input_pane2_->TryShow(&res);
-}
-
-void OnScreenKeyboardDisplayManagerInputPane::TryHide() {
- if (!input_pane2_)
- return;
- boolean res;
- input_pane2_->TryHide(&res);
+OnScreenKeyboardDisplayManagerInputPane::
+ ~OnScreenKeyboardDisplayManagerInputPane() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (virtual_keyboard_input_pane_.get()) {
+ background_task_runner_->ReleaseSoon(
+ FROM_HERE, std::move(virtual_keyboard_input_pane_));
+ }
}
-} // namespace ui
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
index 2a359fbd70f..f97533f4aae 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.h
@@ -29,7 +29,7 @@ class OnScreenKeyboardTest;
class UI_BASE_IME_EXPORT OnScreenKeyboardDisplayManagerInputPane final
: public InputMethodKeyboardController {
public:
- OnScreenKeyboardDisplayManagerInputPane(HWND hwnd);
+ explicit OnScreenKeyboardDisplayManagerInputPane(HWND hwnd);
~OnScreenKeyboardDisplayManagerInputPane() override;
// InputMethodKeyboardController:
@@ -40,39 +40,24 @@ class UI_BASE_IME_EXPORT OnScreenKeyboardDisplayManagerInputPane final
bool IsKeyboardVisible() override;
void SetInputPaneForTesting(
- ABI::Windows::UI::ViewManagement::IInputPane* pane);
+ Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane>
+ pane);
private:
+ class VirtualKeyboardInputPane;
friend class OnScreenKeyboardTest;
- bool EnsureInputPanePointers();
- HRESULT InputPaneShown(
- ABI::Windows::UI::ViewManagement::IInputPane* pane,
- ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs* args);
- HRESULT InputPaneHidden(
- ABI::Windows::UI::ViewManagement::IInputPane* pane,
- ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs* args);
-
void NotifyObserversOnKeyboardShown(gfx::Rect rect);
void NotifyObserversOnKeyboardHidden();
- void TryShow();
- void TryHide();
-
- using InputPaneEventHandler = ABI::Windows::Foundation::ITypedEventHandler<
- ABI::Windows::UI::ViewManagement::InputPane*,
- ABI::Windows::UI::ViewManagement::InputPaneVisibilityEventArgs*>;
// The main window which displays the on screen keyboard.
const HWND hwnd_;
- Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane>
- input_pane_;
- Microsoft::WRL::ComPtr<ABI::Windows::UI::ViewManagement::IInputPane2>
- input_pane2_;
base::ObserverList<InputMethodKeyboardControllerObserver, false>::Unchecked
observers_;
- EventRegistrationToken show_event_token_;
- EventRegistrationToken hide_event_token_;
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ const scoped_refptr<base::SingleThreadTaskRunner> background_task_runner_;
+ scoped_refptr<VirtualKeyboardInputPane> virtual_keyboard_input_pane_;
+ bool is_keyboard_visible_;
base::WeakPtrFactory<OnScreenKeyboardDisplayManagerInputPane> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardDisplayManagerInputPane);
diff --git a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
index 3a17be7a5bc..6cc53194ba0 100644
--- a/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
+++ b/chromium/ui/base/ime/win/on_screen_keyboard_display_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string16.h"
+#include "base/test/scoped_task_environment.h"
#include "base/win/windows_version.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -106,7 +107,9 @@ class MockInputPane
class OnScreenKeyboardTest : public ::testing::Test {
protected:
- OnScreenKeyboardTest() = default;
+ OnScreenKeyboardTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
std::unique_ptr<OnScreenKeyboardDisplayManagerTabTip> CreateTabTip() {
return std::unique_ptr<OnScreenKeyboardDisplayManagerTabTip>(
@@ -118,8 +121,16 @@ class OnScreenKeyboardTest : public ::testing::Test {
new OnScreenKeyboardDisplayManagerInputPane(nullptr));
}
+ void WaitForEventsWithTimeDelay(int64_t time_delta_ms = 10) {
+ base::RunLoop run_loop;
+ scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(time_delta_ms));
+ run_loop.Run();
+ }
+
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboardTest);
};
@@ -163,17 +174,17 @@ TEST_F(OnScreenKeyboardTest, InputPane) {
Microsoft::WRL::ComPtr<MockInputPane> input_pane =
Microsoft::WRL::Make<MockInputPane>();
- keyboard_display_manager->SetInputPaneForTesting(input_pane.Get());
+ keyboard_display_manager->SetInputPaneForTesting(input_pane);
EXPECT_CALL(*observer, OnKeyboardVisible(testing::_)).Times(1);
keyboard_display_manager->AddObserver(observer.get());
keyboard_display_manager->DisplayVirtualKeyboard();
- base::RunLoop().RunUntilIdle();
+ WaitForEventsWithTimeDelay(100);
testing::Mock::VerifyAndClearExpectations(observer.get());
EXPECT_CALL(*observer, OnKeyboardHidden()).Times(1);
keyboard_display_manager->DismissVirtualKeyboard();
- base::RunLoop().RunUntilIdle();
+ WaitForEventsWithTimeDelay(100);
keyboard_display_manager->RemoveObserver(observer.get());
}
diff --git a/chromium/ui/base/ime/win/tsf_bridge.cc b/chromium/ui/base/ime/win/tsf_bridge.cc
index b5b1ba2a38d..eab3ad63a3e 100644
--- a/chromium/ui/base/ime/win/tsf_bridge.cc
+++ b/chromium/ui/base/ime/win/tsf_bridge.cc
@@ -131,7 +131,7 @@ class TSFBridgeImpl : public TSFBridge {
TSFBridgeImpl::TSFBridgeImpl() = default;
TSFBridgeImpl::~TSFBridgeImpl() {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
if (!IsInitialized())
return;
for (TSFDocumentMap::iterator it = tsf_document_map_.begin();
@@ -151,7 +151,7 @@ TSFBridgeImpl::~TSFBridgeImpl() {
}
bool TSFBridgeImpl::Initialize() {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
if (client_id_ != TF_CLIENTID_NULL) {
DVLOG(1) << "Already initialized.";
return false;
@@ -202,7 +202,7 @@ bool TSFBridgeImpl::Initialize() {
}
void TSFBridgeImpl::OnTextInputTypeChanged(const TextInputClient* client) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
DCHECK(IsInitialized());
if (client != client_) {
@@ -229,7 +229,7 @@ void TSFBridgeImpl::OnTextLayoutChanged() {
}
bool TSFBridgeImpl::CancelComposition() {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
DCHECK(IsInitialized());
TSFDocument* document = GetAssociatedDocument();
@@ -242,7 +242,7 @@ bool TSFBridgeImpl::CancelComposition() {
}
bool TSFBridgeImpl::ConfirmComposition() {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
DCHECK(IsInitialized());
TSFDocument* document = GetAssociatedDocument();
@@ -256,7 +256,7 @@ bool TSFBridgeImpl::ConfirmComposition() {
void TSFBridgeImpl::SetFocusedClient(HWND focused_window,
TextInputClient* client) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
DCHECK(client);
DCHECK(IsInitialized());
if (attached_window_handle_ != focused_window)
@@ -276,7 +276,7 @@ void TSFBridgeImpl::SetFocusedClient(HWND focused_window,
}
void TSFBridgeImpl::RemoveFocusedClient(TextInputClient* client) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
DCHECK(IsInitialized());
if (client_ != client)
return;
@@ -296,7 +296,7 @@ TextInputClient* TSFBridgeImpl::GetFocusedTextInputClient() const {
}
Microsoft::WRL::ComPtr<ITfThreadMgr> TSFBridgeImpl::GetThreadManager() {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
DCHECK(IsInitialized());
return thread_manager_;
}
@@ -492,7 +492,7 @@ TSFBridge::~TSFBridge() {}
// static
void TSFBridge::Initialize() {
- if (!base::MessageLoopForUI::IsCurrent()) {
+ if (!base::MessageLoopCurrentForUI::IsSet()) {
DVLOG(1) << "Do not use TSFBridge without UI thread.";
return;
}
@@ -509,7 +509,7 @@ void TSFBridge::Initialize() {
// static
TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) {
- if (!base::MessageLoopForUI::IsCurrent()) {
+ if (!base::MessageLoopCurrentForUI::IsSet()) {
DVLOG(1) << "Do not use TSFBridge without UI thread.";
return nullptr;
}
@@ -520,7 +520,7 @@ TSFBridge* TSFBridge::ReplaceForTesting(TSFBridge* bridge) {
// static
void TSFBridge::Shutdown() {
- if (!base::MessageLoopForUI::IsCurrent()) {
+ if (!base::MessageLoopCurrentForUI::IsSet()) {
DVLOG(1) << "Do not use TSFBridge without UI thread.";
}
TSFBridgeImpl* delegate = static_cast<TSFBridgeImpl*>(TSFBridgeTLS().Get());
@@ -530,7 +530,7 @@ void TSFBridge::Shutdown() {
// static
TSFBridge* TSFBridge::GetInstance() {
- if (!base::MessageLoopForUI::IsCurrent()) {
+ if (!base::MessageLoopCurrentForUI::IsSet()) {
DVLOG(1) << "Do not use TSFBridge without UI thread.";
return nullptr;
}
diff --git a/chromium/ui/base/ime/win/tsf_input_scope.cc b/chromium/ui/base/ime/win/tsf_input_scope.cc
index d11c207328c..2c0db97324f 100644
--- a/chromium/ui/base/ime/win/tsf_input_scope.cc
+++ b/chromium/ui/base/ime/win/tsf_input_scope.cc
@@ -158,7 +158,7 @@ InputScope ConvertTextInputModeToInputScope(TextInputMode text_input_mode) {
} // namespace
void InitializeTsfForInputScopes() {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
// Thread safety is not required because this function is under UI thread.
if (!g_get_proc_done) {
g_get_proc_done = true;
diff --git a/chromium/ui/base/l10n/l10n_util.cc b/chromium/ui/base/l10n/l10n_util.cc
index 506c5c68781..1eef9c217fb 100644
--- a/chromium/ui/base/l10n/l10n_util.cc
+++ b/chromium/ui/base/l10n/l10n_util.cc
@@ -471,6 +471,10 @@ std::string GetApplicationLocaleInternal(const std::string& pref_locale) {
#elif defined(OS_ANDROID)
+ // Try pref_locale first.
+ if (!pref_locale.empty())
+ candidates.push_back(base::i18n::GetCanonicalLocale(pref_locale));
+
// On Android, query java.util.Locale for the default locale.
candidates.push_back(base::android::GetDefaultLocaleString());
diff --git a/chromium/ui/base/l10n/l10n_util_mac.mm b/chromium/ui/base/l10n/l10n_util_mac.mm
index 6347acb9a8e..874a2948fbf 100644
--- a/chromium/ui/base/l10n/l10n_util_mac.mm
+++ b/chromium/ui/base/l10n/l10n_util_mac.mm
@@ -75,7 +75,7 @@ void OverrideLocaleWithCocoaLocale() {
// strings resources vs ICU generated strings). This also makes the Mac acts
// like other Chrome platforms.
NSArray* languageList = [base::mac::OuterBundle() preferredLocalizations];
- NSString* firstLocale = [languageList objectAtIndex:0];
+ NSString* firstLocale = languageList[0];
// Mac OS X uses "_" instead of "-", so swap to get a real locale value.
std::string locale_value =
[[firstLocale stringByReplacingOccurrencesOfString:@"_"
diff --git a/chromium/ui/base/layout.cc b/chromium/ui/base/layout.cc
index 027f357ea40..0a32eb28d8c 100644
--- a/chromium/ui/base/layout.cc
+++ b/chromium/ui/base/layout.cc
@@ -13,7 +13,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "build/build_config.h"
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/chromium/ui/base/material_design/material_design_controller.cc b/chromium/ui/base/material_design/material_design_controller.cc
index d23a4df67be..e9700d2188e 100644
--- a/chromium/ui/base/material_design/material_design_controller.cc
+++ b/chromium/ui/base/material_design/material_design_controller.cc
@@ -6,14 +6,14 @@
#include <string>
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
#include "base/no_destructor.h"
#include "base/observer_list.h"
#include "base/strings/string_number_conversions.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
#include "build/buildflag.h"
#include "ui/base/material_design/material_design_controller_observer.h"
#include "ui/base/ui_base_features.h"
@@ -23,102 +23,69 @@
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
-#if defined(OS_CHROMEOS)
-#include <fcntl.h>
-
-#include "base/files/file_enumerator.h"
-#include "base/files/scoped_file.h"
-#include "base/threading/thread_restrictions.h"
-#include "ui/base/touch/touch_device.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/ozone/evdev/event_device_info.h" // nogncheck
-#endif // defined(OS_CHROMEOS)
-
#if defined(OS_WIN)
#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
#include "ui/base/win/hidden_window.h"
+#include "ui/gfx/win/singleton_hwnd.h"
+#include "ui/gfx/win/singleton_hwnd_observer.h"
#endif
namespace ui {
-namespace {
-#if defined(OS_CHROMEOS)
+#if defined(OS_WIN)
+namespace {
-// Whether to use touchable UI.
-// http://crbug.com/875122 - Disabled by default on ChromeOS except on tablets.
-const base::Feature kTouchOptimizedUi = {"TouchOptimizedUi",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-MaterialDesignController::Mode GetDefaultTouchDeviceMode() {
- bool touch_optimized_ui_enabled =
- base::FeatureList::IsEnabled(kTouchOptimizedUi);
- return touch_optimized_ui_enabled
- ? MaterialDesignController::MATERIAL_TOUCH_REFRESH
- : MaterialDesignController::MATERIAL_REFRESH;
+bool IsTabletMode() {
+ return base::win::IsWindows10TabletMode(
+ gfx::SingletonHwnd::GetInstance()->hwnd());
}
-bool HasTouchscreen() {
- // If a scan of available devices has already completed, use that.
- if (DeviceDataManager::HasInstance() &&
- DeviceDataManager::GetInstance()->AreDeviceListsComplete())
- return GetTouchScreensAvailability() == TouchScreensAvailability::ENABLED;
-
- // Otherwise perform our own scan to determine the presence of a touchscreen.
- // Note this is a one-time call that occurs during device startup or restart.
- base::FileEnumerator file_enum(
- base::FilePath(FILE_PATH_LITERAL("/dev/input")), false,
- base::FileEnumerator::FILES, FILE_PATH_LITERAL("event*[0-9]"));
- for (base::FilePath path = file_enum.Next(); !path.empty();
- path = file_enum.Next()) {
- EventDeviceInfo devinfo;
- base::ScopedFD fd(
- open(path.value().c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC));
- if (fd.is_valid() && devinfo.Initialize(fd.get(), path) &&
- devinfo.HasTouchscreen())
- return true;
- }
-
- return false;
+void TabletModeWatcherWinProc(HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ if (message == WM_SETTINGCHANGE)
+ MaterialDesignController::OnTabletModeToggled(IsTabletMode());
}
-#endif // OS_CHROMEOS
-
} // namespace
+#endif // defined(OS_WIN)
-bool MaterialDesignController::is_mode_initialized_ = false;
-
-MaterialDesignController::Mode MaterialDesignController::mode_ =
- MaterialDesignController::MATERIAL_NORMAL;
-
-bool MaterialDesignController::is_refresh_dynamic_ui_ = false;
+bool MaterialDesignController::touch_ui_ = false;
+bool MaterialDesignController::automatic_touch_ui_ = false;
// static
void MaterialDesignController::Initialize() {
- TRACE_EVENT0("startup", "MaterialDesignController::InitializeMode");
- CHECK(!is_mode_initialized_);
-
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
const std::string switch_value =
- command_line->GetSwitchValueASCII(switches::kTopChromeMD);
-
- if (switch_value == switches::kTopChromeMDMaterialRefresh) {
- SetMode(MATERIAL_REFRESH);
- } else if (switch_value ==
- switches::kTopChromeMDMaterialRefreshTouchOptimized) {
- SetMode(MATERIAL_TOUCH_REFRESH);
- } else if (switch_value == switches::kTopChromeMDMaterialRefreshDynamic) {
- is_refresh_dynamic_ui_ = true;
-
+ command_line->GetSwitchValueASCII(switches::kTopChromeTouchUi);
+ bool touch = switch_value == switches::kTopChromeTouchUiEnabled;
+ automatic_touch_ui_ = switch_value == switches::kTopChromeTouchUiAuto;
+
+ // When the mode is not explicitly forced, platforms vary as to the default
+ // behavior.
+ if (!touch && (switch_value != switches::kTopChromeTouchUiDisabled) &&
+ features::IsAutomaticUiAdjustmentsForTouchEnabled()) {
+#if defined(OS_CHROMEOS)
// TabletModeClient's default state is in non-tablet mode.
- SetMode(MATERIAL_REFRESH);
- } else {
- if (!switch_value.empty()) {
- LOG(ERROR) << "Invalid value='" << switch_value
- << "' for command line switch '" << switches::kTopChromeMD
- << "'.";
+ automatic_touch_ui_ = true;
+#elif defined(OS_WIN)
+ if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
+ // Win 10+ uses dynamic mode by default and checks the current tablet mode
+ // state to determine whether to start in touch mode.
+ automatic_touch_ui_ = true;
+ if (base::MessageLoopCurrentForUI::IsSet() &&
+ !GetInstance()->singleton_hwnd_observer_) {
+ GetInstance()->singleton_hwnd_observer_ =
+ std::make_unique<gfx::SingletonHwndObserver>(
+ base::BindRepeating(TabletModeWatcherWinProc));
+ touch = IsTabletMode();
+ }
}
- SetMode(DefaultMode());
+#endif
}
+ SetTouchUi(touch);
// Ideally, there would be a more general, "initialize random stuff here"
// function into which these things and a call to this function can be placed.
@@ -134,34 +101,9 @@ void MaterialDesignController::Initialize() {
}
// static
-MaterialDesignController::Mode MaterialDesignController::GetMode() {
- CHECK(is_mode_initialized_);
- return mode_;
-}
-
-// static
-bool MaterialDesignController::IsTouchOptimizedUiEnabled() {
- return GetMode() == MATERIAL_TOUCH_OPTIMIZED ||
- GetMode() == MATERIAL_TOUCH_REFRESH;
-}
-
-// static
-MaterialDesignController::Mode MaterialDesignController::DefaultMode() {
-#if defined(OS_CHROMEOS)
- // This is called (once) early in device startup to initialize core UI, so
- // the UI thread should be blocked to perform the device query.
- base::ScopedAllowBlocking allow_io;
- if (HasTouchscreen())
- return GetDefaultTouchDeviceMode();
-#endif // defined(OS_CHROMEOS)
-
- return MATERIAL_REFRESH;
-}
-
-// static
void MaterialDesignController::OnTabletModeToggled(bool enabled) {
- if (is_refresh_dynamic_ui_)
- SetMode(enabled ? MATERIAL_TOUCH_REFRESH : MATERIAL_REFRESH);
+ if (automatic_touch_ui_)
+ SetTouchUi(enabled);
}
// static
@@ -183,17 +125,11 @@ void MaterialDesignController::RemoveObserver(
MaterialDesignController::MaterialDesignController() = default;
// static
-void MaterialDesignController::Uninitialize() {
- is_mode_initialized_ = false;
-}
-
-// static
-void MaterialDesignController::SetMode(MaterialDesignController::Mode mode) {
- if (!is_mode_initialized_ || mode_ != mode) {
- is_mode_initialized_ = true;
- mode_ = mode;
+void MaterialDesignController::SetTouchUi(bool touch_ui) {
+ if (touch_ui_ != touch_ui) {
+ touch_ui_ = touch_ui;
for (auto& observer : GetInstance()->observers_)
- observer.OnMdModeChanged();
+ observer.OnTouchUiChanged();
}
}
diff --git a/chromium/ui/base/material_design/material_design_controller.h b/chromium/ui/base/material_design/material_design_controller.h
index d66f2624b43..1e27b70bcfd 100644
--- a/chromium/ui/base/material_design/material_design_controller.h
+++ b/chromium/ui/base/material_design/material_design_controller.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
+#include "build/build_config.h"
#include "ui/base/ui_base_export.h"
namespace base {
@@ -14,6 +15,10 @@ template <typename T>
class NoDestructor;
}
+namespace gfx {
+class SingletonHwndObserver;
+}
+
namespace ui {
class MaterialDesignControllerObserver;
@@ -25,42 +30,17 @@ class MaterialDesignControllerTestAPI;
// Central controller to handle material design modes.
class UI_BASE_EXPORT MaterialDesignController {
public:
- // The different material design modes. The order cannot be changed without
- // updating references as these are used as array indices.
- enum Mode {
- // Basic material design.
- MATERIAL_NORMAL = 0,
- // Material design targeted at mouse/touch hybrid devices.
- MATERIAL_HYBRID = 1,
- // Material design that is more optimized for touch devices.
- MATERIAL_TOUCH_OPTIMIZED = 2,
- // Material Refresh design targeted at mouse devices.
- MATERIAL_REFRESH = 3,
- // Material Refresh design optimized for touch devices.
- MATERIAL_TOUCH_REFRESH = 4,
- };
-
- // Initializes |mode_|. Must be called before checking |mode_|.
+ // Initializes touch UI state based on command-line flags.
static void Initialize();
- // Get the current Mode that should be used by the system.
- static Mode GetMode();
-
- // Returns true if the touch-optimized UI material design mode is enabled.
- static bool IsTouchOptimizedUiEnabled();
-
- // Returns the per-platform default material design variant.
- static Mode DefaultMode();
+ static bool touch_ui() { return touch_ui_; }
// Exposed for TabletModeClient on ChromeOS + ash.
static void OnTabletModeToggled(bool enabled);
- static bool is_mode_initialized() { return is_mode_initialized_; }
-
static MaterialDesignController* GetInstance();
void AddObserver(MaterialDesignControllerObserver* observer);
-
void RemoveObserver(MaterialDesignControllerObserver* observer);
private:
@@ -68,28 +48,20 @@ class UI_BASE_EXPORT MaterialDesignController {
friend class test::MaterialDesignControllerTestAPI;
MaterialDesignController();
-
~MaterialDesignController() = delete;
- // Resets the initialization state to uninitialized. To be used by tests to
- // allow calling Initialize() more than once.
- static void Uninitialize();
-
- // Set |mode_| to |mode| and updates |is_mode_initialized_| to true. Can be
- // used by tests to directly set the mode.
- static void SetMode(Mode mode);
+ // Sets the touch UI state and notifies observers of the state change.
+ static void SetTouchUi(bool touch_ui);
- // Tracks whether |mode_| has been initialized. This is necessary to avoid
- // checking the |mode_| early in initialization before a call to Initialize().
- // Tests can use it to reset the state back to a clean state during tear down.
- static bool is_mode_initialized_;
+ // Whether the UI layout should be touch-optimized.
+ static bool touch_ui_;
- // The current Mode to be used by the system.
- static Mode mode_;
+ // Whether |touch_ui_| should toggle on and off depending on the tablet state.
+ static bool automatic_touch_ui_;
- // Whether |mode_| should toggle between MATERIAL_REFRESH and
- // MATERIAL_TOUCH_REFRESH depending on the tablet state.
- static bool is_refresh_dynamic_ui_;
+#if defined(OS_WIN)
+ std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
+#endif
base::ObserverList<MaterialDesignControllerObserver> observers_;
diff --git a/chromium/ui/base/material_design/material_design_controller_observer.h b/chromium/ui/base/material_design/material_design_controller_observer.h
index 5b7eba4bbc5..0cde0d2cc75 100644
--- a/chromium/ui/base/material_design/material_design_controller_observer.h
+++ b/chromium/ui/base/material_design/material_design_controller_observer.h
@@ -13,7 +13,7 @@ namespace ui {
class UI_BASE_EXPORT MaterialDesignControllerObserver
: public base::CheckedObserver {
public:
- virtual void OnMdModeChanged() = 0;
+ virtual void OnTouchUiChanged() = 0;
protected:
~MaterialDesignControllerObserver() override {}
diff --git a/chromium/ui/base/material_design/material_design_controller_unittest.cc b/chromium/ui/base/material_design/material_design_controller_unittest.cc
index c5a9075033f..41abb822e7a 100644
--- a/chromium/ui/base/material_design/material_design_controller_unittest.cc
+++ b/chromium/ui/base/material_design/material_design_controller_unittest.cc
@@ -6,23 +6,35 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "build/build_config.h"
+#include "base/scoped_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/material_design/material_design_controller_observer.h"
-#include "ui/base/test/material_design_controller_test_api.h"
#include "ui/base/ui_base_switches.h"
namespace ui {
-TEST(MaterialDesignControllerDeathTest, CrashesWithoutInitialization) {
- ASSERT_FALSE(MaterialDesignController::is_mode_initialized());
- EXPECT_DEATH_IF_SUPPORTED(
- MaterialDesignController::IsTouchOptimizedUiEnabled(), "");
-}
+using MD = MaterialDesignController;
+using MDObserver = MaterialDesignControllerObserver;
namespace {
+class TestObserver : public MDObserver {
+ public:
+ TestObserver() = default;
+ ~TestObserver() override = default;
+
+ int touch_ui_changes() const { return touch_ui_changes_; }
+
+ private:
+ // MDObserver:
+ void OnTouchUiChanged() override { ++touch_ui_changes_; }
+
+ int touch_ui_changes_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
// Test fixture for the MaterialDesignController class.
class MaterialDesignControllerTest : public testing::Test {
public:
@@ -33,153 +45,115 @@ class MaterialDesignControllerTest : public testing::Test {
// testing::Test:
void SetUp() override {
testing::Test::SetUp();
- MaterialDesignController::Initialize();
+ MD::Initialize();
}
void TearDown() override {
- test::MaterialDesignControllerTestAPI::Uninitialize();
testing::Test::TearDown();
}
void SetCommandLineSwitch(const std::string& value_string) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kTopChromeMD, value_string);
+ switches::kTopChromeTouchUi, value_string);
}
private:
DISALLOW_COPY_AND_ASSIGN(MaterialDesignControllerTest);
};
-} // namespace
-
-#if !defined(OS_CHROMEOS)
-// Verify that non-touch is the default.
-TEST_F(MaterialDesignControllerTest, NoCommandLineFlagIsRefresh) {
- ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kTopChromeMD));
- EXPECT_FALSE(MaterialDesignController::IsTouchOptimizedUiEnabled());
-}
-#endif
-
-namespace {
-
-class MaterialDesignControllerTestCommandLineRefresh
+class MaterialDesignControllerTestCommandLineTouchUiDisabled
: public MaterialDesignControllerTest {
public:
- MaterialDesignControllerTestCommandLineRefresh() {
- SetCommandLineSwitch(switches::kTopChromeMDMaterialRefresh);
+ MaterialDesignControllerTestCommandLineTouchUiDisabled() {
+ SetCommandLineSwitch(switches::kTopChromeTouchUiDisabled);
}
private:
- DISALLOW_COPY_AND_ASSIGN(MaterialDesignControllerTestCommandLineRefresh);
+ DISALLOW_COPY_AND_ASSIGN(
+ MaterialDesignControllerTestCommandLineTouchUiDisabled);
};
-} // namespace
-
-// Verify switches::kTopChromeMDMaterialRefresh maps to non-touch (the default).
-TEST_F(MaterialDesignControllerTestCommandLineRefresh, CheckApiReturns) {
- EXPECT_FALSE(MaterialDesignController::IsTouchOptimizedUiEnabled());
-}
-
-namespace {
-
-class MaterialDesignControllerTestCommandLineForceTouchRefresh
+class MaterialDesignControllerTestCommandLineTouchUiEnabled
: public MaterialDesignControllerTest {
public:
- MaterialDesignControllerTestCommandLineForceTouchRefresh() {
- SetCommandLineSwitch(switches::kTopChromeMDMaterialRefreshTouchOptimized);
+ MaterialDesignControllerTestCommandLineTouchUiEnabled() {
+ SetCommandLineSwitch(switches::kTopChromeTouchUiEnabled);
}
private:
DISALLOW_COPY_AND_ASSIGN(
- MaterialDesignControllerTestCommandLineForceTouchRefresh);
+ MaterialDesignControllerTestCommandLineTouchUiEnabled);
};
-} // namespace
-
-// Verify switches::kTopChromeMDMaterialRefreshTouchOptimized maps to touch.
-TEST_F(MaterialDesignControllerTestCommandLineForceTouchRefresh,
- CheckApiReturns) {
- EXPECT_TRUE(MaterialDesignController::IsTouchOptimizedUiEnabled());
-}
-
-namespace {
-
-class TestObserver : public ui::MaterialDesignControllerObserver {
+class MaterialDesignControllerTestCommandLineTouchUiAuto
+ : public MaterialDesignControllerTest {
public:
- TestObserver() = default;
- ~TestObserver() override = default;
-
- bool on_md_mode_changed_called() { return on_md_mode_changed_called_; }
+ MaterialDesignControllerTestCommandLineTouchUiAuto() {
+ SetCommandLineSwitch(switches::kTopChromeTouchUiAuto);
+ }
private:
- // ui::MaterialDesignControllerObserver:
- void OnMdModeChanged() override { on_md_mode_changed_called_ = true; }
-
- bool on_md_mode_changed_called_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(TestObserver);
+ DISALLOW_COPY_AND_ASSIGN(MaterialDesignControllerTestCommandLineTouchUiAuto);
};
} // namespace
-TEST(MaterialDesignControllerObserver, InitializationOnMdModeChanged) {
- // Verifies that the MaterialDesignControllerObserver gets called back when
- // the mode changes at startup.
- TestObserver observer;
- ASSERT_FALSE(observer.on_md_mode_changed_called());
- MaterialDesignController::GetInstance()->AddObserver(&observer);
-
- // Trigger a mode change by setting it for the first time.
- MaterialDesignController::Initialize();
-
- EXPECT_TRUE(observer.on_md_mode_changed_called());
-
- test::MaterialDesignControllerTestAPI::Uninitialize();
- MaterialDesignController::GetInstance()->RemoveObserver(&observer);
+// Verifies that non-touch is the default.
+TEST_F(MaterialDesignControllerTest, NoCommandLineFlagIsNonTouch) {
+ ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kTopChromeTouchUi));
+ EXPECT_FALSE(MD::touch_ui());
}
-TEST(MaterialDesignControllerObserver, TabletOnMdModeChanged) {
- // Verifies that the MaterialDesignControllerObserver gets called back when
- // the tablet mode toggles.
- test::MaterialDesignControllerTestAPI::SetDynamicRefreshUi(true);
-
- MaterialDesignController::Initialize();
- TestObserver tablet_enabled_observer;
- MaterialDesignController::GetInstance()->AddObserver(
- &tablet_enabled_observer);
- ASSERT_FALSE(tablet_enabled_observer.on_md_mode_changed_called());
-
-#if !defined(OS_CHROMEOS)
- EXPECT_FALSE(MaterialDesignController::IsTouchOptimizedUiEnabled());
-#endif
-
- MaterialDesignController::OnTabletModeToggled(true);
+// Verifies that switches::kTopChromeTouchUiDisabled maps to non-touch (the
+// default).
+TEST_F(MaterialDesignControllerTestCommandLineTouchUiDisabled,
+ CheckApiReturns) {
+ EXPECT_FALSE(MD::touch_ui());
+}
- EXPECT_TRUE(MaterialDesignController::IsTouchOptimizedUiEnabled());
+// Verifies that switches::kTopChromeTouchUiEnabled maps to touch.
+TEST_F(MaterialDesignControllerTestCommandLineTouchUiEnabled, CheckApiReturns) {
+ EXPECT_TRUE(MD::touch_ui());
+}
- EXPECT_TRUE(tablet_enabled_observer.on_md_mode_changed_called());
+// Verifies that switches::kTopChromeTouchUiAuto maps to non-touch.
+TEST_F(MaterialDesignControllerTestCommandLineTouchUiAuto, CheckApiReturns) {
+ EXPECT_FALSE(MD::touch_ui());
+}
- TestObserver tablet_disabled_observer;
- MaterialDesignController::GetInstance()->AddObserver(
- &tablet_disabled_observer);
- ASSERT_FALSE(tablet_disabled_observer.on_md_mode_changed_called());
+// Verifies that when the mode is set to non-touch and the tablet mode toggles,
+// the touch UI state does not change.
+TEST_F(MaterialDesignControllerTestCommandLineTouchUiDisabled,
+ TabletOnTouchUiChanged) {
+ TestObserver observer;
+ ScopedObserver<MD, MDObserver> scoped_observer(&observer);
+ scoped_observer.Add(MD::GetInstance());
- MaterialDesignController::OnTabletModeToggled(false);
+ MD::OnTabletModeToggled(true);
+ EXPECT_FALSE(MD::touch_ui());
+ EXPECT_EQ(0, observer.touch_ui_changes());
-#if !defined(OS_CHROMEOS)
- EXPECT_FALSE(MaterialDesignController::IsTouchOptimizedUiEnabled());
-#endif
+ MD::OnTabletModeToggled(false);
+ EXPECT_FALSE(MD::touch_ui());
+ EXPECT_EQ(0, observer.touch_ui_changes());
+}
- EXPECT_TRUE(tablet_disabled_observer.on_md_mode_changed_called());
+// Verifies that when the mode is set to auto and the tablet mode toggles, the
+// touch UI state changes and the observer gets called back.
+TEST_F(MaterialDesignControllerTestCommandLineTouchUiAuto,
+ TabletOnTouchUiChanged) {
+ TestObserver observer;
+ ScopedObserver<MD, MDObserver> scoped_observer(&observer);
+ scoped_observer.Add(MD::GetInstance());
- test::MaterialDesignControllerTestAPI::Uninitialize();
- MaterialDesignController::GetInstance()->RemoveObserver(
- &tablet_disabled_observer);
- MaterialDesignController::GetInstance()->RemoveObserver(
- &tablet_enabled_observer);
+ MD::OnTabletModeToggled(true);
+ EXPECT_TRUE(MD::touch_ui());
+ EXPECT_EQ(1, observer.touch_ui_changes());
- test::MaterialDesignControllerTestAPI::SetDynamicRefreshUi(false);
+ MD::OnTabletModeToggled(false);
+ EXPECT_FALSE(MD::touch_ui());
+ EXPECT_EQ(2, observer.touch_ui_changes());
}
} // namespace ui
diff --git a/chromium/ui/base/models/menu_model.h b/chromium/ui/base/models/menu_model.h
index a19e6e937f8..fb958b187f0 100644
--- a/chromium/ui/base/models/menu_model.h
+++ b/chromium/ui/base/models/menu_model.h
@@ -35,6 +35,9 @@ class UI_BASE_EXPORT MenuModel {
TYPE_BUTTON_ITEM, // Shows a row of buttons.
TYPE_SUBMENU, // Presents a submenu within another menu.
TYPE_ACTIONABLE_SUBMENU, // A SUBMENU that is also a COMMAND.
+ TYPE_HIGHLIGHTED, // Performs an action when selected, and has a different
+ // colored background. When placed at the bottom, the
+ // background matches the menu's rounded corners.
};
virtual ~MenuModel() {}
diff --git a/chromium/ui/base/models/simple_menu_model.cc b/chromium/ui/base/models/simple_menu_model.cc
index 5561c413a29..4aa19f6ea28 100644
--- a/chromium/ui/base/models/simple_menu_model.cc
+++ b/chromium/ui/base/models/simple_menu_model.cc
@@ -119,6 +119,15 @@ void SimpleMenuModel::AddRadioItemWithStringId(int command_id, int string_id,
AddRadioItem(command_id, l10n_util::GetStringUTF16(string_id), group_id);
}
+void SimpleMenuModel::AddHighlightedItemWithStringIdAndIcon(
+ int command_id,
+ int string_id,
+ const gfx::ImageSkia& icon) {
+ Item item(command_id, TYPE_HIGHLIGHTED, l10n_util::GetStringUTF16(string_id));
+ item.icon = gfx::Image(icon);
+ AppendItem(std::move(item));
+}
+
void SimpleMenuModel::AddSeparator(MenuSeparatorType separator_type) {
if (items_.empty()) {
if (separator_type == NORMAL_SEPARATOR) {
diff --git a/chromium/ui/base/models/simple_menu_model.h b/chromium/ui/base/models/simple_menu_model.h
index c1df3036694..ac1e1a78111 100644
--- a/chromium/ui/base/models/simple_menu_model.h
+++ b/chromium/ui/base/models/simple_menu_model.h
@@ -89,6 +89,9 @@ class UI_BASE_EXPORT SimpleMenuModel : public MenuModel {
void AddCheckItemWithStringId(int command_id, int string_id);
void AddRadioItem(int command_id, const base::string16& label, int group_id);
void AddRadioItemWithStringId(int command_id, int string_id, int group_id);
+ void AddHighlightedItemWithStringIdAndIcon(int command_id,
+ int string_id,
+ const gfx::ImageSkia& icon);
// Adds a separator of the specified type to the model.
// - Adding a separator after another separator is always invalid if they
diff --git a/chromium/ui/base/mojo/clipboard_client.cc b/chromium/ui/base/mojo/clipboard_client.cc
index ddc68980c18..0424a79d09a 100644
--- a/chromium/ui/base/mojo/clipboard_client.cc
+++ b/chromium/ui/base/mojo/clipboard_client.cc
@@ -10,6 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
+#include "skia/ext/skia_utils_base.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/custom_data_helper.h"
@@ -148,7 +149,12 @@ void ClipboardClient::WriteWebSmartPaste() {
void ClipboardClient::WriteBitmap(const SkBitmap& bitmap) {
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
- clipboard_->WriteBitmap(bitmap);
+ SkBitmap out_bitmap;
+ if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &out_bitmap)) {
+ NOTREACHED() << "Unable to convert bitmap for clipboard";
+ return;
+ }
+ clipboard_->WriteBitmap(out_bitmap);
}
void ClipboardClient::WriteData(const FormatType& format,
diff --git a/chromium/ui/base/page_transition_types.h b/chromium/ui/base/page_transition_types.h
index b77f25acc48..21773ad6241 100644
--- a/chromium/ui/base/page_transition_types.h
+++ b/chromium/ui/base/page_transition_types.h
@@ -162,7 +162,7 @@ UI_BASE_EXPORT bool PageTransitionTypeIncludingQualifiersIs(PageTransition lhs,
UI_BASE_EXPORT PageTransition PageTransitionStripQualifier(
PageTransition type);
-bool PageTransitionIsValidType(int32_t type);
+UI_BASE_EXPORT bool PageTransitionIsValidType(int32_t type);
UI_BASE_EXPORT PageTransition PageTransitionFromInt(int32_t type);
diff --git a/chromium/ui/base/touch/OWNERS b/chromium/ui/base/pointer/OWNERS
index b8e32c10903..b8e32c10903 100644
--- a/chromium/ui/base/touch/OWNERS
+++ b/chromium/ui/base/pointer/OWNERS
diff --git a/chromium/ui/base/touch/touch_device.cc b/chromium/ui/base/pointer/pointer_device.cc
index f29070abbc5..c3974973a75 100644
--- a/chromium/ui/base/touch/touch_device.cc
+++ b/chromium/ui/base/pointer/pointer_device.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
namespace ui {
diff --git a/chromium/ui/base/touch/touch_device.h b/chromium/ui/base/pointer/pointer_device.h
index 18daecb2b6f..19765542fb3 100644
--- a/chromium/ui/base/touch/touch_device.h
+++ b/chromium/ui/base/pointer/pointer_device.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_BASE_TOUCH_TOUCH_DEVICE_H_
-#define UI_BASE_TOUCH_TOUCH_DEVICE_H_
+#ifndef UI_BASE_POINTER_POINTER_DEVICE_H_
+#define UI_BASE_POINTER_POINTER_DEVICE_H_
#include <tuple>
@@ -14,9 +14,6 @@
#include <jni.h>
#endif
-// TODO(mustaq@chromium.org): This covers more than just touches. Rename to
-// input_device? crbug.com/438794
-
namespace ui {
enum class TouchScreensAvailability {
@@ -72,4 +69,4 @@ UI_BASE_EXPORT HoverType GetPrimaryHoverType(int available_hover_types);
} // namespace ui
-#endif // UI_BASE_TOUCH_TOUCH_DEVICE_H_
+#endif // UI_BASE_POINTER_POINTER_DEVICE_H_
diff --git a/chromium/ui/base/touch/touch_device_android.cc b/chromium/ui/base/pointer/pointer_device_android.cc
index 92febc1dcf8..b2b55bf0d11 100644
--- a/chromium/ui/base/touch/touch_device_android.cc
+++ b/chromium/ui/base/pointer/pointer_device_android.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
#include "base/android/jni_array.h"
#include "base/logging.h"
@@ -24,7 +24,7 @@ std::pair<int, int> AvailablePointerAndHoverTypes() {
JNIEnv* env = AttachCurrentThread();
std::vector<int> pointer_and_hover_types;
base::android::JavaIntArrayToIntVector(
- env, Java_TouchDevice_availablePointerAndHoverTypes(env).obj(),
+ env, Java_TouchDevice_availablePointerAndHoverTypes(env),
&pointer_and_hover_types);
DCHECK_EQ(pointer_and_hover_types.size(), 2u);
return std::make_pair(pointer_and_hover_types[0], pointer_and_hover_types[1]);
diff --git a/chromium/ui/base/touch/touch_device_ios.cc b/chromium/ui/base/pointer/pointer_device_ios.cc
index 18ffc7436d8..fa77b8451a0 100644
--- a/chromium/ui/base/touch/touch_device_ios.cc
+++ b/chromium/ui/base/pointer/pointer_device_ios.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
namespace ui {
diff --git a/chromium/ui/base/touch/touch_device_linux.cc b/chromium/ui/base/pointer/pointer_device_linux.cc
index b903997471f..8e538dbac29 100644
--- a/chromium/ui/base/touch/touch_device_linux.cc
+++ b/chromium/ui/base/pointer/pointer_device_linux.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
#include "base/logging.h"
#include "ui/events/devices/input_device_manager.h"
diff --git a/chromium/ui/base/touch/touch_device_util.cc b/chromium/ui/base/pointer/pointer_device_util.cc
index 734c020a6f2..ab74b766d53 100644
--- a/chromium/ui/base/touch/touch_device_util.cc
+++ b/chromium/ui/base/pointer/pointer_device_util.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
namespace ui {
@@ -11,7 +11,7 @@ namespace {
int available_pointer_types_for_testing = POINTER_TYPE_NONE;
int available_hover_types_for_testing = HOVER_TYPE_NONE;
bool return_available_pointer_and_hover_types_for_testing = false;
-}
+} // namespace
void SetAvailablePointerAndHoverTypesForTesting(int available_pointer_types,
int available_hover_types) {
diff --git a/chromium/ui/base/touch/touch_device_win.cc b/chromium/ui/base/pointer/pointer_device_win.cc
index 1cb49084c18..5f9839ea3e7 100644
--- a/chromium/ui/base/touch/touch_device_win.cc
+++ b/chromium/ui/base/pointer/pointer_device_win.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_device.h"
+#include "ui/base/pointer/pointer_device.h"
#include "base/logging.h"
#include "base/win/win_util.h"
@@ -15,7 +15,7 @@ namespace {
bool IsTouchDevicePresent() {
int value = GetSystemMetrics(SM_DIGITIZER);
return (value & NID_READY) &&
- ((value & NID_INTEGRATED_TOUCH) || (value & NID_EXTERNAL_TOUCH));
+ ((value & NID_INTEGRATED_TOUCH) || (value & NID_EXTERNAL_TOUCH));
}
} // namespace
diff --git a/chromium/ui/base/touch/touch_editing_controller.cc b/chromium/ui/base/pointer/touch_editing_controller.cc
index 79a70ec63a2..08c842f0d7e 100644
--- a/chromium/ui/base/touch/touch_editing_controller.cc
+++ b/chromium/ui/base/pointer/touch_editing_controller.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/base/pointer/touch_editing_controller.h"
namespace ui {
diff --git a/chromium/ui/base/touch/touch_editing_controller.h b/chromium/ui/base/pointer/touch_editing_controller.h
index bfa17bcdc87..e735129b4dc 100644
--- a/chromium/ui/base/touch/touch_editing_controller.h
+++ b/chromium/ui/base/pointer/touch_editing_controller.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_BASE_TOUCH_TOUCH_EDITING_CONTROLLER_H_
-#define UI_BASE_TOUCH_TOUCH_EDITING_CONTROLLER_H_
+#ifndef UI_BASE_POINTER_TOUCH_EDITING_CONTROLLER_H_
+#define UI_BASE_POINTER_TOUCH_EDITING_CONTROLLER_H_
#include "ui/base/models/simple_menu_model.h"
@@ -11,7 +11,7 @@ namespace gfx {
class Point;
class Rect;
class SelectionBound;
-}
+} // namespace gfx
namespace ui {
@@ -76,8 +76,7 @@ class UI_BASE_EXPORT TouchEditingControllerDeprecated {
// Creates a TouchEditingControllerDeprecated. Caller owns the returned
// object.
- static TouchEditingControllerDeprecated* Create(
- TouchEditable* client_view);
+ static TouchEditingControllerDeprecated* Create(TouchEditable* client_view);
// Notifies the controller that the selection has changed.
virtual void SelectionChanged() = 0;
@@ -96,10 +95,10 @@ class UI_BASE_EXPORT TouchEditingControllerFactory {
static void SetInstance(TouchEditingControllerFactory* instance);
- virtual TouchEditingControllerDeprecated* Create(TouchEditable* client_view)
- = 0;
+ virtual TouchEditingControllerDeprecated* Create(
+ TouchEditable* client_view) = 0;
};
} // namespace ui
-#endif // UI_BASE_TOUCH_TOUCH_EDITING_CONTROLLER_H_
+#endif // UI_BASE_POINTER_TOUCH_EDITING_CONTROLLER_H_
diff --git a/chromium/ui/base/resource/resource_bundle.cc b/chromium/ui/base/resource/resource_bundle.cc
index d6d21eeb8ef..c371212e0ce 100644
--- a/chromium/ui/base/resource/resource_bundle.cc
+++ b/chromium/ui/base/resource/resource_bundle.cc
@@ -50,7 +50,7 @@
#endif
#if defined(OS_CHROMEOS)
-#include "ui/gfx/platform_font_linux.h"
+#include "ui/gfx/platform_font_skia.h"
#endif
#if defined(OS_WIN)
@@ -798,7 +798,7 @@ void ResourceBundle::InitDefaultFontList() {
// TODO(yukishiino): Remove SetDefaultFontDescription() once the migration to
// the font list is done. We will no longer need SetDefaultFontDescription()
// after every client gets started using a FontList instead of a Font.
- gfx::PlatformFontLinux::SetDefaultFontDescription(font_family);
+ gfx::PlatformFontSkia::SetDefaultFontDescription(font_family);
#else
// Use a single default font as the default font list.
gfx::FontList::SetDefaultFontDescription(std::string());
diff --git a/chromium/ui/base/resource/resource_bundle_mac.mm b/chromium/ui/base/resource/resource_bundle_mac.mm
index 873989c5017..ef20c6be5cb 100644
--- a/chromium/ui/base/resource/resource_bundle_mac.mm
+++ b/chromium/ui/base/resource/resource_bundle_mac.mm
@@ -134,7 +134,7 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id) {
return GetEmptyImage();
}
- image = gfx::Image(ns_image.release());
+ image = gfx::Image(ns_image);
}
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromium/ui/base/resource/resource_bundle_unittest.cc b/chromium/ui/base/resource/resource_bundle_unittest.cc
index 1d61db04987..710b274ef59 100644
--- a/chromium/ui/base/resource/resource_bundle_unittest.cc
+++ b/chromium/ui/base/resource/resource_bundle_unittest.cc
@@ -175,13 +175,7 @@ TEST_F(ResourceBundleTest, DelegateGetPathForResourcePack) {
resource_bundle->AddDataPackFromPath(pack_path, pack_scale_factor);
}
-#if defined(OS_LINUX)
-// Fails consistently on Linux: crbug.com/161902
-#define MAYBE_DelegateGetPathForLocalePack DISABLED_DelegateGetPathForLocalePack
-#else
-#define MAYBE_DelegateGetPathForLocalePack DelegateGetPathForLocalePack
-#endif
-TEST_F(ResourceBundleTest, MAYBE_DelegateGetPathForLocalePack) {
+TEST_F(ResourceBundleTest, DelegateGetPathForLocalePack) {
ResourceBundle::CleanupSharedInstance();
MockResourceBundleDelegate delegate;
@@ -584,13 +578,16 @@ TEST_F(ResourceBundleImageTest, GetImageNamedFallback1xRounding) {
}
#endif
-#if defined(OS_IOS)
-// Fails on devices that have non-100P scaling. See crbug.com/298406
-#define MAYBE_FallbackToNone DISABLED_FallbackToNone
-#else
-#define MAYBE_FallbackToNone FallbackToNone
-#endif
-TEST_F(ResourceBundleImageTest, MAYBE_FallbackToNone) {
+TEST_F(ResourceBundleImageTest, FallbackToNone) {
+ std::vector<ScaleFactor> supported_factors;
+ supported_factors.push_back(SCALE_FACTOR_100P);
+ supported_factors.push_back(SCALE_FACTOR_200P);
+ supported_factors.push_back(SCALE_FACTOR_300P);
+
+ // Presents a consistent set of supported scale factors for all platforms.
+ // iOS does not include SCALE_FACTOR_100P, which breaks the test below.
+ test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
+
base::FilePath data_default_path = dir_path().AppendASCII("sample.pak");
// Create the pak files.
diff --git a/chromium/ui/base/ui_base_features.cc b/chromium/ui/base/ui_base_features.cc
index 674998b13af..548c51dc17f 100644
--- a/chromium/ui/base/ui_base_features.cc
+++ b/chromium/ui/base/ui_base_features.cc
@@ -12,6 +12,11 @@
namespace features {
+#if defined(OS_WIN)
+// If enabled, calculate native window occlusion - Windows-only.
+const base::Feature kCalculateNativeWinOcclusion{
+ "CalculateNativeWinOcclusion", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // OW_WIN
// If enabled, the emoji picker context menu item may be shown for editable
// text areas.
const base::Feature kEnableEmojiContextMenu {
@@ -23,10 +28,6 @@ const base::Feature kEnableEmojiContextMenu {
#endif
};
-// Enables the floating virtual keyboard behavior.
-const base::Feature kEnableFloatingVirtualKeyboard = {
- "enable-floating-virtual-keyboard", base::FEATURE_ENABLED_BY_DEFAULT};
-
// Enables the full screen handwriting virtual keyboard behavior.
const base::Feature kEnableFullscreenHandwritingVirtualKeyboard = {
"enable-fullscreen-handwriting-virtual-keyboard",
@@ -35,10 +36,6 @@ const base::Feature kEnableFullscreenHandwritingVirtualKeyboard = {
const base::Feature kEnableStylusVirtualKeyboard = {
"enable-stylus-virtual-keyboard", base::FEATURE_ENABLED_BY_DEFAULT};
-// If enabled, uses the Material Design UI for virtual keyboard.
-const base::Feature kEnableVirtualKeyboardMdUi = {
- "EnableVirtualKeyboardMdUi", base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kEnableVirtualKeyboardUkm = {
"EnableVirtualKeyboardUkm", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -46,6 +43,18 @@ const base::Feature kEnableVirtualKeyboardUkm = {
const base::Feature kExperimentalUi{"ExperimentalUi",
base::FEATURE_DISABLED_BY_DEFAULT};
+#if defined(OS_CHROMEOS)
+// Integrate input method specific settings to Chrome OS settings page.
+// https://crbug.com/895886.
+const base::Feature kSettingsShowsPerKeyboardSettings = {
+ "InputMethodIntegratedSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_CHROMEOS)
+
+// Update of the virtual keyboard settings UI as described in
+// https://crbug.com/876901.
+const base::Feature kInputMethodSettingsUiUpdate = {
+ "InputMethodSettingsUiUpdate", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Allows system keyboard event capture when |features::kKeyboardLockApi| is on.
const base::Feature kSystemKeyboardLock{"SystemKeyboardLock",
base::FEATURE_ENABLED_BY_DEFAULT};
@@ -115,6 +124,11 @@ const base::Feature kPrecisionTouchpadScrollPhase{
"PrecisionTouchpadScrollPhase", base::FEATURE_ENABLED_BY_DEFAULT};
#endif // defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+const base::Feature kEnableAutomaticUiAdjustmentsForTouch{
+ "EnableAutomaticUiAdjustmentsForTouch", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // defined(OS_WIN) || defined(OS_CHROMEOS)
+
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
// Enables stylus appearing as touch when in contact with digitizer.
const base::Feature kDirectManipulationStylus = {
@@ -129,6 +143,9 @@ const base::Feature kDirectManipulationStylus = {
const base::Feature kMash = {"Mash", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kMashOopViz = {"MashOopViz",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kSingleProcessMash = {"SingleProcessMash",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -140,10 +157,23 @@ bool IsMultiProcessMash() {
return base::FeatureList::IsEnabled(features::kMash);
}
+bool IsMashOopVizEnabled() {
+ return base::FeatureList::IsEnabled(features::kMashOopViz);
+}
+
bool IsSingleProcessMash() {
return base::FeatureList::IsEnabled(features::kSingleProcessMash);
}
+bool IsAutomaticUiAdjustmentsForTouchEnabled() {
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+ return base::FeatureList::IsEnabled(
+ features::kEnableAutomaticUiAdjustmentsForTouch);
+#else
+ return false;
+#endif
+}
+
#if defined(OS_MACOSX)
// When enabled, the NSWindows for apps will be created in the app's process,
// and will forward input to the browser process.
diff --git a/chromium/ui/base/ui_base_features.h b/chromium/ui/base/ui_base_features.h
index 4a799dda3c5..2a3e2546039 100644
--- a/chromium/ui/base/ui_base_features.h
+++ b/chromium/ui/base/ui_base_features.h
@@ -14,13 +14,15 @@ namespace features {
// Keep sorted!
UI_BASE_EXPORT extern const base::Feature kEnableEmojiContextMenu;
-UI_BASE_EXPORT extern const base::Feature kEnableFloatingVirtualKeyboard;
UI_BASE_EXPORT extern const base::Feature
kEnableFullscreenHandwritingVirtualKeyboard;
UI_BASE_EXPORT extern const base::Feature kEnableStylusVirtualKeyboard;
-UI_BASE_EXPORT extern const base::Feature kEnableVirtualKeyboardMdUi;
UI_BASE_EXPORT extern const base::Feature kEnableVirtualKeyboardUkm;
UI_BASE_EXPORT extern const base::Feature kExperimentalUi;
+#if defined(OS_CHROMEOS)
+UI_BASE_EXPORT extern const base::Feature kSettingsShowsPerKeyboardSettings;
+#endif // defined(OS_CHROMEOS)
+UI_BASE_EXPORT extern const base::Feature kInputMethodSettingsUiUpdate;
UI_BASE_EXPORT extern const base::Feature kSystemKeyboardLock;
UI_BASE_EXPORT extern const base::Feature kTouchableAppContextMenu;
UI_BASE_EXPORT extern const base::Feature kNotificationIndicator;
@@ -32,6 +34,7 @@ UI_BASE_EXPORT bool IsNotificationIndicatorEnabled();
UI_BASE_EXPORT bool IsUiGpuRasterizationEnabled();
#if defined(OS_WIN)
+UI_BASE_EXPORT extern const base::Feature kCalculateNativeWinOcclusion;
UI_BASE_EXPORT extern const base::Feature kInputPaneOnScreenKeyboard;
UI_BASE_EXPORT extern const base::Feature kPointerEventsForTouch;
UI_BASE_EXPORT extern const base::Feature kPrecisionTouchpad;
@@ -42,6 +45,10 @@ UI_BASE_EXPORT extern const base::Feature kTSFImeSupport;
UI_BASE_EXPORT bool IsUsingWMPointerForTouch();
#endif // defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+UI_BASE_EXPORT extern const base::Feature kEnableAutomaticUiAdjustmentsForTouch;
+#endif // defined(OS_WIN) || defined(OS_CHROMEOS)
+
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
UI_BASE_EXPORT extern const base::Feature kDirectManipulationStylus;
#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
@@ -50,6 +57,12 @@ UI_BASE_EXPORT extern const base::Feature kDirectManipulationStylus;
// TODO(jamescook): Make flag only available in Chrome OS.
UI_BASE_EXPORT extern const base::Feature kMash;
+// Used to run Viz in its own process when kMash is enabled. Viz is run in Ash
+// process by default.
+// TODO(mohsen): Remove this when Viz can run fully in a separate process. Then
+// make it the default kMash behavior.
+UI_BASE_EXPORT extern const base::Feature kMashOopViz;
+
UI_BASE_EXPORT extern const base::Feature kSingleProcessMash;
// Returns true if Chrome's aura usage is backed by the WindowService.
@@ -59,6 +72,8 @@ UI_BASE_EXPORT bool IsUsingWindowService();
// service and Viz graphics). See //ash/README.md.
UI_BASE_EXPORT bool IsMultiProcessMash();
+UI_BASE_EXPORT bool IsMashOopVizEnabled();
+
// Returns true if code outside of ash is using the WindowService. In this mode
// there are two aura::Envs. Ash uses one with Env::Mode::LOCAL. Non-ash code
// uses an aura::Env with a mode of MUS. The non-ash code using mus targets the
@@ -67,6 +82,9 @@ UI_BASE_EXPORT bool IsMultiProcessMash();
// See //ash/README.md.
UI_BASE_EXPORT bool IsSingleProcessMash();
+// Whether the UI may accommodate touch input in response to hardware changes.
+UI_BASE_EXPORT bool IsAutomaticUiAdjustmentsForTouchEnabled();
+
#if defined(OS_MACOSX)
UI_BASE_EXPORT extern const base::Feature kHostWindowsInAppShimProcess;
diff --git a/chromium/ui/base/ui_base_switches.cc b/chromium/ui/base/ui_base_switches.cc
index c14baff0863..99cd8eac41d 100644
--- a/chromium/ui/base/ui_base_switches.cc
+++ b/chromium/ui/base/ui_base_switches.cc
@@ -70,21 +70,11 @@ const char kMaterialDesignInkDropAnimationSpeedFast[] = "fast";
// Defines that Material Design visual feedback animations should be slow.
const char kMaterialDesignInkDropAnimationSpeedSlow[] = "slow";
-// Enables top Chrome material design elements.
-const char kTopChromeMD[] = "top-chrome-md";
-
-// Material design mode that represents a refresh of the Chrome UI for the
-// |kTopChromeMD| switch.
-const char kTopChromeMDMaterialRefresh[] = "material-refresh";
-
-// Material design mode that represents a touchable version of material-refresh
-// for the |kTopChromeMD| switch.
-const char kTopChromeMDMaterialRefreshTouchOptimized[] =
- "material-refresh-touch-optimized";
-
-// Switches between material refresh and touchable material refresh depending on
-// the tablet mode.
-const char kTopChromeMDMaterialRefreshDynamic[] = "material-refresh-dynamic";
+// Controls touch-optimized UI layout for top chrome.
+const char kTopChromeTouchUi[] = "top-chrome-touch-ui";
+const char kTopChromeTouchUiAuto[] = "auto";
+const char kTopChromeTouchUiDisabled[] = "disabled";
+const char kTopChromeTouchUiEnabled[] = "enabled";
// Disable partial swap which is needed for some OpenGL drivers / emulators.
const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
diff --git a/chromium/ui/base/ui_base_switches.h b/chromium/ui/base/ui_base_switches.h
index 0c8c5957d48..0ac60c1cd6b 100644
--- a/chromium/ui/base/ui_base_switches.h
+++ b/chromium/ui/base/ui_base_switches.h
@@ -36,10 +36,10 @@ UI_BASE_EXPORT extern const char kMaterialDesignInkDropAnimationSpeedSlow[];
UI_BASE_EXPORT extern const char kShowOverdrawFeedback[];
UI_BASE_EXPORT extern const char kSlowDownCompositingScaleFactor[];
UI_BASE_EXPORT extern const char kTintGlCompositedContent[];
-UI_BASE_EXPORT extern const char kTopChromeMD[];
-UI_BASE_EXPORT extern const char kTopChromeMDMaterialRefresh[];
-UI_BASE_EXPORT extern const char kTopChromeMDMaterialRefreshTouchOptimized[];
-UI_BASE_EXPORT extern const char kTopChromeMDMaterialRefreshDynamic[];
+UI_BASE_EXPORT extern const char kTopChromeTouchUi[];
+UI_BASE_EXPORT extern const char kTopChromeTouchUiAuto[];
+UI_BASE_EXPORT extern const char kTopChromeTouchUiDisabled[];
+UI_BASE_EXPORT extern const char kTopChromeTouchUiEnabled[];
UI_BASE_EXPORT extern const char kUIDisablePartialSwap[];
// Test related.
diff --git a/chromium/ui/base/win/mouse_wheel_util.cc b/chromium/ui/base/win/mouse_wheel_util.cc
index 020c70c17bf..1e5d0ca070b 100644
--- a/chromium/ui/base/win/mouse_wheel_util.cc
+++ b/chromium/ui/base/win/mouse_wheel_util.cc
@@ -4,9 +4,8 @@
#include "ui/base/win/mouse_wheel_util.h"
-#include <windowsx.h>
-
#include "base/auto_reset.h"
+#include "base/win/windowsx_shim.h"
#include "ui/base/view_prop.h"
#include "ui/gfx/win/hwnd_util.h"
diff --git a/chromium/ui/base/win/open_file_name_win.cc b/chromium/ui/base/win/open_file_name_win.cc
deleted file mode 100644
index ccc72030340..00000000000
--- a/chromium/ui/base/win/open_file_name_win.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/win/open_file_name_win.h"
-
-#include "base/files/file_path.h"
-#include "base/strings/string_util.h"
-
-namespace ui {
-namespace win {
-
-OpenFileName::OpenFileName(HWND parent_window, DWORD flags) {
- ::ZeroMemory(&openfilename_, sizeof(openfilename_));
- openfilename_.lStructSize = sizeof(openfilename_);
-
- // According to http://support.microsoft.com/?scid=kb;en-us;222003&x=8&y=12,
- // The lpstrFile Buffer MUST be NULL Terminated.
- filename_buffer_[0] = 0;
- openfilename_.lpstrFile = filename_buffer_;
- openfilename_.nMaxFile = arraysize(filename_buffer_);
-
- openfilename_.Flags = flags;
- openfilename_.hwndOwner = parent_window;
-}
-
-OpenFileName::~OpenFileName() {
-}
-
-void OpenFileName::SetFilters(
- const std::vector<std::tuple<base::string16, base::string16>>& filters) {
- openfilename_.lpstrFilter = NULL;
- filter_buffer_.clear();
- if (filters.empty())
- return;
- for (const auto& filter : filters) {
- filter_buffer_.append(std::get<0>(filter));
- filter_buffer_.push_back(0);
- filter_buffer_.append(std::get<1>(filter));
- filter_buffer_.push_back(0);
- }
- filter_buffer_.push_back(0);
- openfilename_.lpstrFilter = filter_buffer_.c_str();
-}
-
-void OpenFileName::SetInitialSelection(const base::FilePath& initial_directory,
- const base::FilePath& initial_filename) {
- // First reset to the default case.
- // According to http://support.microsoft.com/?scid=kb;en-us;222003&x=8&y=12,
- // The lpstrFile Buffer MUST be NULL Terminated.
- filename_buffer_[0] = 0;
- openfilename_.lpstrFile = filename_buffer_;
- openfilename_.nMaxFile = arraysize(filename_buffer_);
- openfilename_.lpstrInitialDir = NULL;
- initial_directory_buffer_.clear();
-
- if (initial_directory.empty())
- return;
-
- initial_directory_buffer_ = initial_directory.value();
- openfilename_.lpstrInitialDir = initial_directory_buffer_.c_str();
-
- if (initial_filename.empty())
- return;
-
- // The filename is ignored if no initial directory is supplied.
- base::wcslcpy(filename_buffer_,
- initial_filename.value().c_str(),
- arraysize(filename_buffer_));
-}
-
-base::FilePath OpenFileName::GetSingleResult() {
- base::FilePath directory;
- std::vector<base::FilePath> filenames;
- GetResult(&directory, &filenames);
- if (filenames.size() != 1 || filenames[0].empty())
- return base::FilePath();
- return directory.Append(filenames[0]);
-}
-
-void OpenFileName::GetResult(base::FilePath* directory,
- std::vector<base::FilePath>* filenames) {
- DCHECK(filenames->empty());
- const wchar_t* selection = openfilename_.lpstrFile;
- // The return value of |openfilename_.lpstrFile| is dependent on the
- // value of the Multi-Select flag within |openfilename_|. If the flag is
- // not set the return value will be a single null-terminated wide string.
- // If it is set it will be more than one null-terminated wide string, itself
- // terminated by an empty null-terminated wide string.
- if (openfilename_.Flags & OFN_ALLOWMULTISELECT) {
- while (*selection) { // Empty string indicates end of list.
- filenames->push_back(base::FilePath(selection));
- // Skip over filename and null-terminator.
- selection += filenames->back().value().length() + 1;
- }
- } else {
- filenames->push_back(base::FilePath(selection));
- }
- if (filenames->size() == 1) {
- // When there is one file, it contains the path and filename.
- *directory = (*filenames)[0].DirName();
- (*filenames)[0] = (*filenames)[0].BaseName();
- } else if (filenames->size() > 1) {
- // Otherwise, the first string is the path, and the remainder are
- // filenames.
- *directory = (*filenames)[0];
- filenames->erase(filenames->begin());
- }
-}
-
-// static
-void OpenFileName::SetResult(const base::FilePath& directory,
- const std::vector<base::FilePath>& filenames,
- OPENFILENAME* openfilename) {
- base::string16 filename_value;
- if (filenames.size() == 1) {
- filename_value = directory.Append(filenames[0]).value();
- } else {
- filename_value = directory.value();
- filename_value.push_back(0);
- for (std::vector<base::FilePath>::const_iterator it = filenames.begin();
- it != filenames.end();
- ++it) {
- filename_value.append(it->value());
- filename_value.push_back(0);
- }
- }
- if (filename_value.size() + 1 < openfilename->nMaxFile) {
- // Because the result has embedded nulls, we must memcpy.
- memcpy(openfilename->lpstrFile,
- filename_value.c_str(),
- (filename_value.size() + 1) * sizeof(filename_value[0]));
- } else if (openfilename->nMaxFile) {
- openfilename->lpstrFile[0] = 0;
- }
-}
-
-// static
-std::vector<std::tuple<base::string16, base::string16>>
-OpenFileName::GetFilters(const OPENFILENAME* openfilename) {
- std::vector<std::tuple<base::string16, base::string16>> filters;
-
- const base::char16* display_string = openfilename->lpstrFilter;
- if (!display_string)
- return filters;
-
- while (*display_string) {
- const base::char16* display_string_end = display_string;
- while (*display_string_end)
- ++display_string_end;
- const base::char16* pattern = display_string_end + 1;
- const base::char16* pattern_end = pattern;
- while (*pattern_end)
- ++pattern_end;
- filters.push_back(
- std::make_tuple(base::string16(display_string, display_string_end),
- base::string16(pattern, pattern_end)));
- display_string = pattern_end + 1;
- }
-
- return filters;
-}
-
-} // namespace win
-} // namespace ui
diff --git a/chromium/ui/base/win/open_file_name_win.h b/chromium/ui/base/win/open_file_name_win.h
deleted file mode 100644
index b0b32a9f39a..00000000000
--- a/chromium/ui/base/win/open_file_name_win.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 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_BASE_WIN_OPEN_FILE_NAME_WIN_H_
-#define UI_BASE_WIN_OPEN_FILE_NAME_WIN_H_
-
-#include <Windows.h>
-#include <Commdlg.h>
-
-#include <tuple>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "ui/base/ui_base_export.h"
-
-namespace base {
-class FilePath;
-} // namespace base
-
-namespace ui {
-namespace win {
-
-// Encapsulates an OPENFILENAME struct and related buffers. Also provides static
-// methods for interpreting the properties of an OPENFILENAME.
-class UI_BASE_EXPORT OpenFileName {
- public:
- // Initializes the OPENFILENAME, which may be accessed using Get(). All fields
- // will be NULL except for |lStructSize|, |lpstrFile|, and |nMaxFile|. The
- // file buffer will initially contain a null-terminated empty string.
- OpenFileName(HWND parent_window, DWORD flags);
- ~OpenFileName();
-
- // Initializes |lpstrFilter| from the label/pattern pairs in |filters|.
- void SetFilters(
- const std::vector<std::tuple<base::string16, base::string16>>& filters);
-
- // Sets |lpstrInitialDir| and |lpstrFile|.
- void SetInitialSelection(const base::FilePath& initial_directory,
- const base::FilePath& initial_filename);
-
- // Returns the single selected file, or an empty path if there are more or
- // less than one results.
- base::FilePath GetSingleResult();
-
- // Returns the selected file or files.
- void GetResult(base::FilePath* directory,
- std::vector<base::FilePath>* filenames);
-
- // Returns the OPENFILENAME structure.
- OPENFILENAME* GetOPENFILENAME() { return &openfilename_; }
-
- // Returns the OPENFILENAME structure.
- const OPENFILENAME* GetOPENFILENAME() const { return &openfilename_; }
-
- // Stores directory and filenames in the buffer pointed to by
- // |openfilename->lpstrFile| and sized |openfilename->nMaxFile|.
- static void SetResult(const base::FilePath& directory,
- const std::vector<base::FilePath>& filenames,
- OPENFILENAME* openfilename);
-
- // Returns a vector of label/pattern pairs built from
- // |openfilename->lpstrFilter|.
- static std::vector<std::tuple<base::string16, base::string16>> GetFilters(
- const OPENFILENAME* openfilename);
-
- private:
- OPENFILENAME openfilename_;
- base::string16 initial_directory_buffer_;
- wchar_t filename_buffer_[UNICODE_STRING_MAX_CHARS];
- base::string16 filter_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(OpenFileName);
-};
-
-} // namespace win
-} // namespace ui
-
-#endif // UI_BASE_WIN_OPEN_FILE_NAME_WIN_H_
diff --git a/chromium/ui/base/win/open_file_name_win_unittest.cc b/chromium/ui/base/win/open_file_name_win_unittest.cc
deleted file mode 100644
index a6e6ff1f8fb..00000000000
--- a/chromium/ui/base/win/open_file_name_win_unittest.cc
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/win/open_file_name_win.h"
-
-#include <stddef.h>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const HWND kHwnd = reinterpret_cast<HWND>(0xDEADBEEF);
-const DWORD kFlags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING;
-
-void SetResult(const base::string16& result, ui::win::OpenFileName* ofn) {
- if (ofn->GetOPENFILENAME()->nMaxFile <= result.size()) {
- ADD_FAILURE() << "filename buffer insufficient.";
- return;
- }
- if (result.empty()) {
- ofn->GetOPENFILENAME()->lpstrFile[0] = 0;
- } else {
- // Because the result has embedded nulls, we must memcpy.
- memcpy(ofn->GetOPENFILENAME()->lpstrFile,
- result.c_str(),
- (result.size() + 1) * sizeof(result[0]));
- }
-}
-
-void CheckFilters(
- const std::vector<std::tuple<base::string16, base::string16>>& expected,
- const std::vector<std::tuple<base::string16, base::string16>>& actual) {
- if (expected.size() != actual.size()) {
- ADD_FAILURE() << "filter count mismatch. Got " << actual.size()
- << " expected " << expected.size() << ".";
- return;
- }
-
- for (size_t i = 0; i < expected.size(); ++i) {
- EXPECT_EQ(std::get<0>(expected[i]), std::get<0>(actual[i]))
- << "Mismatch at index " << i;
- EXPECT_EQ(std::get<1>(expected[i]), std::get<1>(actual[i]))
- << "Mismatch at index " << i;
- }
-}
-
-void CheckFilterString(const base::string16& expected,
- const ui::win::OpenFileName& ofn) {
- if (!ofn.GetOPENFILENAME()->lpstrFilter) {
- ADD_FAILURE() << "Filter string is NULL.";
- return;
- }
- if (expected.size() == 0) {
- EXPECT_EQ(0, ofn.GetOPENFILENAME()->lpstrFilter[0]);
- } else {
- EXPECT_EQ(0,
- memcmp(expected.c_str(),
- ofn.GetOPENFILENAME()->lpstrFilter,
- expected.size() + 1 * sizeof(expected[0])));
- }
-}
-
-void CheckResult(const base::string16& expected,
- const ui::win::OpenFileName& ofn) {
- if (!ofn.GetOPENFILENAME()->lpstrFile) {
- ADD_FAILURE() << "File string is NULL.";
- return;
- }
- if (expected.size() == 0) {
- EXPECT_EQ(0, ofn.GetOPENFILENAME()->lpstrFile[0]);
- } else {
- EXPECT_EQ(0,
- memcmp(expected.c_str(),
- ofn.GetOPENFILENAME()->lpstrFile,
- expected.size() + 1 * sizeof(expected[0])));
- }
-}
-
-} // namespace
-
-TEST(OpenFileNameTest, Initialization) {
- ui::win::OpenFileName ofn(kHwnd, kFlags);
- EXPECT_EQ(kHwnd, ofn.GetOPENFILENAME()->hwndOwner);
- EXPECT_EQ(kFlags, ofn.GetOPENFILENAME()->Flags);
- EXPECT_EQ(sizeof(OPENFILENAME), ofn.GetOPENFILENAME()->lStructSize);
- ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile);
- ASSERT_GT(ofn.GetOPENFILENAME()->nMaxFile, 0u);
- EXPECT_EQ(0, ofn.GetOPENFILENAME()->lpstrFile[0]);
-}
-
-TEST(OpenFileNameTest, SetInitialSelection) {
- const base::FilePath kDirectory(L"C:\\directory\\child_directory");
- const base::FilePath kFile(L"file_name.ext");
- ui::win::OpenFileName ofn(kHwnd, kFlags);
- ofn.SetInitialSelection(kDirectory, kFile);
- EXPECT_EQ(kDirectory, base::FilePath(ofn.GetOPENFILENAME()->lpstrInitialDir));
- EXPECT_EQ(kFile, base::FilePath(ofn.GetOPENFILENAME()->lpstrFile));
-
- ofn.SetInitialSelection(kDirectory, base::FilePath());
- EXPECT_EQ(kDirectory, base::FilePath(ofn.GetOPENFILENAME()->lpstrInitialDir));
- // Filename buffer will still be a valid pointer, to receive a result.
- ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile);
- EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile));
-
- ofn.SetInitialSelection(base::FilePath(), base::FilePath());
- // No initial directory will lead to a NULL buffer.
- ASSERT_FALSE(ofn.GetOPENFILENAME()->lpstrInitialDir);
- ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile);
- EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile));
-
- // Make sure that both values are cleared when directory is missing.
- ofn.SetInitialSelection(kDirectory, kFile);
- EXPECT_EQ(kDirectory, base::FilePath(ofn.GetOPENFILENAME()->lpstrInitialDir));
- EXPECT_EQ(kFile, base::FilePath(ofn.GetOPENFILENAME()->lpstrFile));
- ofn.SetInitialSelection(base::FilePath(), base::FilePath());
- ASSERT_FALSE(ofn.GetOPENFILENAME()->lpstrInitialDir);
- ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile);
- EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile));
-
- // File is ignored in absence of a directory.
- ofn.SetInitialSelection(base::FilePath(), kFile);
- ASSERT_FALSE(ofn.GetOPENFILENAME()->lpstrInitialDir);
- ASSERT_TRUE(ofn.GetOPENFILENAME()->lpstrFile);
- EXPECT_EQ(base::FilePath(), base::FilePath(ofn.GetOPENFILENAME()->lpstrFile));
-}
-
-TEST(OpenFileNameTest, GetSingleResultFromSingleSelect) {
- ui::win::OpenFileName ofn(kHwnd, kFlags);
- base::FilePath result;
-
- SetResult(L"C:\\dir\\file", &ofn);
- result = ofn.GetSingleResult();
- EXPECT_EQ(base::FilePath(L"C:\\dir\\file"), result);
-
- SetResult(L"", &ofn);
- result = ofn.GetSingleResult();
- EXPECT_EQ(base::FilePath(), result);
-}
-
-TEST(OpenFileNameTest, GetSingleResultFromMultiSelect) {
- const base::string16 kNull(L"\0", 1);
- ui::win::OpenFileName ofn(kHwnd, kFlags | OFN_ALLOWMULTISELECT);
- base::FilePath result;
-
- SetResult(L"C:\\dir\\file" + kNull, &ofn);
- result = ofn.GetSingleResult();
- EXPECT_EQ(base::FilePath(L"C:\\dir\\file"), result);
-
- SetResult(L"C:\\dir" + kNull + L"file" + kNull, &ofn);
- result = ofn.GetSingleResult();
- EXPECT_EQ(base::FilePath(L"C:\\dir\\file"), result);
-
- SetResult(L"C:\\dir" + kNull + L"file" + kNull + L"otherfile" + kNull, &ofn);
- result = ofn.GetSingleResult();
- EXPECT_EQ(base::FilePath(), result);
-
- SetResult(L"", &ofn);
- result = ofn.GetSingleResult();
- EXPECT_EQ(base::FilePath(), result);
-}
-
-TEST(OpenFileNameTest, GetResult) {
- const base::string16 kNull(L"\0", 1);
-
- ui::win::OpenFileName ofn(kHwnd, kFlags | OFN_ALLOWMULTISELECT);
- base::FilePath directory;
- std::vector<base::FilePath> filenames;
-
- SetResult(L"C:\\dir\\file" + kNull, &ofn);
- ofn.GetResult(&directory, &filenames);
- EXPECT_EQ(base::FilePath(L"C:\\dir"), directory);
- ASSERT_EQ(1u, filenames.size());
- EXPECT_EQ(base::FilePath(L"file"), filenames[0]);
-
- directory.clear();
- filenames.clear();
-
- SetResult(L"C:\\dir" + kNull + L"file" + kNull, &ofn);
- ofn.GetResult(&directory, &filenames);
- EXPECT_EQ(base::FilePath(L"C:\\dir"), directory);
- ASSERT_EQ(1u, filenames.size());
- EXPECT_EQ(base::FilePath(L"file"), filenames[0]);
-
- directory.clear();
- filenames.clear();
-
- SetResult(L"C:\\dir" + kNull + L"file" + kNull + L"otherfile" + kNull, &ofn);
- ofn.GetResult(&directory, &filenames);
- EXPECT_EQ(base::FilePath(L"C:\\dir"), directory);
- ASSERT_EQ(2u, filenames.size());
- EXPECT_EQ(base::FilePath(L"file"), filenames[0]);
- EXPECT_EQ(base::FilePath(L"otherfile"), filenames[1]);
-
- directory.clear();
- filenames.clear();
-
- SetResult(L"", &ofn);
- ofn.GetResult(&directory, &filenames);
- EXPECT_EQ(base::FilePath(), directory);
- ASSERT_EQ(0u, filenames.size());
-}
-
-TEST(OpenFileNameTest, SetAndGetFilters) {
- const base::string16 kNull(L"\0", 1);
-
- ui::win::OpenFileName ofn(kHwnd, kFlags);
- std::vector<std::tuple<base::string16, base::string16>> filters;
- ofn.SetFilters(filters);
- EXPECT_FALSE(ofn.GetOPENFILENAME()->lpstrFilter);
- CheckFilters(filters,
- ui::win::OpenFileName::GetFilters(ofn.GetOPENFILENAME()));
-
- filters.push_back(
- std::make_tuple(base::string16(L"a"), base::string16(L"b")));
- ofn.SetFilters(filters);
- CheckFilterString(L"a" + kNull + L"b" + kNull, ofn);
- CheckFilters(filters,
- ui::win::OpenFileName::GetFilters(ofn.GetOPENFILENAME()));
-
- filters.push_back(
- std::make_tuple(base::string16(L"X"), base::string16(L"Y")));
- ofn.SetFilters(filters);
- CheckFilterString(L"a" + kNull + L"b" + kNull + L"X" + kNull + L"Y" + kNull,
- ofn);
- CheckFilters(filters,
- ui::win::OpenFileName::GetFilters(ofn.GetOPENFILENAME()));
-}
-
-TEST(OpenFileNameTest, SetResult) {
- const base::string16 kNull(L"\0", 1);
-
- ui::win::OpenFileName ofn(kHwnd, kFlags);
- base::FilePath directory;
- std::vector<base::FilePath> filenames;
-
- ui::win::OpenFileName::SetResult(directory, filenames, ofn.GetOPENFILENAME());
- CheckResult(L"", ofn);
-
- directory = base::FilePath(L"C:\\dir");
- filenames.push_back(base::FilePath(L"file"));
- ui::win::OpenFileName::SetResult(directory, filenames, ofn.GetOPENFILENAME());
- CheckResult(L"C:\\dir\\file" + kNull, ofn);
-
- filenames.push_back(base::FilePath(L"otherfile"));
- ui::win::OpenFileName::SetResult(directory, filenames, ofn.GetOPENFILENAME());
- CheckResult(L"C:\\dir" + kNull + L"file" + kNull + L"otherfile" + kNull, ofn);
-
- base::char16 short_buffer[10] = L"";
-
- ofn.GetOPENFILENAME()->lpstrFile = short_buffer;
- ofn.GetOPENFILENAME()->nMaxFile = arraysize(short_buffer);
- ui::win::OpenFileName::SetResult(directory, filenames, ofn.GetOPENFILENAME());
- CheckResult(L"", ofn);
-}
diff --git a/chromium/ui/base/win/shell.cc b/chromium/ui/base/win/shell.cc
index e25487ec101..bff3c38f641 100644
--- a/chromium/ui/base/win/shell.cc
+++ b/chromium/ui/base/win/shell.cc
@@ -18,7 +18,7 @@
#include "base/native_library.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
#include "base/win/win_util.h"
#include "ui/base/ui_base_switches.h"
@@ -42,7 +42,7 @@ bool InvokeShellExecute(const base::string16 path,
const base::string16 args,
const base::string16 verb,
DWORD mask) {
- base::AssertBlockingAllowed();
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::WILL_BLOCK);
SHELLEXECUTEINFO sei = {sizeof(sei)};
sei.fMask = mask;
sei.nShow = SW_SHOWNORMAL;
diff --git a/chromium/ui/base/work_area_watcher_observer.h b/chromium/ui/base/work_area_watcher_observer.h
deleted file mode 100644
index 341eda0b9e6..00000000000
--- a/chromium/ui/base/work_area_watcher_observer.h
+++ /dev/null
@@ -1,25 +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_BASE_WORK_AREA_WATCHER_OBSERVER_H_
-#define UI_BASE_WORK_AREA_WATCHER_OBSERVER_H_
-
-#include "ui/base/ui_base_export.h"
-
-namespace ui {
-
-// This interface should be implemented by classes that want to be notified
-// when the work area has changed due to something like screen resolution or
-// taskbar changes.
-class UI_BASE_EXPORT WorkAreaWatcherObserver {
- public:
- virtual void WorkAreaChanged() = 0;
-
- protected:
- virtual ~WorkAreaWatcherObserver() {}
-};
-
-} // namespace ui
-
-#endif // UI_BASE_WORK_AREA_WATCHER_OBSERVER_H_
diff --git a/chromium/ui/base/x/BUILD.gn b/chromium/ui/base/x/BUILD.gn
index eb77c5fff52..593221f2d18 100644
--- a/chromium/ui/base/x/BUILD.gn
+++ b/chromium/ui/base/x/BUILD.gn
@@ -13,6 +13,8 @@ jumbo_component("x") {
sources = [
"ui_base_x_export.h",
+ "x11_display_util.cc",
+ "x11_display_util.h",
"x11_menu_list.cc",
"x11_menu_list.h",
"x11_pointer_grab.cc",
@@ -24,7 +26,10 @@ jumbo_component("x") {
"x11_window_event_manager.h",
]
- configs += [ "//build/config/linux:x11" ]
+ configs += [
+ "//build/config/linux:x11",
+ "//build/config/linux:xrandr",
+ ]
defines = [ "UI_BASE_X_IMPLEMENTATION" ]
@@ -32,6 +37,7 @@ jumbo_component("x") {
"//base",
"//base:i18n",
"//skia",
+ "//ui/display/util",
"//ui/events",
"//ui/events/devices/x11",
"//ui/events/keycodes:x11",
diff --git a/chromium/ui/base/x/x11_display_util.cc b/chromium/ui/base/x/x11_display_util.cc
new file mode 100644
index 00000000000..c13067469e1
--- /dev/null
+++ b/chromium/ui/base/x/x11_display_util.cc
@@ -0,0 +1,221 @@
+// 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/base/x/x11_display_util.h"
+
+#include <dlfcn.h>
+
+#include "base/logging.h"
+#include "base/memory/protected_memory_cfi.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/display/util/display_util.h"
+#include "ui/display/util/x11/edid_parser_x11.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/x/x11.h"
+
+namespace ui {
+
+namespace {
+
+constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3.
+
+typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*);
+typedef void (*XRRFreeMonitors)(XRRMonitorInfo*);
+
+PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRGetMonitors>
+ g_XRRGetMonitors_ptr;
+PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRFreeMonitors>
+ g_XRRFreeMonitors_ptr;
+
+std::map<RROutput, int> GetMonitors(int version,
+ XDisplay* xdisplay,
+ GLXWindow window) {
+ std::map<RROutput, int> output_to_monitor;
+ if (version >= 105) {
+ void* xrandr_lib = dlopen(nullptr, RTLD_NOW);
+ if (xrandr_lib) {
+ static base::ProtectedMemory<XRRGetMonitors>::Initializer get_init(
+ &g_XRRGetMonitors_ptr, reinterpret_cast<XRRGetMonitors>(
+ dlsym(xrandr_lib, "XRRGetMonitors")));
+ static base::ProtectedMemory<XRRFreeMonitors>::Initializer free_init(
+ &g_XRRFreeMonitors_ptr, reinterpret_cast<XRRFreeMonitors>(
+ dlsym(xrandr_lib, "XRRFreeMonitors")));
+ if (*g_XRRGetMonitors_ptr && *g_XRRFreeMonitors_ptr) {
+ int nmonitors = 0;
+ XRRMonitorInfo* monitors = base::UnsanitizedCfiCall(
+ g_XRRGetMonitors_ptr)(xdisplay, window, false, &nmonitors);
+ for (int monitor = 0; monitor < nmonitors; monitor++) {
+ for (int j = 0; j < monitors[monitor].noutput; j++) {
+ output_to_monitor[monitors[monitor].outputs[j]] = monitor;
+ }
+ }
+ base::UnsanitizedCfiCall(g_XRRFreeMonitors_ptr)(monitors);
+ }
+ }
+ }
+ return output_to_monitor;
+}
+
+} // namespace
+
+int GetXrandrVersion(XDisplay* xdisplay) {
+ int xrandr_version = 0;
+ // We only support 1.3+. There were library changes before this and we should
+ // use the new interface instead of the 1.2 one.
+ int randr_version_major = 0;
+ int randr_version_minor = 0;
+ if (XRRQueryVersion(xdisplay, &randr_version_major, &randr_version_minor)) {
+ xrandr_version = randr_version_major * 100 + randr_version_minor;
+ }
+ return xrandr_version;
+}
+
+std::vector<display::Display> GetFallbackDisplayList(float scale) {
+ XDisplay* display = gfx::GetXDisplay();
+ ::Screen* screen = DefaultScreenOfDisplay(display);
+ gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
+
+ int width = WidthOfScreen(screen);
+ int height = HeightOfScreen(screen);
+ gfx::Rect bounds_in_pixels(0, 0, width, height);
+ display::Display gfx_display(0, bounds_in_pixels);
+
+ if (!display::Display::HasForceDeviceScaleFactor() &&
+ !display::IsDisplaySizeBlackListed(physical_size)) {
+ DCHECK_LE(1.0f, scale);
+ gfx_display.SetScaleAndBounds(scale, bounds_in_pixels);
+ }
+
+ return {gfx_display};
+}
+
+std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+ int version,
+ float scale,
+ int64_t* primary_display_index_out) {
+ DCHECK(primary_display_index_out);
+ DCHECK_GE(version, kMinVersionXrandr);
+ XDisplay* xdisplay = gfx::GetXDisplay();
+ GLXWindow x_root_window = DefaultRootWindow(xdisplay);
+ std::vector<display::Display> displays;
+ gfx::XScopedPtr<
+ XRRScreenResources,
+ gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
+ resources(XRRGetScreenResourcesCurrent(xdisplay, x_root_window));
+ if (!resources) {
+ LOG(ERROR) << "XRandR returned no displays; falling back to root window";
+ return GetFallbackDisplayList(scale);
+ }
+
+ std::map<RROutput, int> output_to_monitor =
+ GetMonitors(version, xdisplay, x_root_window);
+ *primary_display_index_out = 0;
+ RROutput primary_display_id = XRRGetOutputPrimary(xdisplay, x_root_window);
+
+ int explicit_primary_display_index = -1;
+ int monitor_order_primary_display_index = -1;
+
+ bool has_work_area = false;
+ gfx::Rect work_area_in_pixels;
+ std::vector<int> value;
+ if (ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) &&
+ value.size() >= 4) {
+ work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
+ has_work_area = true;
+ }
+
+ // As per-display scale factor is not supported right now,
+ // the X11 root window's scale factor is always used.
+ for (int i = 0; i < resources->noutput; ++i) {
+ RROutput output_id = resources->outputs[i];
+ gfx::XScopedPtr<XRROutputInfo,
+ gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
+ output_info(XRRGetOutputInfo(xdisplay, resources.get(), output_id));
+
+ bool is_connected = (output_info->connection == RR_Connected);
+ if (!is_connected)
+ continue;
+
+ bool is_primary_display = (output_id == primary_display_id);
+
+ if (output_info->crtc) {
+ gfx::XScopedPtr<XRRCrtcInfo,
+ gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
+ crtc(XRRGetCrtcInfo(xdisplay, resources.get(), output_info->crtc));
+
+ int64_t display_id = -1;
+ if (!display::EDIDParserX11(output_id).GetDisplayId(
+ static_cast<uint8_t>(i), &display_id)) {
+ // It isn't ideal, but if we can't parse the EDID data, fall back on the
+ // display number.
+ display_id = i;
+ }
+
+ gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
+ display::Display display(display_id, crtc_bounds);
+
+ if (!display::Display::HasForceDeviceScaleFactor()) {
+ display.SetScaleAndBounds(scale, crtc_bounds);
+ }
+
+ if (has_work_area) {
+ gfx::Rect intersection_in_pixels = crtc_bounds;
+ if (is_primary_display) {
+ intersection_in_pixels.Intersect(work_area_in_pixels);
+ }
+ // SetScaleAndBounds() above does the conversion from pixels to DIP for
+ // us, but set_work_area does not, so we need to do it here.
+ display.set_work_area(gfx::Rect(
+ gfx::ScaleToFlooredPoint(intersection_in_pixels.origin(),
+ 1.0f / display.device_scale_factor()),
+ gfx::ScaleToFlooredSize(intersection_in_pixels.size(),
+ 1.0f / display.device_scale_factor())));
+ }
+
+ switch (crtc->rotation) {
+ case RR_Rotate_0:
+ display.set_rotation(display::Display::ROTATE_0);
+ break;
+ case RR_Rotate_90:
+ display.set_rotation(display::Display::ROTATE_90);
+ break;
+ case RR_Rotate_180:
+ display.set_rotation(display::Display::ROTATE_180);
+ break;
+ case RR_Rotate_270:
+ display.set_rotation(display::Display::ROTATE_270);
+ break;
+ }
+
+ if (is_primary_display)
+ explicit_primary_display_index = displays.size();
+
+ auto monitor_iter = output_to_monitor.find(output_id);
+ if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
+ monitor_order_primary_display_index = displays.size();
+
+ if (!display::Display::HasForceDisplayColorProfile()) {
+ gfx::ICCProfile icc_profile = ui::GetICCProfileForMonitor(
+ monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
+ icc_profile.HistogramDisplay(display.id());
+ display.set_color_space(icc_profile.GetColorSpace());
+ }
+
+ displays.push_back(display);
+ }
+ }
+
+ if (explicit_primary_display_index != -1) {
+ *primary_display_index_out = explicit_primary_display_index;
+ } else if (monitor_order_primary_display_index != -1) {
+ *primary_display_index_out = monitor_order_primary_display_index;
+ }
+
+ if (displays.empty())
+ return GetFallbackDisplayList(scale);
+
+ return displays;
+}
+
+} // namespace ui
diff --git a/chromium/ui/base/x/x11_display_util.h b/chromium/ui/base/x/x11_display_util.h
new file mode 100644
index 00000000000..8d16263c232
--- /dev/null
+++ b/chromium/ui/base/x/x11_display_util.h
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_X_X11_DISPLAY_UTIL_H_
+#define UI_BASE_X_X11_DISPLAY_UTIL_H_
+
+#include "ui/base/x/ui_base_x_export.h"
+#include "ui/display/display.h"
+#include "ui/gfx/x/x11_types.h"
+
+namespace ui {
+
+// Return the version for xrandr. It multiplies the major number by 100 and
+// adds the minor like MAJOR * 100 + MINOR. It returns zero if no xrandr is
+// present.
+UI_BASE_X_EXPORT int GetXrandrVersion(XDisplay* xdisplay);
+
+// Builds a list of displays for fallback.
+UI_BASE_X_EXPORT std::vector<display::Display> GetFallbackDisplayList(
+ float scale);
+
+// Builds a list of displays from the current screen information offered by
+// the X server.
+UI_BASE_X_EXPORT std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+ int version,
+ float scale,
+ int64_t* primary_display_index_out);
+
+} // namespace ui
+
+#endif // UI_BASE_X_X11_DISPLAY_UTIL_H_
diff --git a/chromium/ui/base/x/x11_util.cc b/chromium/ui/base/x/x11_util.cc
index 311b10e3d67..9d79f937bd1 100644
--- a/chromium/ui/base/x/x11_util.cc
+++ b/chromium/ui/base/x/x11_util.cc
@@ -19,6 +19,7 @@
#include <vector>
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -55,6 +56,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/x11_error_tracker.h"
@@ -79,6 +81,10 @@ namespace {
constexpr int kNetWMStateAdd = 1;
constexpr int kNetWMStateRemove = 0;
+// Length in 32-bit multiples of the data to be retrieved for
+// XGetWindowProperty.
+constexpr int kLongLength = 0x1FFFFFFF; /* MAXINT32 / 4 */
+
int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
// This callback can be invoked by drivers very late in thread destruction,
// when Chrome TLS is no longer usable. https://crbug.com/849225.
@@ -680,10 +686,9 @@ bool GetRawBytesOfProperty(XID window,
XAtom prop_type = x11::None;
int prop_format = 0;
unsigned char* property_data = NULL;
- if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0,
- 0x1FFFFFFF /* MAXINT32 / 4 */, x11::False,
- AnyPropertyType, &prop_type, &prop_format, &nitems,
- &nbytes, &property_data) != x11::Success) {
+ if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, kLongLength,
+ x11::False, AnyPropertyType, &prop_type, &prop_format,
+ &nitems, &nbytes, &property_data) != x11::Success) {
return false;
}
gfx::XScopedPtr<unsigned char> scoped_property(property_data);
@@ -1269,6 +1274,35 @@ bool WmSupportsHint(XAtom atom) {
return base::ContainsValue(supported_atoms, atom);
}
+gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
+ gfx::ICCProfile icc_profile;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
+ return icc_profile;
+ std::string atom_name;
+ if (monitor == 0) {
+ atom_name = "_ICC_PROFILE";
+ } else {
+ atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor);
+ }
+ Atom property = gfx::GetAtom(atom_name.c_str());
+ if (property != x11::None) {
+ Atom prop_type = x11::None;
+ int prop_format = 0;
+ unsigned long nitems = 0;
+ unsigned long nbytes = 0;
+ char* property_data = nullptr;
+ int result = XGetWindowProperty(
+ gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()), property, 0,
+ kLongLength, x11::False, AnyPropertyType, &prop_type, &prop_format,
+ &nitems, &nbytes, reinterpret_cast<unsigned char**>(&property_data));
+ if (result == x11::Success) {
+ icc_profile = gfx::ICCProfile::FromData(property_data, nitems);
+ XFree(property_data);
+ }
+ }
+ return icc_profile;
+}
+
XRefcountedMemory::XRefcountedMemory(unsigned char* x11_data, size_t length)
: x11_data_(length ? x11_data : nullptr), length_(length) {
}
diff --git a/chromium/ui/base/x/x11_util.h b/chromium/ui/base/x/x11_util.h
index e7942b98090..ee367584b40 100644
--- a/chromium/ui/base/x/x11_util.h
+++ b/chromium/ui/base/x/x11_util.h
@@ -23,6 +23,7 @@
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/platform_event.h"
+#include "ui/gfx/icc_profile.h"
#include "ui/gfx/x/x11_types.h"
typedef unsigned long XSharedMemoryId; // ShmSeg in the X headers.
@@ -297,6 +298,9 @@ UI_BASE_X_EXPORT bool IsX11WindowFullScreen(XID window);
// Returns true if the window manager supports the given hint.
UI_BASE_X_EXPORT bool WmSupportsHint(XAtom atom);
+// Returns the ICCProfile corresponding to |monitor| using XGetWindowProperty.
+UI_BASE_X_EXPORT gfx::ICCProfile GetICCProfileForMonitor(int monitor);
+
// Manages a piece of X11 allocated memory as a RefCountedMemory segment. This
// object takes ownership over the passed in memory and will free it with the
// X11 allocator when done.
diff --git a/chromium/ui/compositor/compositor.cc b/chromium/ui/compositor/compositor.cc
index 8ae7efefd62..5358941075a 100644
--- a/chromium/ui/compositor/compositor.cc
+++ b/chromium/ui/compositor/compositor.cc
@@ -16,7 +16,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
@@ -57,6 +57,11 @@
#include "ui/gl/gl_switches.h"
namespace ui {
+namespace {
+
+const char* kDefaultTraceEnvironmentName = "browser";
+
+} // namespace
Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
ui::ContextFactory* context_factory,
@@ -65,7 +70,8 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
bool enable_surface_synchronization,
bool enable_pixel_canvas,
bool external_begin_frames_enabled,
- bool force_software_compositor)
+ bool force_software_compositor,
+ const char* trace_environment_name)
: context_factory_(context_factory),
context_factory_private_(context_factory_private),
frame_sink_id_(frame_sink_id),
@@ -76,11 +82,15 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
layer_animator_collection_(this),
is_pixel_canvas_(enable_pixel_canvas),
lock_manager_(task_runner),
+ trace_environment_name_(trace_environment_name
+ ? trace_environment_name
+ : kDefaultTraceEnvironmentName),
context_creation_weak_ptr_factory_(this) {
if (context_factory_private) {
auto* host_frame_sink_manager =
context_factory_private_->GetHostFrameSinkManager();
- host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
+ host_frame_sink_manager->RegisterFrameSinkId(
+ frame_sink_id_, this, viz::ReportFirstSurfaceActivation::kNo);
host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_,
"Compositor");
}
@@ -96,7 +106,6 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
settings.layers_always_allowed_lcd_text = true;
// Use occlusion to allow more overlapping windows to take less memory.
settings.use_occlusion_for_tile_prioritization = true;
- refresh_rate_ = context_factory_->GetRefreshRate();
settings.main_frame_before_activation_enabled = false;
settings.delegated_sync_points_required =
context_factory_->SyncTokensRequiredForDisplayCompositor();
@@ -104,15 +113,6 @@ Compositor::Compositor(const viz::FrameSinkId& frame_sink_id,
// Disable edge anti-aliasing in order to increase support for HW overlays.
settings.enable_edge_anti_aliasing = false;
- if (command_line->HasSwitch(switches::kLimitFps)) {
- std::string fps_str =
- command_line->GetSwitchValueASCII(switches::kLimitFps);
- double fps;
- if (base::StringToDouble(fps_str, &fps) && fps > 0) {
- forced_refresh_rate_ = fps;
- }
- }
-
if (command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders)) {
std::string layer_borders_string = command_line->GetSwitchValueASCII(
cc::switches::kUIShowCompositedLayerBorders);
@@ -275,11 +275,6 @@ void Compositor::RemoveChildFrameSink(const viz::FrameSinkId& frame_sink_id) {
child_frame_sinks_.erase(it);
}
-void Compositor::SetLocalSurfaceId(
- const viz::LocalSurfaceId& local_surface_id) {
- host_->SetLocalSurfaceIdFromParent(local_surface_id);
-}
-
void Compositor::SetLayerTreeFrameSink(
std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink) {
layer_tree_frame_sink_requested_ = false;
@@ -357,22 +352,28 @@ void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
host_->QueueSwapPromise(std::move(swap_promise));
}
-void Compositor::SetScaleAndSize(float scale,
- const gfx::Size& size_in_pixel,
- const viz::LocalSurfaceId& local_surface_id) {
+void Compositor::SetScaleAndSize(
+ float scale,
+ const gfx::Size& size_in_pixel,
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
DCHECK_GT(scale, 0);
bool device_scale_factor_changed = device_scale_factor_ != scale;
device_scale_factor_ = scale;
- if (size_ != size_in_pixel && local_surface_id.is_valid()) {
+ if (size_ != size_in_pixel && local_surface_id_allocation.IsValid()) {
// A new LocalSurfaceId must be set when the compositor size changes.
- DCHECK_NE(local_surface_id, host_->local_surface_id_from_parent());
+ DCHECK_NE(
+ local_surface_id_allocation.local_surface_id(),
+ host_->local_surface_id_allocation_from_parent().local_surface_id());
+ DCHECK_NE(local_surface_id_allocation,
+ host_->local_surface_id_allocation_from_parent());
}
if (!size_in_pixel.IsEmpty()) {
bool size_changed = size_ != size_in_pixel;
size_ = size_in_pixel;
- host_->SetViewportSizeAndScale(size_in_pixel, scale, local_surface_id);
+ host_->SetViewportSizeAndScale(size_in_pixel, scale,
+ local_surface_id_allocation);
root_web_layer_->SetBounds(size_in_pixel);
// TODO(fsamuel): Get rid of ContextFactoryPrivate.
if (context_factory_private_ &&
@@ -453,10 +454,6 @@ void Compositor::SetDisplayVSyncParameters(base::TimeTicks timebase,
if (is_frame_rate_limit_disabled)
return;
- if (forced_refresh_rate_) {
- timebase = base::TimeTicks();
- interval = base::TimeDelta::FromSeconds(1) / forced_refresh_rate_;
- }
if (interval.is_zero()) {
// TODO(brianderson): We should not be receiving 0 intervals.
interval = viz::BeginFrameArgs::DefaultInterval();
@@ -470,8 +467,6 @@ void Compositor::SetDisplayVSyncParameters(base::TimeTicks timebase,
vsync_timebase_ = timebase;
vsync_interval_ = interval;
- refresh_rate_ =
- base::Time::kMillisecondsPerSecond / interval.InMillisecondsF();
if (context_factory_private_) {
context_factory_private_->SetDisplayVSyncParameters(this, timebase,
interval);
@@ -586,7 +581,7 @@ static void SendDamagedRectsRecursive(ui::Layer* layer) {
SendDamagedRectsRecursive(child);
}
-void Compositor::UpdateLayerTreeHost() {
+void Compositor::UpdateLayerTreeHost(bool record_main_frame_metrics) {
if (!root_layer())
return;
SendDamagedRectsRecursive(root_layer());
@@ -620,16 +615,28 @@ void Compositor::DidReceiveCompositorFrameAck() {
observer.OnCompositingEnded(this);
}
+void Compositor::DidPresentCompositorFrame(
+ uint32_t frame_token,
+ const gfx::PresentationFeedback& feedback) {
+ TRACE_EVENT_MARK_WITH_TIMESTAMP1("cc,benchmark", "FramePresented",
+ feedback.timestamp, "environment",
+ trace_environment_name_);
+}
+
void Compositor::DidSubmitCompositorFrame() {
base::TimeTicks start_time = base::TimeTicks::Now();
for (auto& observer : observer_list_)
observer.OnCompositingStarted(this, start_time);
}
+void Compositor::FrameIntervalUpdated(base::TimeDelta interval) {
+ refresh_rate_ =
+ base::Time::kMicrosecondsPerSecond / interval.InMicrosecondsF();
+}
+
void Compositor::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {
- // TODO(fsamuel): Once surface synchronization is turned on, the fallback
- // surface should be set here.
+ NOTREACHED();
}
void Compositor::OnFrameTokenChanged(uint32_t frame_token) {
diff --git a/chromium/ui/compositor/compositor.h b/chromium/ui/compositor/compositor.h
index b3905bdfa65..6f46fd5b4b5 100644
--- a/chromium/ui/compositor/compositor.h
+++ b/chromium/ui/compositor/compositor.h
@@ -68,7 +68,6 @@ namespace viz {
class FrameSinkManagerImpl;
class ContextProvider;
class HostFrameSinkManager;
-class LocalSurfaceId;
}
namespace ui {
@@ -182,9 +181,6 @@ class COMPOSITOR_EXPORT ContextFactory {
// Destroys per-compositor data.
virtual void RemoveCompositor(Compositor* compositor) = 0;
- // Returns refresh rate. Tests may return higher values.
- virtual double GetRefreshRate() const = 0;
-
// Gets the GPU memory buffer manager.
virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() = 0;
@@ -208,6 +204,9 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
public viz::HostFrameSinkClient,
public ExternalBeginFrameClient {
public:
+ // |trace_environment_name| is passed to trace events so that tracing
+ // can identify the environment the trace events are from. Examples are,
+ // "ash", and "browser". If no value is supplied, "browser" is used.
Compositor(const viz::FrameSinkId& frame_sink_id,
ui::ContextFactory* context_factory,
ui::ContextFactoryPrivate* context_factory_private,
@@ -215,7 +214,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
bool enable_surface_synchronization,
bool enable_pixel_canvas,
bool external_begin_frames_enabled = false,
- bool force_software_compositor = false);
+ bool force_software_compositor = false,
+ const char* trace_environment_name = nullptr);
~Compositor() override;
ui::ContextFactory* context_factory() { return context_factory_; }
@@ -227,8 +227,6 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void AddChildFrameSink(const viz::FrameSinkId& frame_sink_id);
void RemoveChildFrameSink(const viz::FrameSinkId& frame_sink_id);
- void SetLocalSurfaceId(const viz::LocalSurfaceId& local_surface_id);
-
void SetLayerTreeFrameSink(std::unique_ptr<cc::LayerTreeFrameSink> surface);
// Called when a child surface is about to resize.
@@ -281,9 +279,10 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void SetLatencyInfo(const LatencyInfo& latency_info);
// Sets the compositor's device scale factor and size.
- void SetScaleAndSize(float scale,
- const gfx::Size& size_in_pixel,
- const viz::LocalSurfaceId& local_surface_id);
+ void SetScaleAndSize(
+ float scale,
+ const gfx::Size& size_in_pixel,
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation);
// Set the output color profile into which this compositor should render.
void SetDisplayColorSpace(const gfx::ColorSpace& color_space);
@@ -366,7 +365,7 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
base::TimeDelta timeout =
base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)) {
return lock_manager_.GetCompositorLock(client, timeout,
- host_->DeferCommits());
+ host_->DeferMainFrameUpdate());
}
// Registers a callback that is run when the next frame successfully makes it
@@ -388,7 +387,7 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void BeginMainFrame(const viz::BeginFrameArgs& args) override;
void BeginMainFrameNotExpectedSoon() override;
void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override;
- void UpdateLayerTreeHost() override;
+ void UpdateLayerTreeHost(bool record_main_frame_metrics) override;
void ApplyViewportChanges(const cc::ApplyViewportChangesArgs& args) override {
}
void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel,
@@ -403,12 +402,13 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
void DidCompletePageScaleAnimation() override {}
void DidPresentCompositorFrame(
uint32_t frame_token,
- const gfx::PresentationFeedback& feedback) override {}
+ const gfx::PresentationFeedback& feedback) override;
void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {}
// cc::LayerTreeHostSingleThreadClient implementation.
void DidSubmitCompositorFrame() override;
void DidLoseLayerTreeFrameSink() override {}
+ void FrameIntervalUpdated(base::TimeDelta interval) override;
// viz::HostFrameSinkClient implementation.
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
@@ -459,11 +459,9 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
// A sequence number of a current compositor frame for use with metrics.
int activated_frame_count_ = 0;
- // Current vsync refresh rate per second.
- float refresh_rate_ = 0.f;
-
- // If nonzero, this is the refresh rate forced from the command-line.
- double forced_refresh_rate_ = 0.f;
+ // Current vsync refresh rate per second. Initialized to 60hz as a reasonable
+ // value until first begin frame arrives with the real refresh rate.
+ float refresh_rate_ = 60.f;
// A map from child id to parent id.
std::unordered_set<viz::FrameSinkId, viz::FrameSinkIdHash> child_frame_sinks_;
@@ -511,6 +509,8 @@ class COMPOSITOR_EXPORT Compositor : public cc::LayerTreeHostClient,
// Set in DisableSwapUntilResize and reset when a resize happens.
bool disabled_swap_until_resize_ = false;
+ const char* trace_environment_name_;
+
base::WeakPtrFactory<Compositor> context_creation_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(Compositor);
diff --git a/chromium/ui/compositor/compositor_lock.cc b/chromium/ui/compositor/compositor_lock.cc
index 69a34775bfd..3ca650f4aed 100644
--- a/chromium/ui/compositor/compositor_lock.cc
+++ b/chromium/ui/compositor/compositor_lock.cc
@@ -21,11 +21,13 @@ CompositorLockManager::~CompositorLockManager() = default;
std::unique_ptr<CompositorLock> CompositorLockManager::GetCompositorLock(
CompositorLockClient* client,
base::TimeDelta timeout,
- std::unique_ptr<cc::ScopedDeferCommits> scoped_defer_commits) {
+ std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
+ scoped_defer_main_frame_update) {
// This uses the main WeakPtrFactory to break the connection from the lock to
// the CompositorLockManager when the CompositorLockManager is destroyed.
auto lock = std::make_unique<CompositorLock>(
- client, weak_ptr_factory_.GetWeakPtr(), std::move(scoped_defer_commits));
+ client, weak_ptr_factory_.GetWeakPtr(),
+ std::move(scoped_defer_main_frame_update));
bool was_empty = active_locks_.empty();
active_locks_.push_back(lock.get());
@@ -71,22 +73,23 @@ void CompositorLockManager::TimeoutLocks() {
DCHECK(active_locks_.empty());
}
-CompositorLock::CompositorLock(
- CompositorLockClient* client,
- base::WeakPtr<CompositorLockManager> manager,
- std::unique_ptr<cc::ScopedDeferCommits> scoped_defer_commits)
+CompositorLock::CompositorLock(CompositorLockClient* client,
+ base::WeakPtr<CompositorLockManager> manager,
+ std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
+ scoped_defer_main_frame_update)
: client_(client),
- scoped_defer_commits_(std::move(scoped_defer_commits)),
+ scoped_defer_main_frame_update_(
+ std::move(scoped_defer_main_frame_update)),
manager_(std::move(manager)) {}
CompositorLock::~CompositorLock() {
- scoped_defer_commits_ = nullptr;
+ scoped_defer_main_frame_update_ = nullptr;
if (manager_)
manager_->RemoveCompositorLock(this);
}
void CompositorLock::TimeoutLock() {
- scoped_defer_commits_ = nullptr;
+ scoped_defer_main_frame_update_ = nullptr;
manager_->RemoveCompositorLock(this);
manager_ = nullptr;
if (client_)
diff --git a/chromium/ui/compositor/compositor_lock.h b/chromium/ui/compositor/compositor_lock.h
index 2f08a190619..a28ebde8503 100644
--- a/chromium/ui/compositor/compositor_lock.h
+++ b/chromium/ui/compositor/compositor_lock.h
@@ -13,7 +13,7 @@
#include "ui/compositor/compositor_export.h"
namespace cc {
-class ScopedDeferCommits;
+class ScopedDeferMainFrameUpdate;
}
namespace ui {
@@ -45,7 +45,8 @@ class COMPOSITOR_EXPORT CompositorLockManager {
std::unique_ptr<CompositorLock> GetCompositorLock(
CompositorLockClient* client,
base::TimeDelta timeout,
- std::unique_ptr<cc::ScopedDeferCommits> scoped_defer_commits);
+ std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
+ scoped_defer_main_frame_update);
void set_allow_locks_to_extend_timeout(bool allowed) {
allow_locks_to_extend_timeout_ = allowed;
@@ -92,10 +93,10 @@ class COMPOSITOR_EXPORT CompositorLock {
// The |client| is informed about events from the CompositorLock. The
// |delegate| is used to perform actual unlocking. If |timeout| is zero then
// no timeout is scheduled, else a timeout is scheduled on the |task_runner|.
- explicit CompositorLock(
- CompositorLockClient* client,
- base::WeakPtr<CompositorLockManager> manager,
- std::unique_ptr<cc::ScopedDeferCommits> scoped_defer_commits);
+ explicit CompositorLock(CompositorLockClient* client,
+ base::WeakPtr<CompositorLockManager> manager,
+ std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
+ scoped_defer_main_frame_update);
~CompositorLock();
private:
@@ -105,7 +106,8 @@ class COMPOSITOR_EXPORT CompositorLock {
void TimeoutLock();
CompositorLockClient* const client_;
- std::unique_ptr<cc::ScopedDeferCommits> scoped_defer_commits_;
+ std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
+ scoped_defer_main_frame_update_;
base::WeakPtr<CompositorLockManager> manager_;
DISALLOW_COPY_AND_ASSIGN(CompositorLock);
diff --git a/chromium/ui/compositor/compositor_switches.cc b/chromium/ui/compositor/compositor_switches.cc
index f09ec5452e9..a61a7ba9b59 100644
--- a/chromium/ui/compositor/compositor_switches.cc
+++ b/chromium/ui/compositor/compositor_switches.cc
@@ -18,10 +18,6 @@ const char kEnableHardwareOverlays[] = "enable-hardware-overlays";
// Forces tests to produce pixel output when they normally wouldn't.
const char kEnablePixelOutputInTests[] = "enable-pixel-output-in-tests";
-// Limits the compositor to output a certain number of frames per second,
-// maximum.
-const char kLimitFps[] = "limit-fps";
-
const char kUIEnableRGBA4444Textures[] = "ui-enable-rgba-4444-textures";
const char kUIEnableZeroCopy[] = "ui-enable-zero-copy";
diff --git a/chromium/ui/compositor/compositor_switches.h b/chromium/ui/compositor/compositor_switches.h
index 2f02b8e0ffa..8757e22e970 100644
--- a/chromium/ui/compositor/compositor_switches.h
+++ b/chromium/ui/compositor/compositor_switches.h
@@ -12,7 +12,6 @@ namespace switches {
COMPOSITOR_EXPORT extern const char kEnableHardwareOverlays[];
COMPOSITOR_EXPORT extern const char kEnablePixelOutputInTests[];
-COMPOSITOR_EXPORT extern const char kLimitFps[];
COMPOSITOR_EXPORT extern const char kUIEnableRGBA4444Textures[];
COMPOSITOR_EXPORT extern const char kUIEnableZeroCopy[];
COMPOSITOR_EXPORT extern const char kUIDisableZeroCopy[];
diff --git a/chromium/ui/compositor/compositor_unittest.cc b/chromium/ui/compositor/compositor_unittest.cc
index c308e92d9a5..d393b18fdff 100644
--- a/chromium/ui/compositor/compositor_unittest.cc
+++ b/chromium/ui/compositor/compositor_unittest.cc
@@ -10,6 +10,7 @@
#include "base/test/scoped_task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/surfaces/surface_manager.h"
@@ -106,7 +107,8 @@ TEST_F(CompositorTestWithMessageLoop, OutputColorMatrix) {
auto root_layer = std::make_unique<Layer>(ui::LAYER_SOLID_COLOR);
root_layer->SetBounds(gfx::Rect(10, 10));
compositor()->SetRootLayer(root_layer.get());
- compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10), viz::LocalSurfaceId());
+ compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10),
+ viz::LocalSurfaceIdAllocation());
DCHECK(compositor()->IsVisible());
// Set a non-identity color matrix on the compistor display, and expect it to
@@ -159,7 +161,8 @@ TEST_F(CompositorTestWithMessageLoop, MAYBE_CreateAndReleaseOutputSurface) {
std::unique_ptr<Layer> root_layer(new Layer(ui::LAYER_SOLID_COLOR));
root_layer->SetBounds(gfx::Rect(10, 10));
compositor()->SetRootLayer(root_layer.get());
- compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10), viz::LocalSurfaceId());
+ compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10),
+ viz::LocalSurfaceIdAllocation());
DCHECK(compositor()->IsVisible());
compositor()->ScheduleDraw();
DrawWaiterForTest::WaitForCompositingEnded(compositor());
diff --git a/chromium/ui/compositor/host/host_context_factory_private.cc b/chromium/ui/compositor/host/host_context_factory_private.cc
index 952525b7f82..e16c5490bbc 100644
--- a/chromium/ui/compositor/host/host_context_factory_private.cc
+++ b/chromium/ui/compositor/host/host_context_factory_private.cc
@@ -10,6 +10,7 @@
#include "cc/mojo_embedder/async_layer_tree_frame_sink.h"
#include "components/viz/client/hit_test_data_provider_draw_quad.h"
#include "components/viz/client/local_surface_id_provider.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/switches.h"
#include "components/viz/host/host_display_client.h"
#include "components/viz/host/host_frame_sink_manager.h"
@@ -118,10 +119,12 @@ void HostContextFactoryPrivate::ConfigureCompositor(
params.local_surface_id_provider =
std::make_unique<viz::DefaultLocalSurfaceIdProvider>();
params.enable_surface_synchronization = true;
- params.hit_test_data_provider =
- std::make_unique<viz::HitTestDataProviderDrawQuad>(
- false /* should_ask_for_child_region */,
- true /* root_accepts_events */);
+ if (features::IsVizHitTestingDrawQuadEnabled()) {
+ params.hit_test_data_provider =
+ std::make_unique<viz::HitTestDataProviderDrawQuad>(
+ false /* should_ask_for_child_region */,
+ true /* root_accepts_events */);
+ }
params.client_name = kBrowser;
compositor->SetLayerTreeFrameSink(
std::make_unique<cc::mojo_embedder::AsyncLayerTreeFrameSink>(
diff --git a/chromium/ui/compositor/layer.cc b/chromium/ui/compositor/layer.cc
index f8f3f8cafdb..b605b586cdd 100644
--- a/chromium/ui/compositor/layer.cc
+++ b/chromium/ui/compositor/layer.cc
@@ -189,16 +189,16 @@ std::unique_ptr<Layer> Layer::Clone() const {
// cc::Layer state.
if (surface_layer_) {
- clone->SetShowPrimarySurface(
- surface_layer_->primary_surface_id(), frame_size_in_dip_,
- surface_layer_->background_color(),
- surface_layer_->deadline_in_frames()
- ? cc::DeadlinePolicy::UseSpecifiedDeadline(
- *surface_layer_->deadline_in_frames())
- : cc::DeadlinePolicy::UseDefaultDeadline(),
- surface_layer_->stretch_content_to_fill_bounds());
- if (surface_layer_->fallback_surface_id())
- clone->SetFallbackSurfaceId(*surface_layer_->fallback_surface_id());
+ clone->SetShowSurface(surface_layer_->surface_id(), frame_size_in_dip_,
+ surface_layer_->background_color(),
+ surface_layer_->deadline_in_frames()
+ ? cc::DeadlinePolicy::UseSpecifiedDeadline(
+ *surface_layer_->deadline_in_frames())
+ : cc::DeadlinePolicy::UseDefaultDeadline(),
+ surface_layer_->stretch_content_to_fill_bounds());
+ if (surface_layer_->oldest_acceptable_fallback())
+ clone->SetOldestAcceptableFallback(
+ *surface_layer_->oldest_acceptable_fallback());
} else if (type_ == LAYER_SOLID_COLOR) {
clone->SetColor(GetTargetColor());
}
@@ -525,7 +525,7 @@ void Layer::SetLayerBackgroundFilters() {
background_blur_sigma_, SkBlurImageFilter::kClamp_TileMode));
}
- cc_layer_->SetBackgroundFilters(filters);
+ cc_layer_->SetBackdropFilters(filters);
}
float Layer::GetTargetOpacity() const {
@@ -776,21 +776,16 @@ bool Layer::TextureFlipped() const {
return texture_layer_->flipped();
}
-void Layer::SetShowPrimarySurface(const viz::SurfaceId& surface_id,
- const gfx::Size& frame_size_in_dip,
- SkColor default_background_color,
- const cc::DeadlinePolicy& deadline_policy,
- bool stretch_content_to_fill_bounds) {
+void Layer::SetShowSurface(const viz::SurfaceId& surface_id,
+ const gfx::Size& frame_size_in_dip,
+ SkColor default_background_color,
+ const cc::DeadlinePolicy& deadline_policy,
+ bool stretch_content_to_fill_bounds) {
DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
- if (!surface_layer_) {
- scoped_refptr<cc::SurfaceLayer> new_layer = cc::SurfaceLayer::Create();
- new_layer->SetSurfaceHitTestable(true);
- SwitchToLayer(new_layer);
- surface_layer_ = new_layer;
- }
+ CreateSurfaceLayerIfNecessary();
- surface_layer_->SetPrimarySurfaceId(surface_id, deadline_policy);
+ surface_layer_->SetSurfaceId(surface_id, deadline_policy);
surface_layer_->SetBackgroundColor(default_background_color);
surface_layer_->SetStretchContentToFillBounds(stretch_content_to_fill_bounds);
@@ -798,31 +793,53 @@ void Layer::SetShowPrimarySurface(const viz::SurfaceId& surface_id,
RecomputeDrawsContentAndUVRect();
for (const auto& mirror : mirrors_) {
- mirror->dest()->SetShowPrimarySurface(
- surface_id, frame_size_in_dip, default_background_color,
- deadline_policy, stretch_content_to_fill_bounds);
+ mirror->dest()->SetShowSurface(surface_id, frame_size_in_dip,
+ default_background_color, deadline_policy,
+ stretch_content_to_fill_bounds);
}
}
-void Layer::SetFallbackSurfaceId(const viz::SurfaceId& surface_id) {
+void Layer::SetOldestAcceptableFallback(const viz::SurfaceId& surface_id) {
DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
- DCHECK(surface_layer_);
- surface_layer_->SetFallbackSurfaceId(surface_id);
+ CreateSurfaceLayerIfNecessary();
+
+ surface_layer_->SetOldestAcceptableFallback(surface_id);
for (const auto& mirror : mirrors_)
- mirror->dest()->SetFallbackSurfaceId(surface_id);
+ mirror->dest()->SetOldestAcceptableFallback(surface_id);
+}
+
+void Layer::SetShowReflectedSurface(const viz::SurfaceId& surface_id,
+ const gfx::Size& frame_size_in_pixels) {
+ DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
+
+ if (!surface_layer_) {
+ scoped_refptr<cc::SurfaceLayer> new_layer = cc::SurfaceLayer::Create();
+ SwitchToLayer(new_layer);
+ surface_layer_ = new_layer;
+ }
+
+ surface_layer_->SetSurfaceId(surface_id,
+ cc::DeadlinePolicy::UseInfiniteDeadline());
+ surface_layer_->SetBackgroundColor(SK_ColorBLACK);
+ // TODO(kylechar): Include UV transform and don't stretch to fill bounds.
+ surface_layer_->SetStretchContentToFillBounds(true);
+
+ // The reflecting surface uses the native size of the display.
+ frame_size_in_dip_ = frame_size_in_pixels;
+ RecomputeDrawsContentAndUVRect();
}
-const viz::SurfaceId* Layer::GetPrimarySurfaceId() const {
+const viz::SurfaceId* Layer::GetSurfaceId() const {
if (surface_layer_)
- return &surface_layer_->primary_surface_id();
+ return &surface_layer_->surface_id();
return nullptr;
}
-const viz::SurfaceId* Layer::GetFallbackSurfaceId() const {
- if (surface_layer_ && surface_layer_->fallback_surface_id())
- return &surface_layer_->fallback_surface_id().value();
+const viz::SurfaceId* Layer::GetOldestAcceptableFallback() const {
+ if (surface_layer_ && surface_layer_->oldest_acceptable_fallback())
+ return &surface_layer_->oldest_acceptable_fallback().value();
return nullptr;
}
@@ -1333,4 +1350,13 @@ void Layer::OnMirrorDestroyed(LayerMirror* mirror) {
mirrors_.erase(it);
}
+void Layer::CreateSurfaceLayerIfNecessary() {
+ if (surface_layer_)
+ return;
+ scoped_refptr<cc::SurfaceLayer> new_layer = cc::SurfaceLayer::Create();
+ new_layer->SetSurfaceHitTestable(true);
+ SwitchToLayer(new_layer);
+ surface_layer_ = new_layer;
+}
+
} // namespace ui
diff --git a/chromium/ui/compositor/layer.h b/chromium/ui/compositor/layer.h
index bda5eb12b82..3e1771ffb45 100644
--- a/chromium/ui/compositor/layer.h
+++ b/chromium/ui/compositor/layer.h
@@ -304,21 +304,26 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
// TODO(fsamuel): Update this comment.
// Begins showing content from a surface with a particular ID.
- void SetShowPrimarySurface(const viz::SurfaceId& surface_id,
- const gfx::Size& frame_size_in_dip,
- SkColor default_background_color,
- const cc::DeadlinePolicy& deadline_policy,
- bool stretch_content_to_fill_bounds);
+ void SetShowSurface(const viz::SurfaceId& surface_id,
+ const gfx::Size& frame_size_in_dip,
+ SkColor default_background_color,
+ const cc::DeadlinePolicy& deadline_policy,
+ bool stretch_content_to_fill_bounds);
// In the event that the primary surface is not yet available in the
// display compositor, the fallback surface will be used.
- void SetFallbackSurfaceId(const viz::SurfaceId& surface_id);
+ void SetOldestAcceptableFallback(const viz::SurfaceId& surface_id);
- // Returns the primary SurfaceId set by SetShowPrimarySurface.
- const viz::SurfaceId* GetPrimarySurfaceId() const;
+ // Begins mirroring content from a reflected surface, e.g. a software mirrored
+ // display. |surface_id| should be the root surface for a display.
+ void SetShowReflectedSurface(const viz::SurfaceId& surface_id,
+ const gfx::Size& frame_size_in_pixels);
- // Returns the fallback SurfaceId set by SetFallbackSurfaceId.
- const viz::SurfaceId* GetFallbackSurfaceId() const;
+ // Returns the primary SurfaceId set by SetShowSurface.
+ const viz::SurfaceId* GetSurfaceId() const;
+
+ // Returns the fallback SurfaceId set by SetOldestAcceptableFallback.
+ const viz::SurfaceId* GetOldestAcceptableFallback() const;
bool has_external_content() const {
return texture_layer_.get() || surface_layer_.get();
@@ -522,6 +527,8 @@ class COMPOSITOR_EXPORT Layer : public LayerAnimationDelegate,
void OnMirrorDestroyed(LayerMirror* mirror);
+ void CreateSurfaceLayerIfNecessary();
+
const LayerType type_;
Compositor* compositor_;
diff --git a/chromium/ui/compositor/layer_unittest.cc b/chromium/ui/compositor/layer_unittest.cc
index 190cf162069..efad60457e3 100644
--- a/chromium/ui/compositor/layer_unittest.cc
+++ b/chromium/ui/compositor/layer_unittest.cc
@@ -21,6 +21,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/animation/animation_events.h"
@@ -56,7 +57,6 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/font_list.h"
-#include "ui/gfx/gfx_paths.h"
#include "ui/gfx/interpolated_transform.h"
#include "ui/gfx/skia_util.h"
@@ -133,17 +133,20 @@ class LayerWithRealCompositorTest : public testing::Test {
LayerWithRealCompositorTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {
- if (base::PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_)) {
- test_data_directory_ = test_data_directory_.AppendASCII("compositor");
- } else {
- LOG(ERROR) << "Could not open test data directory.";
- }
gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
}
~LayerWithRealCompositorTest() override {}
// Overridden from testing::Test:
void SetUp() override {
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
+ test_data_dir_ = test_data_dir_.Append(FILE_PATH_LITERAL("ui"))
+ .Append(FILE_PATH_LITERAL("gfx"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .Append(FILE_PATH_LITERAL("compositor"));
+ ASSERT_TRUE(base::PathExists(test_data_dir_));
+
bool enable_pixel_output = true;
ui::ContextFactory* context_factory = nullptr;
ui::ContextFactoryPrivate* context_factory_private = nullptr;
@@ -244,9 +247,7 @@ class LayerWithRealCompositorTest : public testing::Test {
gfx::Rect(0, 0, layer->bounds().width(), layer->bounds().height()));
}
- const base::FilePath& test_data_directory() const {
- return test_data_directory_;
- }
+ const base::FilePath& test_data_dir() const { return test_data_dir_; }
private:
class ReadbackHolder : public base::RefCountedThreadSafe<ReadbackHolder> {
@@ -278,7 +279,7 @@ class LayerWithRealCompositorTest : public testing::Test {
std::unique_ptr<TestCompositorHost> compositor_host_;
// The root directory for test files.
- base::FilePath test_data_directory_;
+ base::FilePath test_data_dir_;
DISALLOW_COPY_AND_ASSIGN(LayerWithRealCompositorTest);
};
@@ -905,10 +906,12 @@ TEST_F(LayerWithDelegateTest, SurfaceLayerCloneAndMirror) {
viz::ParentLocalSurfaceIdAllocator allocator;
std::unique_ptr<Layer> layer(CreateLayer(LAYER_SOLID_COLOR));
- viz::LocalSurfaceId local_surface_id = allocator.GenerateId();
+ allocator.GenerateId();
+ viz::LocalSurfaceId local_surface_id =
+ allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
viz::SurfaceId surface_id_one(arbitrary_frame_sink, local_surface_id);
- layer->SetShowPrimarySurface(surface_id_one, gfx::Size(10, 10), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ layer->SetShowSurface(surface_id_one, gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
EXPECT_FALSE(layer->StretchContentToFillBounds());
auto clone = layer->Clone();
@@ -916,10 +919,12 @@ TEST_F(LayerWithDelegateTest, SurfaceLayerCloneAndMirror) {
auto mirror = layer->Mirror();
EXPECT_FALSE(mirror->StretchContentToFillBounds());
- local_surface_id = allocator.GenerateId();
+ allocator.GenerateId();
+ local_surface_id =
+ allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
viz::SurfaceId surface_id_two(arbitrary_frame_sink, local_surface_id);
- layer->SetShowPrimarySurface(surface_id_two, gfx::Size(10, 10), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(), true);
+ layer->SetShowSurface(surface_id_two, gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), true);
EXPECT_TRUE(layer->StretchContentToFillBounds());
clone = layer->Clone();
@@ -1508,7 +1513,7 @@ TEST_F(LayerWithRealCompositorTest, MAYBE_CompositorObservers) {
// Checks that modifying the hierarchy correctly affects final composite.
TEST_F(LayerWithRealCompositorTest, ModifyHierarchy) {
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(50, 50),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
// l0
// +-l11
@@ -1523,10 +1528,8 @@ TEST_F(LayerWithRealCompositorTest, ModifyHierarchy) {
std::unique_ptr<Layer> l12(
CreateColorLayer(SK_ColorBLUE, gfx::Rect(10, 10, 25, 25)));
- base::FilePath ref_img1 =
- test_data_directory().AppendASCII("ModifyHierarchy1.png");
- base::FilePath ref_img2 =
- test_data_directory().AppendASCII("ModifyHierarchy2.png");
+ base::FilePath ref_img1 = test_data_dir().AppendASCII("ModifyHierarchy1.png");
+ base::FilePath ref_img2 = test_data_dir().AppendASCII("ModifyHierarchy2.png");
SkBitmap bitmap;
l0->Add(l11.get());
@@ -1581,7 +1584,7 @@ TEST_F(LayerWithRealCompositorTest, ModifyHierarchy) {
#if defined(OS_WIN)
TEST_F(LayerWithRealCompositorTest, CanvasDrawFadedString) {
gfx::Size size(50, 50);
- GetCompositor()->SetScaleAndSize(1.0f, size, viz::LocalSurfaceId());
+ GetCompositor()->SetScaleAndSize(1.0f, size, viz::LocalSurfaceIdAllocation());
DrawFadedStringLayerDelegate delegate(SK_ColorBLUE, size);
std::unique_ptr<Layer> layer(
CreateDrawFadedStringLayerDelegate(gfx::Rect(size), &delegate));
@@ -1591,8 +1594,7 @@ TEST_F(LayerWithRealCompositorTest, CanvasDrawFadedString) {
ReadPixels(&bitmap);
ASSERT_FALSE(bitmap.empty());
- base::FilePath ref_img =
- test_data_directory().AppendASCII("string_faded.png");
+ base::FilePath ref_img = test_data_dir().AppendASCII("string_faded.png");
// WritePNGFile(bitmap, ref_img, true);
float percentage_pixels_large_error = 8.0f; // 200px / (50*50)
@@ -1616,7 +1618,7 @@ TEST_F(LayerWithRealCompositorTest, CanvasDrawFadedString) {
// Checks that modifying the hierarchy correctly affects final composite.
TEST_F(LayerWithRealCompositorTest, Opacity) {
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(50, 50),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
// l0
// +-l11
@@ -1625,7 +1627,7 @@ TEST_F(LayerWithRealCompositorTest, Opacity) {
std::unique_ptr<Layer> l11(
CreateColorLayer(SK_ColorGREEN, gfx::Rect(0, 0, 25, 25)));
- base::FilePath ref_img = test_data_directory().AppendASCII("Opacity.png");
+ base::FilePath ref_img = test_data_dir().AppendASCII("Opacity.png");
l11->SetOpacity(0.75);
l0->Add(l11.get());
@@ -1733,7 +1735,7 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
l1_delegate.set_layer_bounds(l1->bounds());
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(l1.get());
WaitForDraw();
@@ -1750,7 +1752,7 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
// Scale up to 2.0. Changing scale doesn't change the bounds in DIP.
GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
// CC layer should still match the UI layer bounds.
@@ -1765,7 +1767,7 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
// Scale down back to 1.0f.
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
EXPECT_EQ("10,20 140x180", l1->bounds().ToString());
// CC layer should still match the UI layer bounds.
@@ -1783,7 +1785,7 @@ TEST_F(LayerWithRealCompositorTest, ScaleUpDown) {
// Just changing the size shouldn't notify the scale change nor
// trigger repaint.
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(1000, 1000),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
// No scale change, so no scale notification.
EXPECT_EQ(0.0f, root_delegate.device_scale_factor());
EXPECT_EQ(0.0f, l1_delegate.device_scale_factor());
@@ -1800,7 +1802,7 @@ TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
l1_delegate.set_layer_bounds(l1->bounds());
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(500, 500),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(l1.get());
@@ -1814,7 +1816,7 @@ TEST_F(LayerWithRealCompositorTest, ScaleReparent) {
EXPECT_EQ(NULL, l1->parent());
EXPECT_EQ(NULL, l1->GetCompositor());
GetCompositor()->SetScaleAndSize(2.0f, gfx::Size(500, 500),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
// Sanity check on root and l1.
EXPECT_EQ("10,20 200x220", root->bounds().ToString());
cc_bounds_size = l1->cc_layer_for_testing()->bounds();
@@ -1889,18 +1891,26 @@ TEST_F(LayerWithDelegateTest, ExternalContent) {
viz::FrameSinkId frame_sink_id(1u, 1u);
viz::ParentLocalSurfaceIdAllocator allocator;
before = child->cc_layer_for_testing();
- child->SetShowPrimarySurface(
- viz::SurfaceId(frame_sink_id, allocator.GenerateId()), gfx::Size(10, 10),
- SK_ColorWHITE, cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ allocator.GenerateId();
+ child->SetShowSurface(
+ viz::SurfaceId(
+ frame_sink_id,
+ allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()),
+ gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
scoped_refptr<cc::Layer> after = child->cc_layer_for_testing();
const auto* surface = static_cast<cc::SurfaceLayer*>(after.get());
EXPECT_TRUE(after.get());
EXPECT_NE(before.get(), after.get());
EXPECT_EQ(base::nullopt, surface->deadline_in_frames());
- child->SetShowPrimarySurface(
- viz::SurfaceId(frame_sink_id, allocator.GenerateId()), gfx::Size(10, 10),
- SK_ColorWHITE, cc::DeadlinePolicy::UseSpecifiedDeadline(4u), false);
+ allocator.GenerateId();
+ child->SetShowSurface(
+ viz::SurfaceId(
+ frame_sink_id,
+ allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id()),
+ gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseSpecifiedDeadline(4u), false);
EXPECT_EQ(4u, surface->deadline_in_frames());
}
@@ -1910,29 +1920,29 @@ TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
viz::SurfaceId surface_id(
viz::FrameSinkId(0, 1),
viz::LocalSurfaceId(2, base::UnguessableToken::Create()));
- layer->SetShowPrimarySurface(surface_id, gfx::Size(10, 10), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ layer->SetShowSurface(surface_id, gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
const auto mirror = layer->Mirror();
auto* const cc_layer = mirror->cc_layer_for_testing();
const auto* surface = static_cast<cc::SurfaceLayer*>(cc_layer);
// Mirroring preserves surface state.
- EXPECT_EQ(surface_id, surface->primary_surface_id());
+ EXPECT_EQ(surface_id, surface->surface_id());
surface_id =
viz::SurfaceId(viz::FrameSinkId(1, 2),
viz::LocalSurfaceId(3, base::UnguessableToken::Create()));
- layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ layer->SetShowSurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
// The mirror should continue to use the same cc_layer.
EXPECT_EQ(cc_layer, mirror->cc_layer_for_testing());
- layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ layer->SetShowSurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
// Surface updates propagate to the mirror.
- EXPECT_EQ(surface_id, surface->primary_surface_id());
+ EXPECT_EQ(surface_id, surface->surface_id());
}
// Verifies that layer filters still attached after changing implementation
@@ -1949,9 +1959,8 @@ TEST_F(LayerWithDelegateTest, LayerFiltersSurvival) {
// Showing surface content changes the underlying cc layer.
scoped_refptr<cc::Layer> before = layer->cc_layer_for_testing();
- layer->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10),
- SK_ColorWHITE,
- cc::DeadlinePolicy::UseDefaultDeadline(), false);
+ layer->SetShowSurface(viz::SurfaceId(), gfx::Size(10, 10), SK_ColorWHITE,
+ cc::DeadlinePolicy::UseDefaultDeadline(), false);
EXPECT_EQ(layer->layer_grayscale(), 0.5f);
EXPECT_TRUE(layer->cc_layer_for_testing());
EXPECT_NE(before.get(), layer->cc_layer_for_testing());
@@ -2252,7 +2261,7 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixels) {
std::unique_ptr<Layer> c11(CreateLayer(LAYER_TEXTURED));
GetCompositor()->SetScaleAndSize(1.25f, gfx::Size(100, 100),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(c1.get());
c1->Add(c11.get());
@@ -2266,7 +2275,7 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixels) {
Vector2dFTo100thPrecisionString(c11->subpixel_position_offset()));
GetCompositor()->SetScaleAndSize(1.5f, gfx::Size(100, 100),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
SnapLayerToPhysicalPixelBoundary(root.get(), c11.get());
// c11 must already be aligned at 1.5 scale.
EXPECT_EQ("0.00 0.00",
@@ -2287,7 +2296,7 @@ TEST_F(LayerWithRealCompositorTest, SnapLayerToPixelsWithScaleTransform) {
std::unique_ptr<Layer> c111(CreateLayer(LAYER_TEXTURED));
GetCompositor()->SetScaleAndSize(1.0f, gfx::Size(100, 100),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
GetCompositor()->SetRootLayer(root.get());
root->Add(c1.get());
c1->Add(c11.get());
diff --git a/chromium/ui/compositor/recyclable_compositor_mac.cc b/chromium/ui/compositor/recyclable_compositor_mac.cc
index b8ca96d55ce..7f474063719 100644
--- a/chromium/ui/compositor/recyclable_compositor_mac.cc
+++ b/chromium/ui/compositor/recyclable_compositor_mac.cc
@@ -73,8 +73,11 @@ void RecyclableCompositorMac::UpdateSurface(const gfx::Size& size_pixels,
if (size_pixels != size_pixels_ || scale_factor != scale_factor_) {
size_pixels_ = size_pixels;
scale_factor_ = scale_factor;
+ local_surface_id_allocator_.GenerateId();
+ viz::LocalSurfaceIdAllocation local_surface_id_allocation =
+ local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
compositor()->SetScaleAndSize(scale_factor_, size_pixels_,
- local_surface_id_allocator_.GenerateId());
+ local_surface_id_allocation);
}
}
@@ -84,7 +87,7 @@ void RecyclableCompositorMac::InvalidateSurface() {
local_surface_id_allocator_.Invalidate();
compositor()->SetScaleAndSize(
scale_factor_, size_pixels_,
- local_surface_id_allocator_.GetCurrentLocalSurfaceId());
+ local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation());
}
void RecyclableCompositorMac::OnCompositingDidCommit(
diff --git a/chromium/ui/compositor/test/test_compositor_host_ozone.cc b/chromium/ui/compositor/test/test_compositor_host_ozone.cc
index 38d067327fd..5a97ed93e3a 100644
--- a/chromium/ui/compositor/test/test_compositor_host_ozone.cc
+++ b/chromium/ui/compositor/test/test_compositor_host_ozone.cc
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
@@ -87,7 +88,11 @@ TestCompositorHostOzone::TestCompositorHostOzone(
false /* enable_surface_synchronization */,
false /* enable_pixel_canvas */) {}
-TestCompositorHostOzone::~TestCompositorHostOzone() {}
+TestCompositorHostOzone::~TestCompositorHostOzone() {
+ // |window_| should be destroyed earlier than |window_delegate_| as it refers
+ // to its delegate on destroying.
+ window_.reset();
+}
void TestCompositorHostOzone::Show() {
ui::PlatformWindowInitProperties properties;
@@ -99,7 +104,8 @@ void TestCompositorHostOzone::Show() {
DCHECK_NE(window_delegate_.widget(), gfx::kNullAcceleratedWidget);
compositor_.SetAcceleratedWidget(window_delegate_.widget());
- compositor_.SetScaleAndSize(1.0f, bounds_.size(), viz::LocalSurfaceId());
+ compositor_.SetScaleAndSize(1.0f, bounds_.size(),
+ viz::LocalSurfaceIdAllocation());
compositor_.SetVisible(true);
}
diff --git a/chromium/ui/compositor_extra/shadow.cc b/chromium/ui/compositor_extra/shadow.cc
index d14b7e35f15..05b0f596b11 100644
--- a/chromium/ui/compositor_extra/shadow.cc
+++ b/chromium/ui/compositor_extra/shadow.cc
@@ -27,6 +27,7 @@ void Shadow::Init(int elevation) {
DCHECK_GE(elevation, 0);
desired_elevation_ = elevation;
layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN));
+ layer_->set_name("Shadow Parent Container");
RecreateShadowLayer();
}
diff --git a/chromium/ui/display/display_observer.h b/chromium/ui/display/display_observer.h
index e487ce3fe5b..3a11fd204ab 100644
--- a/chromium/ui/display/display_observer.h
+++ b/chromium/ui/display/display_observer.h
@@ -14,8 +14,6 @@ namespace display {
class Display;
// Observers for display configuration changes.
-// TODO(oshima): consolidate |WorkAreaWatcherObserver| and
-// |DisplaySettingsProvier|. crbug.com/122863.
class DISPLAY_EXPORT DisplayObserver : public base::CheckedObserver {
public:
enum DisplayMetric {
diff --git a/chromium/ui/display/mac/screen_mac.mm b/chromium/ui/display/mac/screen_mac.mm
index ec1fc4edf55..ff92b9fad59 100644
--- a/chromium/ui/display/mac/screen_mac.mm
+++ b/chromium/ui/display/mac/screen_mac.mm
@@ -168,7 +168,8 @@ class ScreenMac : public Screen {
return gfx::ScreenPointFromNSPoint([NSEvent mouseLocation]);
}
- bool IsWindowUnderCursor(gfx::NativeWindow window) override {
+ bool IsWindowUnderCursor(gfx::NativeWindow native_window) override {
+ NSWindow* window = native_window.GetNativeNSWindow();
return [NSWindow windowNumberAtPoint:[NSEvent mouseLocation]
belowWindowWithWindowNumber:0] == [window windowNumber];
}
@@ -184,7 +185,9 @@ class ScreenMac : public Screen {
return displays_;
}
- Display GetDisplayNearestWindow(gfx::NativeWindow window) const override {
+ Display GetDisplayNearestWindow(
+ gfx::NativeWindow native_window) const override {
+ NSWindow* window = native_window.GetNativeNSWindow();
EnsureDisplaysValid();
if (displays_.size() == 1)
return displays_[0];
@@ -202,7 +205,8 @@ class ScreenMac : public Screen {
return GetCachedDisplayForScreen(match_screen);
}
- Display GetDisplayNearestView(gfx::NativeView view) const override {
+ Display GetDisplayNearestView(gfx::NativeView native_view) const override {
+ NSView* view = native_view.GetNativeNSView();
NSWindow* window = [view window];
if (!window)
return GetPrimaryDisplay();
@@ -366,12 +370,14 @@ class ScreenMac : public Screen {
} // namespace
// static
-gfx::NativeWindow Screen::GetWindowForView(gfx::NativeView view) {
- NSWindow* window = nil;
+gfx::NativeWindow Screen::GetWindowForView(gfx::NativeView native_view) {
#if !defined(USE_AURA)
- window = [view window];
-#endif
+ NSView* view = native_view.GetNativeNSView();
+ return [view window];
+#else
+ gfx::NativeWindow window = nil;
return window;
+#endif
}
#if !defined(USE_AURA)
diff --git a/chromium/ui/display/manager/display_manager.cc b/chromium/ui/display/manager/display_manager.cc
index 06e2cff23c5..043235bbee0 100644
--- a/chromium/ui/display/manager/display_manager.cc
+++ b/chromium/ui/display/manager/display_manager.cc
@@ -40,7 +40,7 @@
#include "ui/strings/grit/ui_strings.h"
#if defined(OS_CHROMEOS)
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "base/time/time.h"
#include "chromeos/system/devicemode.h"
#include "ui/display/manager/display_util.h"
@@ -1003,7 +1003,7 @@ void DisplayManager::UpdateDisplaysWith(
new_displays.push_back(new_display);
++curr_iter;
++new_info_iter;
- } else if (curr_iter->id() < new_info_iter->id()) {
+ } else if (CompareDisplayIds(curr_iter->id(), new_info_iter->id())) {
// more displays in current list between ids, which means it is deleted.
removed_displays.push_back(*curr_iter);
++curr_iter;
@@ -1214,12 +1214,40 @@ void DisplayManager::SetUnifiedDesktopMatrix(
SetDefaultMultiDisplayModeForCurrentDisplays(UNIFIED);
}
-const Display* DisplayManager::GetPrimaryMirroringDisplayForUnifiedDesktop()
- const {
+Display DisplayManager::GetMirroringDisplayForUnifiedDesktop(
+ DisplayPositionInUnifiedMatrix cell_position) const {
if (!IsInUnifiedMode())
- return nullptr;
+ return Display();
+
+ DCHECK(!current_unified_desktop_matrix_.empty());
+
+ const size_t rows = current_unified_desktop_matrix_.size();
+ const size_t columns = current_unified_desktop_matrix_[0].size();
+
+ int64_t display_id = kInvalidDisplayId;
+ switch (cell_position) {
+ case DisplayPositionInUnifiedMatrix::kTopLeft:
+ display_id = current_unified_desktop_matrix_[0][0];
+ break;
+
+ case DisplayPositionInUnifiedMatrix::kTopRight:
+ display_id = current_unified_desktop_matrix_[0][columns - 1];
+ break;
+
+ case DisplayPositionInUnifiedMatrix::kBottomLeft:
+ display_id = current_unified_desktop_matrix_[rows - 1][0];
+ break;
+ }
+
+ DCHECK_NE(display_id, kInvalidDisplayId);
+
+ for (auto& display : software_mirroring_display_list_) {
+ if (display.id() == display_id)
+ return display;
+ }
- return &software_mirroring_display_list_[0];
+ NOTREACHED();
+ return Display();
}
int DisplayManager::GetMirroringDisplayRowIndexInUnifiedMatrix(
@@ -1338,7 +1366,8 @@ void DisplayManager::SetMirrorMode(
ReconfigureDisplays();
}
-void DisplayManager::AddRemoveDisplay() {
+void DisplayManager::AddRemoveDisplay(
+ ManagedDisplayInfo::ManagedDisplayModeList display_modes) {
DCHECK(!active_display_list_.empty());
DisplayInfoList new_display_info_list;
@@ -1349,13 +1378,33 @@ void DisplayManager::AddRemoveDisplay() {
new_display_info_list.push_back(first_display);
// Add if there is only one display connected.
if (num_connected_displays() == 1) {
+ gfx::Rect host_bounds = first_display.bounds_in_native();
+ if (display_modes.empty()) {
+ display_modes.emplace_back(
+ gfx::Size(600 /* width */, host_bounds.height()),
+ 60.0, /* refresh_rate */
+ false /* is_interlaced */, true /* native */);
+ }
+
+ // Find native display mode (or just the first one if there is no
+ // mode marked as native) and create a display with this mode as a default
+ const ManagedDisplayMode* native_display_mode = &(display_modes[0]);
+ for (const ManagedDisplayMode& display_mode : display_modes) {
+ if (display_mode.native()) {
+ native_display_mode = &display_mode;
+ break;
+ }
+ }
+
const int kVerticalOffsetPx = 100;
// Layout the 2nd display below the primary as with the real device.
- gfx::Rect host_bounds = first_display.bounds_in_native();
- new_display_info_list.push_back(
- ManagedDisplayInfo::CreateFromSpec(base::StringPrintf(
- "%d+%d-600x%d", host_bounds.x(),
- host_bounds.bottom() + kVerticalOffsetPx, host_bounds.height())));
+ ManagedDisplayInfo display = ManagedDisplayInfo::CreateFromSpec(
+ base::StringPrintf("%d+%d-%dx%d", host_bounds.x(),
+ host_bounds.bottom() + kVerticalOffsetPx,
+ native_display_mode->size().width(),
+ native_display_mode->size().height()));
+ display.SetManagedDisplayModes(std::move(display_modes));
+ new_display_info_list.push_back(std::move(display));
}
num_connected_displays_ = new_display_info_list.size();
ClearMirroringSourceAndDestination();
@@ -2147,6 +2196,12 @@ void DisplayManager::UpdateInfoForRestoringMirrorMode() {
if (num_connected_displays_ <= 1)
return;
+ // External displays mirrored because of forced tablet mode mirroring should
+ // not be considered candidates for restoring their mirrored state.
+ // https://crbug.com/919994.
+ if (layout_store_->forced_mirror_mode_for_tablet())
+ return;
+
for (auto id : GetCurrentDisplayIdList()) {
if (Display::IsInternalDisplayId(id))
continue;
diff --git a/chromium/ui/display/manager/display_manager.h b/chromium/ui/display/manager/display_manager.h
index 6f0d784463d..6b24e337e78 100644
--- a/chromium/ui/display/manager/display_manager.h
+++ b/chromium/ui/display/manager/display_manager.h
@@ -375,11 +375,11 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// current mode to Unified Desktop.
void SetUnifiedDesktopMatrix(const UnifiedDesktopLayoutMatrix& matrix);
- // In Unified Desktop mode, we consider the first mirroring display to be the
- // primary. It's also the top-left display in the layout matrix, and it's
- // where the shelf is placed.
- // This returns nullptr if we're not in unified desktop mode.
- const Display* GetPrimaryMirroringDisplayForUnifiedDesktop() const;
+ // Returns the Unified Desktop mode mirroring display according to the
+ // supplied |cell_position| in the matrix. Returns invalid display if we're
+ // not in Unified mode.
+ Display GetMirroringDisplayForUnifiedDesktop(
+ DisplayPositionInUnifiedMatrix cell_position) const;
// Returns the index of the row in the Unified Mode layout matrix which
// contains the display with |display_id|.
@@ -420,7 +420,8 @@ class DISPLAY_MANAGER_EXPORT DisplayManager
// Used to emulate display change when run in a desktop environment instead
// of on a device.
- void AddRemoveDisplay();
+ void AddRemoveDisplay(
+ ManagedDisplayInfo::ManagedDisplayModeList display_modes = {});
void ToggleDisplayScaleFactor();
// SoftwareMirroringController override:
diff --git a/chromium/ui/display/manager/display_manager_utilities.cc b/chromium/ui/display/manager/display_manager_utilities.cc
index a8e5120d5bc..3b395db8bda 100644
--- a/chromium/ui/display/manager/display_manager_utilities.cc
+++ b/chromium/ui/display/manager/display_manager_utilities.cc
@@ -9,7 +9,7 @@
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "ui/display/display_switches.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/gfx/geometry/size_conversions.h"
diff --git a/chromium/ui/display/unified_desktop_utils.h b/chromium/ui/display/unified_desktop_utils.h
index 7c120e0b7d5..426b32370df 100644
--- a/chromium/ui/display/unified_desktop_utils.h
+++ b/chromium/ui/display/unified_desktop_utils.h
@@ -12,6 +12,13 @@
namespace display {
+// Defines a display position in the unified display matrix.
+enum class DisplayPositionInUnifiedMatrix {
+ kTopLeft,
+ kTopRight,
+ kBottomLeft,
+};
+
// Type of the matrix that represents the display layout in Unified Desktop
// mode. The ID of a display is placed in a cell in the matrix where that
// display is desired to be placed in the actual layout.
diff --git a/chromium/ui/display/util/BUILD.gn b/chromium/ui/display/util/BUILD.gn
index ebf6b16c1c2..86f8f992942 100644
--- a/chromium/ui/display/util/BUILD.gn
+++ b/chromium/ui/display/util/BUILD.gn
@@ -5,6 +5,7 @@
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
+import("//ui/ozone/ozone.gni")
jumbo_component("util") {
output_name = "display_util"
@@ -27,7 +28,7 @@ jumbo_component("util") {
"//ui/gfx/geometry",
]
- if (use_x11) {
+ if (use_x11 || ozone_platform_x11) {
sources += [
"x11/edid_parser_x11.cc",
"x11/edid_parser_x11.h",
@@ -40,6 +41,10 @@ jumbo_component("util") {
}
if (is_chromeos) {
deps += [ "//ui/display/types" ]
+ } else if (is_mac) {
+ libs = [
+ "IOSurface.framework",
+ ]
}
}
diff --git a/chromium/ui/events/BUILD.gn b/chromium/ui/events/BUILD.gn
index 75bd864ef4b..278550b665b 100644
--- a/chromium/ui/events/BUILD.gn
+++ b/chromium/ui/events/BUILD.gn
@@ -161,6 +161,7 @@ jumbo_component("events") {
"event_dispatcher.h",
"event_handler.h",
"event_modifiers.h",
+ "event_observer.h",
"event_processor.h",
"event_rewriter.h",
"event_sink.h",
@@ -194,6 +195,7 @@ jumbo_component("events") {
"event_source.cc",
"event_target.cc",
"event_utils.cc",
+ "events_exports.cc",
"events_stub.cc",
"gestures/gesture_recognizer.cc",
"gestures/gesture_recognizer_impl_mac.cc",
@@ -209,8 +211,10 @@ jumbo_component("events") {
"system_input_injector.cc",
"win/events_win.cc",
"win/events_win_utils.cc",
- "win/keyboard_hook_win.cc",
- "win/keyboard_hook_win.h",
+ "win/keyboard_hook_win_base.cc",
+ "win/keyboard_hook_win_base.h",
+ "win/media_keyboard_hook_win.cc",
+ "win/modifier_keyboard_hook_win.cc",
"win/system_event_state_lookup.cc",
]
@@ -413,6 +417,8 @@ jumbo_static_library("test_support") {
"test/test_event_handler.h",
"test/test_event_processor.cc",
"test/test_event_processor.h",
+ "test/test_event_rewriter.cc",
+ "test/test_event_rewriter.h",
"test/test_event_target.cc",
"test/test_event_target.h",
"test/test_event_targeter.cc",
@@ -505,7 +511,8 @@ if (!is_ios) {
"platform/platform_event_source_unittest.cc",
"scoped_target_handler_unittest.cc",
"win/event_utils_win_unittest.cc",
- "win/keyboard_hook_win_unittest.cc",
+ "win/media_keyboard_hook_win_unittest.cc",
+ "win/modifier_keyboard_hook_win_unittest.cc",
]
deps = [
@@ -611,6 +618,7 @@ if (!is_ios) {
if (is_fuchsia) {
sources += [ "fuchsia/input_event_dispatcher_unittest.cc" ]
+ deps += [ "//third_party/fuchsia-sdk/sdk:input" ]
}
}
}
@@ -626,3 +634,21 @@ if (is_android) {
classes = [ "android/view/KeyEvent.class" ]
}
}
+
+# This target is added as a dependency of browser interactive_ui_tests. It must
+# be source_set, otherwise the linker will drop the tests as dead code.
+source_set("events_interactive_ui_tests") {
+ testonly = true
+ if (is_win) {
+ sources = [
+ "win/media_keyboard_hook_win_interactive_test.cc",
+ ]
+
+ deps = [
+ ":events",
+ ":test_support",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/chromium/ui/events/android/keyboard_hook_android.cc b/chromium/ui/events/android/keyboard_hook_android.cc
index be373af2175..31937535ffc 100644
--- a/chromium/ui/events/android/keyboard_hook_android.cc
+++ b/chromium/ui/events/android/keyboard_hook_android.cc
@@ -14,11 +14,17 @@
namespace ui {
// static
-std::unique_ptr<KeyboardHook> KeyboardHook::Create(
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
base::Optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget,
KeyboardHook::KeyEventCallback callback) {
return nullptr;
}
+// static
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateMediaKeyboardHook(
+ KeyboardHook::KeyEventCallback callback) {
+ return nullptr;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/blink/blink_event_util.cc b/chromium/ui/events/blink/blink_event_util.cc
index 6d3fda87397..a2108c64397 100644
--- a/chromium/ui/events/blink/blink_event_util.cc
+++ b/chromium/ui/events/blink/blink_event_util.cc
@@ -754,6 +754,8 @@ WebGestureEvent CreateWebGestureEvent(const GestureEventDetails& details,
gesture.data.tap.tap_count = details.tap_count();
gesture.data.tap.width = details.bounding_box_f().width();
gesture.data.tap.height = details.bounding_box_f().height();
+ gesture.SetNeedsWheelEvent(source_device ==
+ blink::kWebGestureDeviceTouchpad);
break;
case ET_GESTURE_TAP:
gesture.SetType(WebInputEvent::kGestureTap);
@@ -1077,13 +1079,13 @@ EventType WebEventTypeToEventType(WebInputEvent::Type type) {
return ET_TOUCH_CANCELLED;
case WebInputEvent::kTouchScrollStarted:
case WebInputEvent::kPointerDown:
- return ET_POINTER_DOWN;
+ return ET_TOUCH_PRESSED;
case WebInputEvent::kPointerUp:
- return ET_POINTER_UP;
+ return ET_TOUCH_RELEASED;
case WebInputEvent::kPointerMove:
- return ET_POINTER_MOVED;
+ return ET_TOUCH_MOVED;
case WebInputEvent::kPointerCancel:
- return ET_POINTER_CANCELLED;
+ return ET_TOUCH_CANCELLED;
default:
return ET_UNKNOWN;
}
diff --git a/chromium/ui/events/blink/blink_features.cc b/chromium/ui/events/blink/blink_features.cc
index a88686acbcd..a5ded831437 100644
--- a/chromium/ui/events/blink/blink_features.cc
+++ b/chromium/ui/events/blink/blink_features.cc
@@ -6,14 +6,12 @@
namespace features {
-// Enables VSync aligned input for GestureScroll/Pinch on compositor thread.
-// Tracking: https://crbug.com/625689
-const base::Feature kVsyncAlignedInputEvents{"VsyncAlignedInput",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kResamplingScrollEvents{"ResamplingScrollEvents",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kScrollPredictorTypeChoice{
+ "ScrollPredictorTypeChoice", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kSendMouseLeaveEvents{"SendMouseLeaveEvents",
base::FEATURE_ENABLED_BY_DEFAULT};
@@ -22,4 +20,7 @@ const base::Feature kNoHoverAfterLayoutChange{
const base::Feature kNoHoverDuringScroll{"NoHoverDuringScroll",
base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kCompositorTouchAction{"CompositorTouchAction",
+ base::FEATURE_DISABLED_BY_DEFAULT};
}
diff --git a/chromium/ui/events/blink/blink_features.h b/chromium/ui/events/blink/blink_features.h
index c7ee6ef5495..08b123ed8c4 100644
--- a/chromium/ui/events/blink/blink_features.h
+++ b/chromium/ui/events/blink/blink_features.h
@@ -9,11 +9,15 @@
namespace features {
-extern const base::Feature kVsyncAlignedInputEvents;
-
// Enables resampling GestureScroll events on compositor thread.
extern const base::Feature kResamplingScrollEvents;
+// This flag is used to set field parameters to choose predictor we use when
+// resampling is disabled. It's used for gatherig accuracy metrics on finch
+// without enabling resampling. It does not have any effect when the resampling
+// flag is enabled.
+extern const base::Feature kScrollPredictorTypeChoice;
+
// This feature allows native ET_MOUSE_EXIT events to be passed
// through to blink as mouse leave events. Traditionally these events were
// converted to mouse move events due to a number of inconsistencies on
@@ -29,6 +33,10 @@ extern const base::Feature kNoHoverAfterLayoutChange;
// dispatching mouse enter/exit events for elements under the mouse as the page
// is scrolled.
extern const base::Feature kNoHoverDuringScroll;
+
+// Enables handling touch events in compositor using impl side touch action
+// knowledge.
+extern const base::Feature kCompositorTouchAction;
}
#endif // UI_EVENTS_BLINK_BLINK_FEATURES_H_
diff --git a/chromium/ui/events/blink/event_with_callback.cc b/chromium/ui/events/blink/event_with_callback.cc
index 3991269461a..cbed0013120 100644
--- a/chromium/ui/events/blink/event_with_callback.cc
+++ b/chromium/ui/events/blink/event_with_callback.cc
@@ -59,7 +59,11 @@ void EventWithCallback::CoalesceWith(EventWithCallback* other,
event_->SetTimeStamp(time_stamp);
// When coalescing two input events, we keep the oldest LatencyInfo
- // since it will represent the longest latency.
+ // since it will represent the longest latency. If it's a GestureScrollUpdate
+ // event, also update the old event's last timestamp and scroll delta using
+ // the newer event's latency info.
+ if (event_->GetType() == WebInputEvent::kGestureScrollUpdate)
+ latency_.CoalesceScrollUpdateWith(other->latency_);
other->latency_ = latency_;
other->latency_.set_coalesced();
diff --git a/chromium/ui/events/blink/input_handler_proxy.cc b/chromium/ui/events/blink/input_handler_proxy.cc
index d37158e58e1..7bb88f69628 100644
--- a/chromium/ui/events/blink/input_handler_proxy.cc
+++ b/chromium/ui/events/blink/input_handler_proxy.cc
@@ -144,7 +144,7 @@ InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler,
input_handler_(input_handler),
synchronous_input_handler_(nullptr),
allow_root_animate_(true),
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
expect_scroll_update_end_(false),
#endif
gesture_scroll_on_impl_thread_(false),
@@ -156,7 +156,9 @@ InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler,
has_ongoing_compositor_scroll_or_pinch_(false),
is_first_gesture_scroll_update_(false),
tick_clock_(base::DefaultTickClock::GetInstance()),
- snap_fling_controller_(std::make_unique<cc::SnapFlingController>(this)) {
+ snap_fling_controller_(std::make_unique<cc::SnapFlingController>(this)),
+ compositor_touch_action_enabled_(
+ base::FeatureList::IsEnabled(features::kCompositorTouchAction)) {
DCHECK(client);
input_handler_->BindToClient(this);
cc::ScrollElasticityHelper* scroll_elasticity_helper =
@@ -165,14 +167,9 @@ InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler,
scroll_elasticity_controller_.reset(
new InputScrollElasticityController(scroll_elasticity_helper));
}
- compositor_event_queue_ =
- base::FeatureList::IsEnabled(features::kVsyncAlignedInputEvents)
- ? std::make_unique<CompositorThreadEventQueue>()
- : nullptr;
- scroll_predictor_ =
- base::FeatureList::IsEnabled(features::kResamplingScrollEvents)
- ? std::make_unique<ScrollPredictor>()
- : nullptr;
+ compositor_event_queue_ = std::make_unique<CompositorThreadEventQueue>();
+ scroll_predictor_ = std::make_unique<ScrollPredictor>(
+ base::FeatureList::IsEnabled(features::kResamplingScrollEvents));
}
InputHandlerProxy::~InputHandlerProxy() {}
@@ -588,7 +585,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
if (compositor_event_queue_ && scroll_predictor_)
scroll_predictor_->ResetOnGestureScrollBegin(gesture_event);
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
expect_scroll_update_end_ = true;
#endif
cc::ScrollState scroll_state = CreateScrollStateForGesture(gesture_event);
@@ -648,7 +645,7 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
InputHandlerProxy::EventDisposition
InputHandlerProxy::HandleGestureScrollUpdate(
const WebGestureEvent& gesture_event) {
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
DCHECK(expect_scroll_update_end_);
#endif
@@ -699,7 +696,7 @@ InputHandlerProxy::HandleGestureScrollUpdate(
if (snap_fling_controller_->HandleGestureScrollUpdate(
GetGestureScrollUpdateInfo(gesture_event))) {
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
expect_scroll_update_end_ = false;
#endif
gesture_scroll_on_impl_thread_ = false;
@@ -729,7 +726,7 @@ InputHandlerProxy::HandleGestureScrollUpdate(
InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollEnd(
const WebGestureEvent& gesture_event) {
TRACE_EVENT0("input", "InputHandlerProxy::HandleGestureScrollEnd");
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
DCHECK(expect_scroll_update_end_);
expect_scroll_update_end_ = false;
#endif
@@ -788,7 +785,14 @@ InputHandlerProxy::EventDisposition InputHandlerProxy::HitTestTouchEvent(
event_listener_type ==
cc::InputHandler::TouchStartOrMoveEventListenerType::
HANDLER_ON_SCROLLING_LAYER;
- result = DID_NOT_HANDLE;
+ // A non-passive touch start / move will always set the whitelisted touch
+ // action to kTouchActionNone, and in that case we do not ack the event
+ // from the compositor.
+ if (compositor_touch_action_enabled_ && white_listed_touch_action &&
+ *white_listed_touch_action != cc::kTouchActionNone)
+ result = DID_HANDLE_NON_BLOCKING;
+ else
+ result = DID_NOT_HANDLE;
break;
}
}
diff --git a/chromium/ui/events/blink/input_handler_proxy.h b/chromium/ui/events/blink/input_handler_proxy.h
index c3dc86ba139..60175cc13da 100644
--- a/chromium/ui/events/blink/input_handler_proxy.h
+++ b/chromium/ui/events/blink/input_handler_proxy.h
@@ -186,7 +186,7 @@ class InputHandlerProxy : public cc::InputHandlerClient,
SynchronousInputHandler* synchronous_input_handler_;
bool allow_root_animate_;
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
bool expect_scroll_update_end_;
#endif
bool gesture_scroll_on_impl_thread_;
@@ -224,6 +224,8 @@ class InputHandlerProxy : public cc::InputHandlerClient,
std::unique_ptr<ScrollPredictor> scroll_predictor_;
+ bool compositor_touch_action_enabled_;
+
DISALLOW_COPY_AND_ASSIGN(InputHandlerProxy);
};
diff --git a/chromium/ui/events/blink/input_handler_proxy_unittest.cc b/chromium/ui/events/blink/input_handler_proxy_unittest.cc
index c0d6d6fb0b9..39e30dd7360 100644
--- a/chromium/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/chromium/ui/events/blink/input_handler_proxy_unittest.cc
@@ -63,10 +63,21 @@ enum InputHandlerProxyTestType {
ROOT_SCROLL_SYNCHRONOUS_HANDLER,
CHILD_SCROLL_NORMAL_HANDLER,
CHILD_SCROLL_SYNCHRONOUS_HANDLER,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_NORMAL,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_NORMAL,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS,
};
static const InputHandlerProxyTestType test_types[] = {
- ROOT_SCROLL_NORMAL_HANDLER, ROOT_SCROLL_SYNCHRONOUS_HANDLER,
- CHILD_SCROLL_NORMAL_HANDLER, CHILD_SCROLL_SYNCHRONOUS_HANDLER};
+ ROOT_SCROLL_NORMAL_HANDLER,
+ ROOT_SCROLL_SYNCHRONOUS_HANDLER,
+ CHILD_SCROLL_NORMAL_HANDLER,
+ CHILD_SCROLL_SYNCHRONOUS_HANDLER,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_NORMAL,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_NORMAL,
+ COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS,
+};
MATCHER_P(WheelEventsMatch, expected, "") {
return WheelEventsMatch(arg, expected);
@@ -287,11 +298,24 @@ class InputHandlerProxyTest
public testing::WithParamInterface<InputHandlerProxyTestType> {
public:
InputHandlerProxyTest()
- : synchronous_root_scroll_(GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER),
+ : synchronous_root_scroll_(
+ GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER ||
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS),
install_synchronous_handler_(
GetParam() == ROOT_SCROLL_SYNCHRONOUS_HANDLER ||
- GetParam() == CHILD_SCROLL_SYNCHRONOUS_HANDLER),
+ GetParam() == CHILD_SCROLL_SYNCHRONOUS_HANDLER ||
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS ||
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS),
+ compositor_touch_action_enabled_(
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_NORMAL ||
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_ROOT_SYNCHRONOUS ||
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_NORMAL ||
+ GetParam() == COMPOSITOR_TOUCH_ACTION_ENABLED_CHILD_SYNCHRONOUS),
expected_disposition_(InputHandlerProxy::DID_HANDLE) {
+ if (compositor_touch_action_enabled_)
+ feature_list_.InitAndEnableFeature(features::kCompositorTouchAction);
+ else
+ feature_list_.InitAndDisableFeature(features::kCompositorTouchAction);
input_handler_.reset(
new TestInputHandlerProxy(&mock_input_handler_, &mock_client_));
scroll_result_did_scroll_.did_scroll = true;
@@ -364,6 +388,7 @@ class InputHandlerProxyTest
const bool synchronous_root_scroll_;
const bool install_synchronous_handler_;
+ const bool compositor_touch_action_enabled_;
testing::StrictMock<MockInputHandler> mock_input_handler_;
testing::StrictMock<MockSynchronousInputHandler>
mock_synchronous_input_handler_;
@@ -374,13 +399,14 @@ class InputHandlerProxyTest
base::HistogramTester histogram_tester_;
cc::InputHandlerScrollResult scroll_result_did_scroll_;
cc::InputHandlerScrollResult scroll_result_did_not_scroll_;
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
};
class InputHandlerProxyEventQueueTest : public testing::Test {
public:
- InputHandlerProxyEventQueueTest() : weak_ptr_factory_(this) {
- feature_list_.InitAndEnableFeature(features::kVsyncAlignedInputEvents);
- }
+ InputHandlerProxyEventQueueTest() : weak_ptr_factory_(this) {}
~InputHandlerProxyEventQueueTest() { input_handler_proxy_.reset(); }
@@ -393,7 +419,7 @@ class InputHandlerProxyEventQueueTest : public testing::Test {
input_handler_proxy_->compositor_event_queue_ =
std::make_unique<CompositorThreadEventQueue>();
input_handler_proxy_->scroll_predictor_ =
- std::make_unique<ScrollPredictor>();
+ std::make_unique<ScrollPredictor>(true /* enable_resampling */);
}
void HandleGestureEvent(WebInputEvent::Type type,
@@ -444,7 +470,6 @@ class InputHandlerProxyEventQueueTest : public testing::Test {
}
protected:
- base::test::ScopedFeatureList feature_list_;
testing::StrictMock<MockInputHandler> mock_input_handler_;
std::unique_ptr<TestInputHandlerProxy> input_handler_proxy_;
testing::StrictMock<MockInputHandlerProxyClient> mock_client_;
@@ -1004,7 +1029,9 @@ TEST_P(InputHandlerProxyTest,
TEST_P(InputHandlerProxyTest, HitTestTouchEventNonNullTouchAction) {
// One of the touch points is on a touch-region. So the event should be sent
// to the main thread.
- expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+ expected_disposition_ = compositor_touch_action_enabled_
+ ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
+ : InputHandlerProxy::DID_NOT_HANDLE;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(
@@ -1134,7 +1161,9 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestNegative) {
TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
// One of the touch points is on a touch-region. So the event should be sent
// to the main thread.
- expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+ expected_disposition_ = compositor_touch_action_enabled_
+ ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
+ : InputHandlerProxy::DID_NOT_HANDLE;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(
@@ -1156,9 +1185,8 @@ TEST_P(InputHandlerProxyTest, MultiTouchPointHitTestPositive) {
return cc::InputHandler::TouchStartOrMoveEventListenerType::
HANDLER_ON_SCROLLING_LAYER;
}));
- EXPECT_CALL(mock_client_,
- SetWhiteListedTouchAction(cc::kTouchActionPanY, 1,
- InputHandlerProxy::DID_NOT_HANDLE))
+ EXPECT_CALL(mock_client_, SetWhiteListedTouchAction(cc::kTouchActionPanY, 1,
+ expected_disposition_))
.WillOnce(testing::Return());
// Since the second touch point hits a touch-region, there should be no
// hit-testing for the third touch point.
@@ -1301,7 +1329,9 @@ TEST_P(InputHandlerProxyTest, TouchMoveBlockingAddedAfterPassiveTouchStart) {
touch.touches_length = 1;
touch.touch_start_or_first_touch_move = true;
touch.touches[0] = CreateWebTouchPoint(WebTouchPoint::kStateMoved, 10, 10);
- EXPECT_EQ(InputHandlerProxy::DID_NOT_HANDLE,
+ EXPECT_EQ(compositor_touch_action_enabled_
+ ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
+ : InputHandlerProxy::DID_NOT_HANDLE,
input_handler_->HandleInputEvent(touch));
VERIFY_AND_RESET_MOCKS();
}
@@ -1977,9 +2007,8 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
GestureScrollTouchEventHandlerRegion) {
- // The touch event hits a touch event handler and should block on main thread.
- // Since ScrollBegin allows the gesture to scroll on impl. We collect
- // TouchEventHandler reason but not HandlingScrollFromMainThread.
+ // The touch event hits a touch event handler that is acked from the
+ // compositor thread when kCompositorTouchAction is enabld.
SetupEvents(TestEventType::Touch);
EXPECT_CALL(
@@ -1993,7 +2022,9 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
.WillOnce(testing::Return());
- expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+ expected_disposition_ = compositor_touch_action_enabled_
+ ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
+ : InputHandlerProxy::DID_NOT_HANDLE;
EXPECT_EQ(expected_disposition_,
input_handler_->HandleInputEvent(touch_start_));
@@ -2002,12 +2033,15 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
EXPECT_EQ(expected_disposition_,
input_handler_->HandleInputEvent(gesture_scroll_begin_));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "Renderer4.MainThreadGestureScrollReason"),
- testing::ElementsAre(base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
- 1)));
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples(
+ "Renderer4.MainThreadGestureScrollReason"),
+ testing::ElementsAre(base::Bucket(
+ GetBucketSample(
+ compositor_touch_action_enabled_
+ ? cc::MainThreadScrollingReason::kNotScrollingOnMain
+ : cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
+ 1)));
EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
expected_disposition_ = InputHandlerProxy::DID_HANDLE;
@@ -2036,7 +2070,9 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
.WillOnce(testing::Return());
- expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+ expected_disposition_ = compositor_touch_action_enabled_
+ ? InputHandlerProxy::DID_HANDLE_NON_BLOCKING
+ : InputHandlerProxy::DID_NOT_HANDLE;
EXPECT_EQ(expected_disposition_,
input_handler_->HandleInputEvent(touch_start_));
@@ -2046,12 +2082,15 @@ TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
EXPECT_EQ(expected_disposition_,
input_handler_->HandleInputEvent(gesture_scroll_begin_));
- EXPECT_THAT(histogram_tester().GetAllSamples(
- "Renderer4.MainThreadGestureScrollReason"),
- testing::ElementsAre(base::Bucket(
- GetBucketSample(
- cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
- 1)));
+ EXPECT_THAT(
+ histogram_tester().GetAllSamples(
+ "Renderer4.MainThreadGestureScrollReason"),
+ testing::ElementsAre(base::Bucket(
+ GetBucketSample(
+ compositor_touch_action_enabled_
+ ? cc::MainThreadScrollingReason::kHandlingScrollFromMainThread
+ : cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
+ 1)));
// Handle touch end event so that input handler proxy is out of the state of
// DID_NOT_HANDLE.
diff --git a/chromium/ui/events/blink/prediction/empty_predictor.cc b/chromium/ui/events/blink/prediction/empty_predictor.cc
index 10c17d57b25..dd4097c6f67 100644
--- a/chromium/ui/events/blink/prediction/empty_predictor.cc
+++ b/chromium/ui/events/blink/prediction/empty_predictor.cc
@@ -12,6 +12,10 @@ EmptyPredictor::EmptyPredictor() {
EmptyPredictor::~EmptyPredictor() = default;
+const char* EmptyPredictor::GetName() const {
+ return "Empty";
+}
+
void EmptyPredictor::Reset() {
last_input_.time_stamp = base::TimeTicks();
}
diff --git a/chromium/ui/events/blink/prediction/empty_predictor.h b/chromium/ui/events/blink/prediction/empty_predictor.h
index b1a849448c1..81a3e6ef936 100644
--- a/chromium/ui/events/blink/prediction/empty_predictor.h
+++ b/chromium/ui/events/blink/prediction/empty_predictor.h
@@ -15,6 +15,8 @@ class EmptyPredictor : public InputPredictor {
EmptyPredictor();
~EmptyPredictor() override;
+ const char* GetName() const override;
+
void Reset() override;
// store the cur_input in last_input_
diff --git a/chromium/ui/events/blink/prediction/input_predictor.h b/chromium/ui/events/blink/prediction/input_predictor.h
index 60f9bcd2c1c..1ca88db999a 100644
--- a/chromium/ui/events/blink/prediction/input_predictor.h
+++ b/chromium/ui/events/blink/prediction/input_predictor.h
@@ -25,6 +25,9 @@ class InputPredictor {
base::TimeTicks time_stamp;
};
+ // Returns the name of the predictor.
+ virtual const char* GetName() const = 0;
+
// Reset should be called each time when a new line start.
virtual void Reset() = 0;
diff --git a/chromium/ui/events/blink/prediction/kalman_predictor.cc b/chromium/ui/events/blink/prediction/kalman_predictor.cc
index c2d66ac10ee..2a6ed018293 100644
--- a/chromium/ui/events/blink/prediction/kalman_predictor.cc
+++ b/chromium/ui/events/blink/prediction/kalman_predictor.cc
@@ -22,6 +22,10 @@ KalmanPredictor::KalmanPredictor() = default;
KalmanPredictor::~KalmanPredictor() = default;
+const char* KalmanPredictor::GetName() const {
+ return "Kalman";
+}
+
void KalmanPredictor::Reset() {
x_predictor_.Reset();
y_predictor_.Reset();
@@ -47,15 +51,15 @@ bool KalmanPredictor::HasPrediction() const {
return x_predictor_.Stable() && y_predictor_.Stable();
}
-bool KalmanPredictor::GeneratePrediction(base::TimeTicks frame_time,
+bool KalmanPredictor::GeneratePrediction(base::TimeTicks predict_time,
InputData* result) const {
std::vector<InputData> pred_points;
- base::TimeDelta dt = frame_time - last_point_.time_stamp;
+ base::TimeDelta dt = predict_time - last_point_.time_stamp;
// Kalman filter is not very good when predicting backwards. Besides,
// predicting backwards means increasing latency. Thus disable prediction when
// dt < 0.
- if (!HasPrediction() || dt < base::TimeDelta::Min() || dt > kMaxResampleTime)
+ if (!HasPrediction() || dt < base::TimeDelta() || dt > kMaxResampleTime)
return false;
gfx::Vector2dF position(last_point_.pos.x(), last_point_.pos.y());
diff --git a/chromium/ui/events/blink/prediction/kalman_predictor.h b/chromium/ui/events/blink/prediction/kalman_predictor.h
index cf1edb33a6e..a52e3521944 100644
--- a/chromium/ui/events/blink/prediction/kalman_predictor.h
+++ b/chromium/ui/events/blink/prediction/kalman_predictor.h
@@ -22,6 +22,8 @@ class KalmanPredictor : public InputPredictor {
explicit KalmanPredictor();
~KalmanPredictor() override;
+ const char* GetName() const override;
+
// Reset the predictor to initial state.
void Reset() override;
@@ -33,7 +35,7 @@ class KalmanPredictor : public InputPredictor {
// Generate the prediction based on stored points and given time_stamp.
// Return false if no prediction available.
- bool GeneratePrediction(base::TimeTicks frame_time,
+ bool GeneratePrediction(base::TimeTicks predict_time,
InputData* result) const override;
private:
diff --git a/chromium/ui/events/blink/prediction/least_squares_predictor.cc b/chromium/ui/events/blink/prediction/least_squares_predictor.cc
index 534d3de407d..f8d43d2a470 100644
--- a/chromium/ui/events/blink/prediction/least_squares_predictor.cc
+++ b/chromium/ui/events/blink/prediction/least_squares_predictor.cc
@@ -40,6 +40,10 @@ LeastSquaresPredictor::LeastSquaresPredictor() {}
LeastSquaresPredictor::~LeastSquaresPredictor() {}
+const char* LeastSquaresPredictor::GetName() const {
+ return "LSQ";
+}
+
void LeastSquaresPredictor::Reset() {
x_queue_.clear();
y_queue_.clear();
@@ -75,14 +79,14 @@ gfx::Matrix3F LeastSquaresPredictor::GetXMatrix() const {
return x;
}
-bool LeastSquaresPredictor::GeneratePrediction(base::TimeTicks frame_time,
+bool LeastSquaresPredictor::GeneratePrediction(base::TimeTicks predict_time,
InputData* result) const {
- if (!HasPrediction() || frame_time - time_.back() > kMaxResampleTime)
+ if (!HasPrediction() || predict_time - time_.back() > kMaxResampleTime)
return false;
gfx::Matrix3F time_matrix = GetXMatrix();
- double dt = (frame_time - time_[0]).InMillisecondsF();
+ double dt = (predict_time - time_[0]).InMillisecondsF();
if (dt > 0) {
gfx::Vector3dF b1, b2;
if (SolveLeastSquares(time_matrix, x_queue_, b1) &&
diff --git a/chromium/ui/events/blink/prediction/least_squares_predictor.h b/chromium/ui/events/blink/prediction/least_squares_predictor.h
index c5eb33bfa26..87d734d1f8c 100644
--- a/chromium/ui/events/blink/prediction/least_squares_predictor.h
+++ b/chromium/ui/events/blink/prediction/least_squares_predictor.h
@@ -22,6 +22,8 @@ class LeastSquaresPredictor : public InputPredictor {
explicit LeastSquaresPredictor();
~LeastSquaresPredictor() override;
+ const char* GetName() const override;
+
// Reset the predictor to initial state.
void Reset() override;
@@ -33,7 +35,7 @@ class LeastSquaresPredictor : public InputPredictor {
// Generate the prediction based on stored points and given time_stamp.
// Return false if no prediction available.
- bool GeneratePrediction(base::TimeTicks frame_time,
+ bool GeneratePrediction(base::TimeTicks predict_time,
InputData* result) const override;
private:
diff --git a/chromium/ui/events/blink/scroll_predictor.cc b/chromium/ui/events/blink/scroll_predictor.cc
index 6c153b4889d..68a95b93864 100644
--- a/chromium/ui/events/blink/scroll_predictor.cc
+++ b/chromium/ui/events/blink/scroll_predictor.cc
@@ -6,6 +6,7 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
#include "base/trace_event/trace_event.h"
#include "ui/events/blink/prediction/empty_predictor.h"
#include "ui/events/blink/prediction/kalman_predictor.h"
@@ -24,12 +25,20 @@ constexpr char kScrollPredictorTypeKalman[] = "kalman";
} // namespace
-ScrollPredictor::ScrollPredictor() {
- std::string predictor_type_ = GetFieldTrialParamValueByFeature(
- features::kResamplingScrollEvents, kPredictor);
- if (predictor_type_ == kScrollPredictorTypeLsq)
+ScrollPredictor::ScrollPredictor(bool enable_resampling)
+ : enable_resampling_(enable_resampling) {
+ // When resampling is enabled, set predictor type by resampling flag params;
+ // otherwise, get predictor type parameters from kPredictorTypeChoice flag.
+ std::string predictor_type =
+ enable_resampling_
+ ? GetFieldTrialParamValueByFeature(features::kResamplingScrollEvents,
+ kPredictor)
+ : GetFieldTrialParamValueByFeature(
+ features::kScrollPredictorTypeChoice, kPredictor);
+
+ if (predictor_type == kScrollPredictorTypeLsq)
predictor_ = std::make_unique<LeastSquaresPredictor>();
- else if (predictor_type_ == kScrollPredictorTypeKalman)
+ else if (predictor_type == kScrollPredictorTypeKalman)
predictor_ = std::make_unique<KalmanPredictor>();
else
predictor_ = std::make_unique<EmptyPredictor>();
@@ -63,10 +72,14 @@ void ScrollPredictor::ResampleScrollEvents(
if (original_events.empty())
return;
+ temporary_accumulated_delta_ = current_accumulated_delta_;
+ for (auto& coalesced_event : original_events)
+ ComputeAccuracy(coalesced_event.event_);
+
for (auto& coalesced_event : original_events)
UpdatePrediction(coalesced_event.event_, frame_time);
- if (should_resample_scroll_events_)
+ if (enable_resampling_ && should_resample_scroll_events_)
ResampleEvent(frame_time, event);
TRACE_EVENT_END2("input", "ScrollPredictor::ResampleScrollEvents",
@@ -101,6 +114,7 @@ void ScrollPredictor::UpdatePrediction(const WebScopedInputEvent& event,
gesture_event.TimeStamp()};
predictor_->Update(data);
+ last_event_timestamp_ = gesture_event.TimeStamp();
}
void ScrollPredictor::ResampleEvent(base::TimeTicks time_stamp,
@@ -108,11 +122,11 @@ void ScrollPredictor::ResampleEvent(base::TimeTicks time_stamp,
DCHECK(event->GetType() == WebInputEvent::kGestureScrollUpdate);
WebGestureEvent* gesture_event = static_cast<WebGestureEvent*>(event);
- gfx::PointF predicted_accumulated_delta_ = current_accumulated_delta_;
+ gfx::PointF predicted_accumulated_delta = current_accumulated_delta_;
InputPredictor::InputData result;
if (predictor_->HasPrediction() &&
predictor_->GeneratePrediction(time_stamp, &result)) {
- predicted_accumulated_delta_ = result.pos;
+ predicted_accumulated_delta = result.pos;
gesture_event->SetTimeStamp(time_stamp);
}
@@ -121,7 +135,7 @@ void ScrollPredictor::ResampleEvent(base::TimeTicks time_stamp,
// So we set the new delta to 0 when predicted delta is in different direction
// to the original event.
gfx::Vector2dF new_delta =
- predicted_accumulated_delta_ - last_accumulated_delta_;
+ predicted_accumulated_delta - last_accumulated_delta_;
gesture_event->data.scroll_update.delta_x =
(new_delta.x() * gesture_event->data.scroll_update.delta_x < 0)
? 0
@@ -135,4 +149,47 @@ void ScrollPredictor::ResampleEvent(base::TimeTicks time_stamp,
gesture_event->data.scroll_update.delta_y);
}
+void ScrollPredictor::ComputeAccuracy(const WebScopedInputEvent& event) {
+ const WebGestureEvent& gesture_event =
+ static_cast<const WebGestureEvent&>(*event);
+
+ base::TimeDelta time_delta = event->TimeStamp() - last_event_timestamp_;
+ std::string suffix;
+ if (time_delta < base::TimeDelta::FromMilliseconds(10))
+ suffix = "Short";
+ else if (time_delta < base::TimeDelta::FromMilliseconds(20))
+ suffix = "Middle";
+ else if (time_delta < base::TimeDelta::FromMilliseconds(35))
+ suffix = "Long";
+ else
+ return;
+
+ InputPredictor::InputData predict_result;
+ temporary_accumulated_delta_.Offset(gesture_event.data.scroll_update.delta_x,
+ gesture_event.data.scroll_update.delta_y);
+ if (predictor_->HasPrediction() &&
+ predictor_->GeneratePrediction(event->TimeStamp(), &predict_result)) {
+ float distance =
+ (predict_result.pos - gfx::PointF(temporary_accumulated_delta_))
+ .Length();
+ base::UmaHistogramCounts1000(
+ "Event.InputEventPrediction.Accuracy.Scroll." + suffix,
+ static_cast<int>(distance));
+
+ // If the distance from predicted position to actual position is in same
+ // direction as the delta_y, the result is under predicted, otherwise over
+ // predict.
+ float dist_y = temporary_accumulated_delta_.y() - predict_result.pos.y();
+ if (gesture_event.data.scroll_update.delta_y * dist_y < 0) {
+ base::UmaHistogramCounts1000(
+ "Event.InputEventPrediction.Accuracy.Scroll.OverPredict." + suffix,
+ static_cast<int>(std::abs(dist_y)));
+ } else {
+ base::UmaHistogramCounts1000(
+ "Event.InputEventPrediction.Accuracy.Scroll.UnderPredict." + suffix,
+ static_cast<int>(std::abs(dist_y)));
+ }
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/events/blink/scroll_predictor.h b/chromium/ui/events/blink/scroll_predictor.h
index 6c8e6856316..e9d7d2bd770 100644
--- a/chromium/ui/events/blink/scroll_predictor.h
+++ b/chromium/ui/events/blink/scroll_predictor.h
@@ -23,26 +23,31 @@ class ScrollPredictorTest;
// timestamp and delta_x/y to the VSync time.
class ScrollPredictor {
public:
- ScrollPredictor();
+ // Select the predictor type from field trial params and initialize the
+ // predictor. enable_resampling is true when kResamplingScrollEvents is
+ // enabled.
+ explicit ScrollPredictor(bool enable_resampling);
~ScrollPredictor();
+ // Reset the predictors on each GSB.
void ResetOnGestureScrollBegin(const blink::WebGestureEvent& event);
+
// Resampling GestureScrollUpdate events. Updates the prediction with events
// in original events list, and apply the prediction to the aggregated GSU
- // event.
+ // event if enable_resampling is true.
void ResampleScrollEvents(
const EventWithCallback::OriginalEventList& original_events,
base::TimeTicks frame_time,
blink::WebInputEvent* event);
- // Reset predictor and clear accumulated delta. This should be called on
- // GestureScrollBegin.
- void Reset();
-
private:
friend class test::InputHandlerProxyEventQueueTest;
friend class test::ScrollPredictorTest;
+ // Reset predictor and clear accumulated delta. This should be called on
+ // GestureScrollBegin.
+ void Reset();
+
// Update the prediction with GestureScrollUpdate deltaX and deltaY
void UpdatePrediction(const WebScopedInputEvent& event,
base::TimeTicks frame_time);
@@ -50,6 +55,10 @@ class ScrollPredictor {
// Apply resampled deltaX/deltaY to gesture events
void ResampleEvent(base::TimeTicks frame_time, blink::WebInputEvent* event);
+ // Reports prediction accuracy UMA histogram. Calculates position in current
+ // event time and compute the distance between real event and predicted event.
+ void ComputeAccuracy(const WebScopedInputEvent& event);
+
std::unique_ptr<InputPredictor> predictor_;
// Total scroll delta, used for prediction. Reset when GestureScrollBegin
@@ -58,8 +67,20 @@ class ScrollPredictor {
// the aggregated event.
gfx::PointF last_accumulated_delta_;
+ // Whether resampling is enabled by feature flag.
+ bool enable_resampling_ = false;
+
+ // Whether current scroll event should be resampled. This only valid when
+ // enable_resampling_ is true.
bool should_resample_scroll_events_ = false;
+ // Records the timestamp for last event added to predictor. Use for
+ // reporting the accuracy metrics.
+ base::TimeTicks last_event_timestamp_;
+ // Total scroll data, similar as current_accumulated_delta_, used for
+ // calculating accuracy.
+ gfx::PointF temporary_accumulated_delta_;
+
DISALLOW_COPY_AND_ASSIGN(ScrollPredictor);
};
diff --git a/chromium/ui/events/blink/scroll_predictor_unittest.cc b/chromium/ui/events/blink/scroll_predictor_unittest.cc
index fda70c82593..486830a1c2c 100644
--- a/chromium/ui/events/blink/scroll_predictor_unittest.cc
+++ b/chromium/ui/events/blink/scroll_predictor_unittest.cc
@@ -6,9 +6,14 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/metrics/field_trial_param_associator.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/blink/blink_features.h"
#include "ui/events/blink/prediction/empty_predictor.h"
+#include "ui/events/blink/prediction/kalman_predictor.h"
#include "ui/events/blink/prediction/least_squares_predictor.h"
using blink::WebInputEvent;
@@ -28,7 +33,8 @@ class ScrollPredictorTest : public testing::Test {
void SetUp() override {
original_events_.clear();
- scroll_predictor_ = std::make_unique<ScrollPredictor>();
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(true /* enable_resampling */);
scroll_predictor_->predictor_ = std::make_unique<EmptyPredictor>();
}
@@ -101,10 +107,43 @@ class ScrollPredictorTest : public testing::Test {
return scroll_predictor_->should_resample_scroll_events_;
}
+ void ConfigureFieldTrial(const base::Feature& feature,
+ const std::string& predictor_type) {
+ const std::string kTrialName = "TestTrial";
+ const std::string kGroupName = "TestGroup";
+
+ field_trial_list_.reset();
+ field_trial_list_.reset(new base::FieldTrialList(nullptr));
+ scoped_refptr<base::FieldTrial> trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+ base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+
+ std::map<std::string, std::string> params;
+ params["predictor"] = predictor_type;
+ base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
+ kTrialName, kGroupName, params);
+
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(
+ feature.name, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
+ base::FeatureList::ClearInstanceForTesting();
+ scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+
+ EXPECT_EQ(params["predictor"],
+ GetFieldTrialParamValueByFeature(feature, "predictor"));
+ }
+
+ void VerifyPredictorType(const std::string& expected_type) {
+ EXPECT_EQ(expected_type, scroll_predictor_->predictor_->GetName());
+ }
+
protected:
EventWithCallback::OriginalEventList original_events_;
std::unique_ptr<ScrollPredictor> scroll_predictor_;
+ std::unique_ptr<base::FieldTrialList> field_trial_list_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+
DISALLOW_COPY_AND_ASSIGN(ScrollPredictorTest);
};
@@ -348,5 +387,51 @@ TEST_F(ScrollPredictorTest, ScrollPredictorNotChangeScrollDirection) {
EXPECT_NEAR(36, GetLastAccumulatedDelta().y(), kEpsilon);
}
+TEST_F(ScrollPredictorTest, ScrollPredictorTypeSelection) {
+ // Empty Predictor when both kResamplingScrollEvents and
+ // kScrollPredictorTypeChoice are disabled.
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(true /* enable_resampling */);
+ VerifyPredictorType("Empty");
+
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(false /* enable_resampling */);
+ VerifyPredictorType("Empty");
+
+ // When resampling is enabled, predictor type is set from
+ // kResamplingScrollEvents.
+ ConfigureFieldTrial(features::kResamplingScrollEvents, "empty");
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(true /* enable_resampling */);
+ VerifyPredictorType("Empty");
+
+ ConfigureFieldTrial(features::kResamplingScrollEvents, "lsq");
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(true /* enable_resampling */);
+ VerifyPredictorType("LSQ");
+
+ ConfigureFieldTrial(features::kResamplingScrollEvents, "kalman");
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(true /* enable_resampling */);
+ VerifyPredictorType("Kalman");
+
+ // When resampling is disabled, predictor type is set from
+ // kScrollPredictorTypeChoice.
+ ConfigureFieldTrial(features::kScrollPredictorTypeChoice, "empty");
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(false /* enable_resampling */);
+ VerifyPredictorType("Empty");
+
+ ConfigureFieldTrial(features::kScrollPredictorTypeChoice, "lsq");
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(false /* enable_resampling */);
+ VerifyPredictorType("LSQ");
+
+ ConfigureFieldTrial(features::kScrollPredictorTypeChoice, "kalman");
+ scroll_predictor_ =
+ std::make_unique<ScrollPredictor>(false /* enable_resampling */);
+ VerifyPredictorType("Kalman");
+}
+
} // namespace test
} // namespace ui
diff --git a/chromium/ui/events/blink/web_input_event_builders_win.cc b/chromium/ui/events/blink/web_input_event_builders_win.cc
index ffa4a066451..33bc7d3c448 100644
--- a/chromium/ui/events/blink/web_input_event_builders_win.cc
+++ b/chromium/ui/events/blink/web_input_event_builders_win.cc
@@ -4,8 +4,7 @@
#include "ui/events/blink/web_input_event_builders_win.h"
-#include <windowsx.h>
-
+#include "base/win/windowsx_shim.h"
#include "ui/display/win/screen_win.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event_utils.h"
diff --git a/chromium/ui/events/devices/device_util_linux.cc b/chromium/ui/events/devices/device_util_linux.cc
index d81d3a813d9..eeecc316391 100644
--- a/chromium/ui/events/devices/device_util_linux.cc
+++ b/chromium/ui/events/devices/device_util_linux.cc
@@ -9,7 +9,6 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
-#include "base/threading/thread_restrictions.h"
namespace ui {
@@ -19,11 +18,9 @@ base::FilePath GetInputPathInSys(const base::FilePath& path) {
}
InputDeviceType GetInputDeviceTypeFromPath(const base::FilePath& path) {
- base::AssertBlockingAllowed();
std::string event_node = path.BaseName().value();
if (event_node.empty() ||
- !base::StartsWith(event_node, "event",
- base::CompareCase::INSENSITIVE_ASCII))
+ !base::StartsWith(event_node, "event", base::CompareCase::SENSITIVE))
return InputDeviceType::INPUT_DEVICE_UNKNOWN;
base::FilePath sysfs_path = GetInputPathInSys(path);
diff --git a/chromium/ui/events/devices/input_device_manager.cc b/chromium/ui/events/devices/input_device_manager.cc
index 1f53855e3f6..12c47b9bf93 100644
--- a/chromium/ui/events/devices/input_device_manager.cc
+++ b/chromium/ui/events/devices/input_device_manager.cc
@@ -3,41 +3,35 @@
// found in the LICENSE file.
#include "ui/events/devices/input_device_manager.h"
-#include "base/lazy_instance.h"
-#include "base/threading/thread_local.h"
namespace ui {
namespace {
-// InputDeviceManager singleton is thread-local so that different instances can
-// be used on different threads (eg. UI Service thread vs. browser UI thread).
-base::LazyInstance<base::ThreadLocalPointer<InputDeviceManager>>::Leaky
- lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+InputDeviceManager* g_instance = nullptr;
} // namespace
// static
InputDeviceManager* InputDeviceManager::GetInstance() {
- InputDeviceManager* instance = lazy_tls_ptr.Pointer()->Get();
- DCHECK(instance) << "InputDeviceManager::SetInstance must be called before "
- "getting the instance of InputDeviceManager.";
- return instance;
+ DCHECK(g_instance) << "InputDeviceManager::SetInstance must be called before "
+ "getting the instance of InputDeviceManager.";
+ return g_instance;
}
// static
bool InputDeviceManager::HasInstance() {
- return lazy_tls_ptr.Pointer()->Get() != nullptr;
+ return g_instance;
}
// static
void InputDeviceManager::SetInstance(InputDeviceManager* instance) {
- DCHECK(!lazy_tls_ptr.Pointer()->Get());
- lazy_tls_ptr.Pointer()->Set(instance);
+ DCHECK(!g_instance);
+ g_instance = instance;
}
// static
void InputDeviceManager::ClearInstance() {
- lazy_tls_ptr.Pointer()->Set(nullptr);
+ g_instance = nullptr;
}
} // namespace ui
diff --git a/chromium/ui/events/devices/input_device_manager.h b/chromium/ui/events/devices/input_device_manager.h
index dcbd3167b80..4f72ea67941 100644
--- a/chromium/ui/events/devices/input_device_manager.h
+++ b/chromium/ui/events/devices/input_device_manager.h
@@ -15,13 +15,13 @@
namespace ui {
-// Interface to query available input devices. Holds a thread-local pointer to
-// an implementation that provides this service. The implementation could be
-// DeviceDataManager or something that mirrors the necessary state if
-// DeviceDataManager is in a different process.
+// Interface to query available input devices. The implementation, which is a
+// singleton, could be DeviceDataManager or something that mirrors the necessary
+// state if DeviceDataManager is in a different process.
class EVENTS_DEVICES_EXPORT InputDeviceManager {
public:
- InputDeviceManager() {}
+ InputDeviceManager() = default;
+ virtual ~InputDeviceManager() = default;
static InputDeviceManager* GetInstance();
static bool HasInstance();
diff --git a/chromium/ui/events/devices/x11/device_data_manager_x11.cc b/chromium/ui/events/devices/x11/device_data_manager_x11.cc
index 19648ce1bac..fbf372f14c3 100644
--- a/chromium/ui/events/devices/x11/device_data_manager_x11.cc
+++ b/chromium/ui/events/devices/x11/device_data_manager_x11.cc
@@ -14,7 +14,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "build/build_config.h"
#include "ui/display/display.h"
#include "ui/events/devices/x11/device_list_cache_x11.h"
diff --git a/chromium/ui/events/devices/x11/touch_factory_x11.cc b/chromium/ui/events/devices/x11/touch_factory_x11.cc
index 40c9e65b7d2..f454bcbbb18 100644
--- a/chromium/ui/events/devices/x11/touch_factory_x11.cc
+++ b/chromium/ui/events/devices/x11/touch_factory_x11.cc
@@ -12,7 +12,7 @@
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "build/build_config.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
diff --git a/chromium/ui/events/event.cc b/chromium/ui/events/event.cc
index d2eca3cd64b..2c636ab6b42 100644
--- a/chromium/ui/events/event.cc
+++ b/chromium/ui/events/event.cc
@@ -59,15 +59,8 @@ constexpr int kChangedButtonFlagMask =
SourceEventType EventTypeToLatencySourceEventType(EventType type) {
switch (type) {
case ET_UNKNOWN:
- // SourceEventType for PointerEvents/GestureEvents can be either TOUCH or
- // WHEEL. The proper value is assigned in the constructors.
- case ET_POINTER_DOWN:
- case ET_POINTER_MOVED:
- case ET_POINTER_UP:
- case ET_POINTER_CANCELLED:
- case ET_POINTER_ENTERED:
- case ET_POINTER_EXITED:
- case ET_POINTER_CAPTURE_CHANGED:
+ // SourceEventType for GestureEvents can be either TOUCH or WHEEL. The
+ // proper value is assigned in the constructors.
case ET_GESTURE_SCROLL_BEGIN:
case ET_GESTURE_SCROLL_END:
case ET_GESTURE_SCROLL_UPDATE:
@@ -117,7 +110,6 @@ SourceEventType EventTypeToLatencySourceEventType(EventType type) {
return SourceEventType::TOUCH;
case ET_MOUSEWHEEL:
- case ET_POINTER_WHEEL_CHANGED:
case ET_SCROLL:
return SourceEventType::WHEEL;
@@ -158,11 +150,6 @@ std::unique_ptr<Event> Event::Clone(const Event& event) {
static_cast<const GestureEvent&>(event));
}
- if (event.IsPointerEvent()) {
- return std::make_unique<PointerEvent>(
- static_cast<const PointerEvent&>(event));
- }
-
if (event.IsScrollEvent()) {
return std::make_unique<ScrollEvent>(
static_cast<const ScrollEvent&>(event));
@@ -184,23 +171,6 @@ void Event::SetProperties(const Properties& properties) {
properties_ = std::make_unique<Properties>(properties);
}
-bool Event::IsMousePointerEvent() const {
- return IsPointerEvent() &&
- AsPointerEvent()->pointer_details().pointer_type ==
- EventPointerType::POINTER_TYPE_MOUSE;
-}
-
-bool Event::IsTouchPointerEvent() const {
- return IsPointerEvent() &&
- AsPointerEvent()->pointer_details().pointer_type ==
- EventPointerType::POINTER_TYPE_TOUCH;
-}
-
-bool Event::IsPenPointerEvent() const {
- return IsPointerEvent() && AsPointerEvent()->pointer_details().pointer_type ==
- EventPointerType::POINTER_TYPE_PEN;
-}
-
CancelModeEvent* Event::AsCancelModeEvent() {
CHECK(IsCancelModeEvent());
return static_cast<CancelModeEvent*>(this);
@@ -261,16 +231,6 @@ const MouseWheelEvent* Event::AsMouseWheelEvent() const {
return static_cast<const MouseWheelEvent*>(this);
}
-PointerEvent* Event::AsPointerEvent() {
- CHECK(IsPointerEvent());
- return static_cast<PointerEvent*>(this);
-}
-
-const PointerEvent* Event::AsPointerEvent() const {
- CHECK(IsPointerEvent());
- return static_cast<const PointerEvent*>(this);
-}
-
ScrollEvent* Event::AsScrollEvent() {
CHECK(IsScrollEvent());
return static_cast<ScrollEvent*>(this);
@@ -522,53 +482,6 @@ MouseEvent::MouseEvent(const PlatformEvent& native_event)
SetClickCount(GetRepeatCount(*this));
}
-MouseEvent::MouseEvent(const PointerEvent& pointer_event)
- : LocatedEvent(pointer_event),
- changed_button_flags_(pointer_event.changed_button_flags()),
- pointer_details_(pointer_event.pointer_details()) {
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- DCHECK(pointer_event.IsMousePointerEvent());
- switch (pointer_event.type()) {
- case ET_POINTER_DOWN:
- SetType(ET_MOUSE_PRESSED);
- break;
-
- case ET_POINTER_MOVED:
- if (pointer_event.flags() &
- (EF_LEFT_MOUSE_BUTTON | EF_MIDDLE_MOUSE_BUTTON |
- EF_RIGHT_MOUSE_BUTTON)) {
- SetType(ET_MOUSE_DRAGGED);
- } else {
- SetType(ET_MOUSE_MOVED);
- }
- break;
-
- case ET_POINTER_ENTERED:
- SetType(ET_MOUSE_ENTERED);
- break;
-
- case ET_POINTER_EXITED:
- SetType(ET_MOUSE_EXITED);
- break;
-
- case ET_POINTER_UP:
- SetType(ET_MOUSE_RELEASED);
- break;
-
- case ET_POINTER_WHEEL_CHANGED:
- // Explicitly not setting a type here. MouseWheelEvent should be converted
- // from PointerEvent using its own ctor.
- break;
-
- case ET_POINTER_CAPTURE_CHANGED:
- SetType(ET_MOUSE_CAPTURE_CHANGED);
- break;
-
- default:
- NOTREACHED();
- }
-}
-
MouseEvent::MouseEvent(EventType type,
const gfx::Point& location,
const gfx::Point& root_location,
@@ -723,13 +636,6 @@ MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event)
SetType(ET_MOUSEWHEEL);
}
-MouseWheelEvent::MouseWheelEvent(const PointerEvent& pointer_event)
- : MouseEvent(pointer_event),
- offset_(pointer_event.pointer_details().offset.x(),
- pointer_event.pointer_details().offset.y()) {
- SetType(ET_MOUSEWHEEL);
-}
-
MouseWheelEvent::MouseWheelEvent(const MouseEvent& mouse_event,
int x_offset,
int y_offset)
@@ -791,37 +697,6 @@ TouchEvent::TouchEvent(const PlatformEvent& native_event)
should_remove_native_touch_id_mapping_ = true;
}
-TouchEvent::TouchEvent(const PointerEvent& pointer_event)
- : LocatedEvent(pointer_event),
- unique_event_id_(ui::GetNextTouchEventId()),
- may_cause_scrolling_(false),
- should_remove_native_touch_id_mapping_(false),
- hovering_(false),
- pointer_details_(pointer_event.pointer_details()) {
- DCHECK(pointer_event.IsTouchPointerEvent() ||
- pointer_event.IsPenPointerEvent());
- switch (pointer_event.type()) {
- case ET_POINTER_DOWN:
- SetType(ET_TOUCH_PRESSED);
- break;
-
- case ET_POINTER_MOVED:
- SetType(ET_TOUCH_MOVED);
- break;
-
- case ET_POINTER_UP:
- SetType(ET_TOUCH_RELEASED);
- break;
-
- case ET_POINTER_CANCELLED:
- SetType(ET_TOUCH_CANCELLED);
- break;
-
- default:
- NOTREACHED();
- }
-}
-
TouchEvent::TouchEvent(EventType type,
const gfx::Point& location,
base::TimeTicks time_stamp,
@@ -899,144 +774,6 @@ float TouchEvent::ComputeRotationAngle() const {
}
////////////////////////////////////////////////////////////////////////////////
-// PointerEvent
-
-bool PointerEvent::CanConvertFrom(const Event& event) {
- switch (event.type()) {
- case ET_MOUSE_PRESSED:
- case ET_MOUSE_DRAGGED:
- case ET_MOUSE_MOVED:
- case ET_MOUSE_ENTERED:
- case ET_MOUSE_EXITED:
- case ET_MOUSE_RELEASED:
- case ET_MOUSEWHEEL:
- case ET_MOUSE_CAPTURE_CHANGED:
- case ET_TOUCH_PRESSED:
- case ET_TOUCH_MOVED:
- case ET_TOUCH_RELEASED:
- case ET_TOUCH_CANCELLED:
- return true;
- default:
- return false;
- }
-}
-
-PointerEvent::PointerEvent(const PointerEvent& pointer_event)
- : LocatedEvent(pointer_event),
- changed_button_flags_(pointer_event.changed_button_flags()),
- details_(pointer_event.pointer_details()) {
- if (details_.pointer_type == EventPointerType::POINTER_TYPE_TOUCH)
- latency()->set_source_event_type(ui::SourceEventType::TOUCH);
- else if (pointer_event.type() == ET_POINTER_WHEEL_CHANGED)
- latency()->set_source_event_type(ui::SourceEventType::WHEEL);
- else if (details_.pointer_type == EventPointerType::POINTER_TYPE_MOUSE)
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- else
- latency()->set_source_event_type(ui::SourceEventType::OTHER);
-}
-
-PointerEvent::PointerEvent(const MouseEvent& mouse_event)
- : LocatedEvent(mouse_event),
- changed_button_flags_(mouse_event.changed_button_flags()),
- details_(mouse_event.pointer_details()) {
- DCHECK(CanConvertFrom(mouse_event));
- switch (mouse_event.type()) {
- case ET_MOUSE_PRESSED:
- SetType(ET_POINTER_DOWN);
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- break;
-
- case ET_MOUSE_DRAGGED:
- case ET_MOUSE_MOVED:
- SetType(ET_POINTER_MOVED);
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- break;
-
- case ET_MOUSE_ENTERED:
- SetType(ET_POINTER_ENTERED);
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- break;
-
- case ET_MOUSE_EXITED:
- SetType(ET_POINTER_EXITED);
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- break;
-
- case ET_MOUSE_RELEASED:
- SetType(ET_POINTER_UP);
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- break;
-
- case ET_MOUSEWHEEL:
- SetType(ET_POINTER_WHEEL_CHANGED);
- details_ = PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- mouse_event.AsMouseWheelEvent()->offset(),
- mouse_event.pointer_details().id);
- latency()->set_source_event_type(ui::SourceEventType::WHEEL);
- break;
-
- case ET_MOUSE_CAPTURE_CHANGED:
- SetType(ET_POINTER_CAPTURE_CHANGED);
- break;
-
- default:
- NOTREACHED();
- }
-}
-
-PointerEvent::PointerEvent(const TouchEvent& touch_event)
- : LocatedEvent(touch_event),
- changed_button_flags_(0),
- details_(touch_event.pointer_details()) {
- DCHECK(CanConvertFrom(touch_event));
- switch (touch_event.type()) {
- case ET_TOUCH_PRESSED:
- SetType(ET_POINTER_DOWN);
- break;
-
- case ET_TOUCH_MOVED:
- SetType(ET_POINTER_MOVED);
- break;
-
- case ET_TOUCH_RELEASED:
- SetType(ET_POINTER_UP);
- break;
-
- case ET_TOUCH_CANCELLED:
- SetType(ET_POINTER_CANCELLED);
- break;
-
- default:
- NOTREACHED();
- }
- latency()->set_source_event_type(ui::SourceEventType::TOUCH);
-}
-
-PointerEvent::PointerEvent(EventType type,
- const gfx::Point& location,
- const gfx::Point& root_location,
- int flags,
- int changed_button_flags,
- const PointerDetails& pointer_details,
- base::TimeTicks time_stamp)
- : LocatedEvent(type,
- gfx::PointF(location),
- gfx::PointF(root_location),
- time_stamp,
- flags),
- changed_button_flags_(changed_button_flags),
- details_(pointer_details) {
- if (details_.pointer_type == EventPointerType::POINTER_TYPE_TOUCH)
- latency()->set_source_event_type(ui::SourceEventType::TOUCH);
- else if (type == ET_POINTER_WHEEL_CHANGED)
- latency()->set_source_event_type(ui::SourceEventType::WHEEL);
- else if (details_.pointer_type == EventPointerType::POINTER_TYPE_MOUSE)
- latency()->set_source_event_type(ui::SourceEventType::MOUSE);
- else
- latency()->set_source_event_type(ui::SourceEventType::OTHER);
-}
-
-////////////////////////////////////////////////////////////////////////////////
// KeyEvent
// static
@@ -1087,10 +824,9 @@ bool KeyEvent::IsRepeated(const KeyEvent& event) {
// Bit 30 of lParam represents the "previous key state". If set, the key
// was already down, therefore this is an auto-repeat.
is_repeat = (event.native_event().lParam & 0x40000000) != 0;
- } else
+ }
#endif
- {
- // Note that this is only reach for non-native events under Windows.
+ if (!is_repeat) {
if (event.key_code() == (*last_key_event)->key_code() &&
event.flags() == ((*last_key_event)->flags() & ~ui::EF_IS_REPEAT) &&
(event.time_stamp() - (*last_key_event)->time_stamp())
@@ -1333,6 +1069,12 @@ void KeyEvent::NormalizeFlags() {
set_flags(flags() & ~mask);
}
+base::OnceCallback<void(bool)> KeyEvent::WillHandleAsync() {
+ if (cancelable())
+ SetHandled();
+ return std::move(async_callback_);
+}
+
KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
return NonLocatedToLocatedKeyboardCode(key_code_, code_);
}
diff --git a/chromium/ui/events/event.h b/chromium/ui/events/event.h
index b9b4c72be8b..1ba9510dd41 100644
--- a/chromium/ui/events/event.h
+++ b/chromium/ui/events/event.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/gtest_prod_util.h"
@@ -40,7 +41,6 @@ class KeyEvent;
class LocatedEvent;
class MouseEvent;
class MouseWheelEvent;
-class PointerEvent;
class ScrollEvent;
class TouchEvent;
@@ -70,9 +70,9 @@ class EVENTS_EXPORT Event {
void set_result(int result) {
event_->result_ = static_cast<EventResult>(result);
}
+ void set_time_stamp(base::TimeTicks time) { event_->time_stamp_ = time; }
private:
- DispatcherApi();
Event* event_;
DISALLOW_COPY_AND_ASSIGN(DispatcherApi);
@@ -155,20 +155,6 @@ class EVENTS_EXPORT Event {
type_ == ET_TOUCH_CANCELLED;
}
- bool IsPointerEvent() const {
- return type_ == ET_POINTER_DOWN || type_ == ET_POINTER_MOVED ||
- type_ == ET_POINTER_UP || type_ == ET_POINTER_CANCELLED ||
- type_ == ET_POINTER_ENTERED || type_ == ET_POINTER_EXITED ||
- type_ == ET_POINTER_WHEEL_CHANGED ||
- type_ == ET_POINTER_CAPTURE_CHANGED;
- }
-
- // Convenience methods to check pointer type of |this|. Returns false if
- // |this| is not a PointerEvent.
- bool IsMousePointerEvent() const;
- bool IsTouchPointerEvent() const;
- bool IsPenPointerEvent() const;
-
bool IsGestureEvent() const {
switch (type_) {
case ET_GESTURE_SCROLL_BEGIN:
@@ -251,7 +237,7 @@ class EVENTS_EXPORT Event {
bool IsLocatedEvent() const {
return IsMouseEvent() || IsScrollEvent() || IsTouchEvent() ||
- IsGestureEvent() || IsPointerEvent();
+ IsGestureEvent();
}
// Convenience methods to cast |this| to a CancelModeEvent.
@@ -286,11 +272,6 @@ class EVENTS_EXPORT Event {
MouseWheelEvent* AsMouseWheelEvent();
const MouseWheelEvent* AsMouseWheelEvent() const;
- // Convenience methods to cast |this| to a PointerEvent. IsPointerEvent()
- // must be true as a precondition to calling these methods.
- PointerEvent* AsPointerEvent();
- const PointerEvent* AsPointerEvent() const;
-
// Convenience methods to cast |this| to a ScrollEvent. IsScrollEvent()
// must be true as a precondition to calling these methods.
ScrollEvent* AsScrollEvent();
@@ -526,12 +507,6 @@ class EVENTS_EXPORT MouseEvent : public LocatedEvent {
// void*, see PlatformEvent.
explicit MouseEvent(const PlatformEvent& native_event);
- // |pointer_event.IsMousePointerEvent()| must be true.
- // Note: If |pointer_event| is a mouse wheel pointer event, use the
- // MouseWheelEvent version of this function to convert to a MouseWheelEvent
- // instead.
- explicit MouseEvent(const PointerEvent& pointer_event);
-
// Create a new MouseEvent based on the provided model.
// Uses the provided |type| and |flags| for the new event.
// If source / target windows are provided, the model location will be
@@ -659,7 +634,6 @@ class EVENTS_EXPORT MouseWheelEvent : public MouseEvent {
explicit MouseWheelEvent(const PlatformEvent& native_event);
explicit MouseWheelEvent(const ScrollEvent& scroll_event);
- explicit MouseWheelEvent(const PointerEvent& pointer_event);
MouseWheelEvent(const MouseEvent& mouse_event, int x_offset, int y_offset);
MouseWheelEvent(const MouseWheelEvent& copy);
~MouseWheelEvent() override;
@@ -697,9 +671,6 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
public:
explicit TouchEvent(const PlatformEvent& native_event);
- // |pointer_event.IsTouchPointerEvent()| must be true.
- explicit TouchEvent(const PointerEvent& pointer_event);
-
// Create a new TouchEvent which is identical to the provided model.
// If source / target windows are provided, the model location will be
// converted from |source| coordinate system to |target| coordinate system.
@@ -783,33 +754,6 @@ class EVENTS_EXPORT TouchEvent : public LocatedEvent {
PointerDetails pointer_details_;
};
-class EVENTS_EXPORT PointerEvent : public LocatedEvent {
- public:
- // Returns true if a PointerEvent can be constructed from |event|. Currently,
- // only mouse and touch events can be converted to pointer events.
- static bool CanConvertFrom(const Event& event);
-
- PointerEvent(const PointerEvent& pointer_event);
- explicit PointerEvent(const MouseEvent& mouse_event);
- explicit PointerEvent(const TouchEvent& touch_event);
-
- PointerEvent(EventType type,
- const gfx::Point& location,
- const gfx::Point& root_location,
- int flags,
- int changed_button_flags,
- const PointerDetails& pointer_details,
- base::TimeTicks time_stamp);
-
- int changed_button_flags() const { return changed_button_flags_; }
- void set_changed_button_flags(int flags) { changed_button_flags_ = flags; }
- const PointerDetails& pointer_details() const { return details_; }
-
- private:
- int changed_button_flags_;
- PointerDetails details_;
-};
-
// A KeyEvent is really two distinct classes, melded together due to the
// DOM legacy of Windows key events: a keystroke event (is_char_ == false),
// or a character event (is_char_ == true).
@@ -850,6 +794,20 @@ class EVENTS_EXPORT PointerEvent : public LocatedEvent {
//
class EVENTS_EXPORT KeyEvent : public Event {
public:
+ class KeyDispatcherApi {
+ public:
+ explicit KeyDispatcherApi(KeyEvent* event) : event_(event) {}
+
+ void set_async_callback(base::OnceCallback<void(bool)> callback) {
+ event_->async_callback_ = std::move(callback);
+ }
+
+ private:
+ KeyEvent* event_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyDispatcherApi);
+ };
+
// Create a KeyEvent from a NativeEvent. For Windows this native event can
// be either a keystroke message (WM_KEYUP/WM_KEYDOWN) or a character message
// (WM_CHAR). Other systems have only keystroke events.
@@ -957,6 +915,12 @@ class EVENTS_EXPORT KeyEvent : public Event {
// (Native X11 event flags describe the state before the event.)
void NormalizeFlags();
+ // Called if the event is handled asynchronously. If the returned callback is
+ // non-null, it *must* be run once async handling is complete. The argument
+ // to the callback indicates if the event was handled or not.
+ base::OnceCallback<void(bool)> WillHandleAsync();
+ bool HasAsyncCallback() const { return !async_callback_.is_null(); }
+
protected:
friend class KeyEventTestApi;
@@ -995,6 +959,8 @@ class EVENTS_EXPORT KeyEvent : public Event {
// it may be set only if and when GetCharacter() or GetDomKey() is called.
mutable DomKey key_ = DomKey::NONE;
+ base::OnceCallback<void(bool)> async_callback_;
+
static KeyEvent* last_key_event_;
#if defined(USE_X11)
static KeyEvent* last_ibus_key_event_;
diff --git a/chromium/ui/events/event_constants.h b/chromium/ui/events/event_constants.h
index ee1a4ce24f0..3d81edebdf5 100644
--- a/chromium/ui/events/event_constants.h
+++ b/chromium/ui/events/event_constants.h
@@ -31,16 +31,6 @@ enum EventType {
ET_TOUCH_CANCELLED,
ET_DROP_TARGET_EVENT,
- // PointerEvent types
- ET_POINTER_DOWN,
- ET_POINTER_MOVED,
- ET_POINTER_UP,
- ET_POINTER_CANCELLED,
- ET_POINTER_ENTERED,
- ET_POINTER_EXITED,
- ET_POINTER_WHEEL_CHANGED,
- ET_POINTER_CAPTURE_CHANGED,
-
// GestureEvent types
ET_GESTURE_SCROLL_BEGIN,
ET_GESTURE_TYPE_START = ET_GESTURE_SCROLL_BEGIN,
diff --git a/chromium/ui/events/event_dispatcher.cc b/chromium/ui/events/event_dispatcher.cc
index 8a0c18ecffb..f3b451ef69c 100644
--- a/chromium/ui/events/event_dispatcher.cc
+++ b/chromium/ui/events/event_dispatcher.cc
@@ -100,11 +100,12 @@ EventDispatchDetails EventDispatcherDelegate::DispatchEventToTarget(
// EventDispatcher:
EventDispatcher::EventDispatcher(EventDispatcherDelegate* delegate)
- : delegate_(delegate),
- current_event_(NULL) {
-}
+ : delegate_(delegate) {}
EventDispatcher::~EventDispatcher() {
+ // |handler_list_| must be empty, otherwise this has been added to an
+ // EventHandler that will callback to this when destroyed.
+ CHECK(handler_list_.empty());
}
void EventDispatcher::OnHandlerDestroyed(EventHandler* handler) {
@@ -125,6 +126,8 @@ void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
dispatch_helper.set_phase(EP_PRETARGET);
DispatchEventToEventHandlers(&handler_list_, event);
+ // All pre-target handler should have been removed.
+ CHECK(handler_list_.empty());
if (event->handled())
return;
@@ -144,14 +147,13 @@ void EventDispatcher::ProcessEvent(EventTarget* target, Event* event) {
if (!delegate_ || !delegate_->CanDispatchToTarget(target))
return;
- handler_list_.clear();
target->GetPostTargetHandlers(&handler_list_);
dispatch_helper.set_phase(EP_POSTTARGET);
DispatchEventToEventHandlers(&handler_list_, event);
}
void EventDispatcher::OnDispatcherDelegateDestroyed() {
- delegate_ = NULL;
+ delegate_ = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
@@ -159,23 +161,23 @@ void EventDispatcher::OnDispatcherDelegateDestroyed() {
void EventDispatcher::DispatchEventToEventHandlers(EventHandlerList* list,
Event* event) {
- for (EventHandlerList::const_iterator it = list->begin(),
- end = list->end(); it != end; ++it) {
- (*it)->dispatchers_.push(this);
- }
+ // Let each EventHandler know this is about to make use of it. This way, if
+ // during dispatch the EventHandler is destroyed it is removed from |list|
+ // (OnHandlerDestroyed() is called, which removes from |list|).
+ for (EventHandler* handler : *list)
+ handler->dispatchers_.push(this);
while (!list->empty()) {
EventHandler* handler = (*list->begin());
+
+ // |this| no longer needs to know if |handler| is destroyed.
+ CHECK(handler->dispatchers_.top() == this);
+ handler->dispatchers_.pop();
+ list->erase(list->begin());
+
+ // A null |delegate| means no more events should be dispatched.
if (delegate_ && !event->stopped_propagation())
DispatchEvent(handler, event);
-
- if (!list->empty() && *list->begin() == handler) {
- // The handler has not been destroyed (because if it were, then it would
- // have been removed from the list).
- CHECK(handler->dispatchers_.top() == this);
- handler->dispatchers_.pop();
- list->erase(list->begin());
- }
}
}
diff --git a/chromium/ui/events/event_dispatcher.h b/chromium/ui/events/event_dispatcher.h
index 94da89f83b6..bc9cd5b8a9c 100644
--- a/chromium/ui/events/event_dispatcher.h
+++ b/chromium/ui/events/event_dispatcher.h
@@ -95,7 +95,7 @@ class EVENTS_EXPORT EventDispatcher {
EventDispatcherDelegate* delegate_;
- Event* current_event_;
+ Event* current_event_ = nullptr;
EventHandlerList handler_list_;
diff --git a/chromium/ui/events/event_dispatcher_unittest.cc b/chromium/ui/events/event_dispatcher_unittest.cc
index 8443dda83e7..f3d080f1179 100644
--- a/chromium/ui/events/event_dispatcher_unittest.cc
+++ b/chromium/ui/events/event_dispatcher_unittest.cc
@@ -61,15 +61,14 @@ class TestTarget : public EventTarget,
class TestEventHandler : public EventHandler {
public:
- TestEventHandler(int id)
- : id_(id),
- event_result_(ER_UNHANDLED),
- expect_pre_target_(false),
- expect_post_target_(false),
- received_pre_target_(false) {
+ explicit TestEventHandler(int id) : id_(id) {}
+
+ ~TestEventHandler() override {
+ if (pre_target_)
+ pre_target_->RemovePreTargetHandler(this);
}
- ~TestEventHandler() override {}
+ void set_pre_target(EventTarget* pre_target) { pre_target_ = pre_target; }
virtual void ReceivedEvent(Event* event) {
static_cast<TestTarget*>(event->target())->AddHandlerId(id_);
@@ -105,11 +104,12 @@ class TestEventHandler : public EventHandler {
event->SetHandled();
}
- int id_;
- EventResult event_result_;
- bool expect_pre_target_;
- bool expect_post_target_;
- bool received_pre_target_;
+ const int id_;
+ EventResult event_result_ = ER_UNHANDLED;
+ bool expect_pre_target_ = false;
+ bool expect_post_target_ = false;
+ bool received_pre_target_ = false;
+ EventTarget* pre_target_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TestEventHandler);
};
@@ -300,6 +300,12 @@ TEST(EventDispatcherTest, EventDispatchOrder) {
EXPECT_EQ(
std::vector<int>(exp, exp + sizeof(exp) / sizeof(int)),
child.handler_list());
+
+ parent.RemovePreTargetHandler(&h1);
+ parent.RemovePreTargetHandler(&h2);
+
+ child.RemovePreTargetHandler(&h3);
+ child.RemovePreTargetHandler(&h4);
}
// Tests that the event-phases are correct.
@@ -324,6 +330,8 @@ TEST(EventDispatcherTest, EventDispatchPhase) {
EXPECT_EQ(
std::vector<int>(handlers, handlers + sizeof(handlers) / sizeof(int)),
target.handler_list());
+
+ target.RemovePreTargetHandler(&handler);
}
// Tests that if the dispatcher is destroyed in the middle of pre or post-target
@@ -354,6 +362,10 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(5, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&handler);
+ target.RemovePreTargetHandler(&h2);
}
// Test for non-cancelable event.
@@ -379,6 +391,10 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(5, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&handler);
+ target.RemovePreTargetHandler(&h2);
}
// Now test for post-target.
@@ -406,6 +422,10 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(5, target.handler_list()[1]);
+
+ target.RemovePostTargetHandler(&h1);
+ target.RemovePostTargetHandler(&handler);
+ target.RemovePostTargetHandler(&h2);
}
// Test for non-cancelable event.
@@ -431,6 +451,10 @@ TEST(EventDispatcherTest, EventDispatcherDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(5, target.handler_list()[1]);
+
+ target.RemovePostTargetHandler(&h1);
+ target.RemovePostTargetHandler(&handler);
+ target.RemovePostTargetHandler(&h2);
}
}
@@ -473,6 +497,10 @@ TEST(EventDispatcherTest, EventDispatcherInvalidateTarget) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&invalidate_handler);
+ target.RemovePreTargetHandler(&h3);
}
// Tests that if an event-handler gets destroyed during event-dispatch, it does
@@ -487,6 +515,7 @@ TEST(EventDispatcherTest, EventHandlerDestroyedDuringDispatch) {
target.AddPreTargetHandler(&h1);
target.AddPreTargetHandler(&handle_destroyer);
+ h3->set_pre_target(&target);
target.AddPreTargetHandler(h3);
h1.set_expect_pre_target(true);
@@ -504,6 +533,9 @@ TEST(EventDispatcherTest, EventHandlerDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&handle_destroyer);
}
// Test for non-cancelable events.
@@ -517,6 +549,7 @@ TEST(EventDispatcherTest, EventHandlerDestroyedDuringDispatch) {
target.AddPreTargetHandler(&h1);
target.AddPreTargetHandler(&handle_destroyer);
target.AddPreTargetHandler(h3);
+ h3->set_pre_target(&target);
h1.set_expect_pre_target(true);
handle_destroyer.set_expect_pre_target(true);
@@ -529,6 +562,9 @@ TEST(EventDispatcherTest, EventHandlerDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&handle_destroyer);
}
}
@@ -545,6 +581,7 @@ TEST(EventDispatcherTest, EventHandlerAndDispatcherDestroyedDuringDispatch) {
target.AddPreTargetHandler(&h1);
target.AddPreTargetHandler(&destroyer);
target.AddPreTargetHandler(h3);
+ h3->set_pre_target(&target);
h1.set_expect_pre_target(true);
destroyer.set_expect_pre_target(true);
@@ -561,6 +598,9 @@ TEST(EventDispatcherTest, EventHandlerAndDispatcherDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&destroyer);
}
// Test for non-cancelable events.
@@ -574,6 +614,7 @@ TEST(EventDispatcherTest, EventHandlerAndDispatcherDestroyedDuringDispatch) {
target.AddPreTargetHandler(&h1);
target.AddPreTargetHandler(&destroyer);
target.AddPreTargetHandler(h3);
+ h3->set_pre_target(&target);
h1.set_expect_pre_target(true);
destroyer.set_expect_pre_target(true);
@@ -588,6 +629,9 @@ TEST(EventDispatcherTest, EventHandlerAndDispatcherDestroyedDuringDispatch) {
EXPECT_EQ(2U, target.handler_list().size());
EXPECT_EQ(1, target.handler_list()[0]);
EXPECT_EQ(2, target.handler_list()[1]);
+
+ target.RemovePreTargetHandler(&h1);
+ target.RemovePreTargetHandler(&destroyer);
}
}
diff --git a/chromium/ui/events/event_handler.cc b/chromium/ui/events/event_handler.cc
index 179420f376b..f674e88b53f 100644
--- a/chromium/ui/events/event_handler.cc
+++ b/chromium/ui/events/event_handler.cc
@@ -9,6 +9,9 @@
namespace ui {
+// static
+bool EventHandler::check_targets_ = true;
+
EventHandler::EventHandler() {
}
@@ -18,6 +21,9 @@ EventHandler::~EventHandler() {
dispatchers_.pop();
dispatcher->OnHandlerDestroyed(this);
}
+
+ // Should have been removed from all pre-target handlers.
+ CHECK(!check_targets_ || targets_installed_on_.empty());
}
void EventHandler::OnEvent(Event* event) {
diff --git a/chromium/ui/events/event_handler.h b/chromium/ui/events/event_handler.h
index 73c700fb06f..60a50755b24 100644
--- a/chromium/ui/events/event_handler.h
+++ b/chromium/ui/events/event_handler.h
@@ -17,6 +17,7 @@ namespace ui {
class CancelModeEvent;
class Event;
class EventDispatcher;
+class EventTarget;
class GestureEvent;
class KeyEvent;
class MouseEvent;
@@ -30,6 +31,11 @@ class EVENTS_EXPORT EventHandler {
EventHandler();
virtual ~EventHandler();
+ // Disables a CHECK() that this has been removed from all pre-target
+ // handlers in the destructor.
+ // TODO(sky): remove, used to track https://crbug.com/867035.
+ static void DisableCheckTargets() { check_targets_ = false; }
+
// This is called for all events. The default implementation routes the event
// to one of the event-specific callbacks (OnKeyEvent, OnMouseEvent etc.). If
// this is overridden, then normally, the override should chain into the
@@ -50,11 +56,20 @@ class EVENTS_EXPORT EventHandler {
private:
friend class EventDispatcher;
+ friend class EventTarget;
// EventDispatcher pushes itself on the top of this stack while dispatching
// events to this then pops itself off when done.
base::stack<EventDispatcher*> dispatchers_;
+ // Set of EventTargets |this| has been installed as a pre-target handler on.
+ // This is a vector as AddPreTargetHandler() may be called multiple times for
+ // the same EventTarget.
+ // TODO(sky): remove, used to track https://crbug.com/867035.
+ std::vector<EventTarget*> targets_installed_on_;
+
+ static bool check_targets_;
+
DISALLOW_COPY_AND_ASSIGN(EventHandler);
};
diff --git a/chromium/ui/events/event_observer.h b/chromium/ui/events/event_observer.h
new file mode 100644
index 00000000000..e5381dea8b8
--- /dev/null
+++ b/chromium/ui/events/event_observer.h
@@ -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.
+
+#ifndef UI_EVENTS_EVENT_OBSERVER_H_
+#define UI_EVENTS_EVENT_OBSERVER_H_
+
+#include "base/macros.h"
+#include "ui/events/events_export.h"
+
+namespace ui {
+
+class Event;
+
+// EventObservers are notified of events but are unable to modify the events or
+// mark them as handled before they are dispatched to EventHandlers.
+//
+// Window service clients may use this interface for observation of events that
+// target the window manager or other clients. Clients should limit the types
+// and duration of observation, as there is a system-wide perf/battery penalty,
+// especially for frequently occurring events, like mouse moves. Events with
+// targets outside of the client's scope will have a null target.
+class EVENTS_EXPORT EventObserver {
+ public:
+ // Called for all events matching the requested event types.
+ // The root location of located events is always in screen coordinates.
+ virtual void OnEvent(const Event& event) = 0;
+
+ protected:
+ virtual ~EventObserver() {}
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_EVENT_OBSERVER_H_
diff --git a/chromium/ui/events/event_processor_unittest.cc b/chromium/ui/events/event_processor_unittest.cc
index 0a088a52e37..1c51a24e662 100644
--- a/chromium/ui/events/event_processor_unittest.cc
+++ b/chromium/ui/events/event_processor_unittest.cc
@@ -405,6 +405,10 @@ TEST_F(EventProcessorTest, HandlerSequence) {
"PostR", "PreR", "PreC", "C", "PostC", "PostR", "PreR", "R", "PostR" };
EXPECT_EQ(std::vector<std::string>(
expected, expected + arraysize(expected)), recorder);
+
+ root()->RemovePreTargetHandler(&pre_root);
+ child_r->RemovePreTargetHandler(&pre_child);
+ grandchild_r->RemovePreTargetHandler(&pre_grandchild);
}
TEST(EventProcessorCrashTest, Basic) {
diff --git a/chromium/ui/events/event_target.cc b/chromium/ui/events/event_target.cc
index e72b72cc924..11852779159 100644
--- a/chromium/ui/events/event_target.cc
+++ b/chromium/ui/events/event_target.cc
@@ -31,17 +31,26 @@ gfx::Point EventTarget::GetScreenLocation(const ui::LocatedEvent& event) const {
void EventTarget::AddPreTargetHandler(EventHandler* handler,
Priority priority) {
- DCHECK(handler);
- PrioritizedHandler prioritized = PrioritizedHandler();
+ CHECK(handler);
+ PrioritizedHandler prioritized;
prioritized.handler = handler;
prioritized.priority = priority;
if (priority == Priority::kDefault)
pre_target_list_.push_back(prioritized);
else
pre_target_list_.insert(pre_target_list_.begin(), prioritized);
+ handler->targets_installed_on_.push_back(this);
}
void EventTarget::RemovePreTargetHandler(EventHandler* handler) {
+ CHECK(handler);
+ // Only erase a single one, which matches the removal code right after this.
+ auto installed_on_iter =
+ std::find(handler->targets_installed_on_.begin(),
+ handler->targets_installed_on_.end(), this);
+ if (installed_on_iter != handler->targets_installed_on_.end())
+ handler->targets_installed_on_.erase(installed_on_iter);
+
EventHandlerPriorityList::iterator it, end;
for (it = pre_target_list_.begin(), end = pre_target_list_.end(); it != end;
++it) {
@@ -97,11 +106,8 @@ void EventTarget::GetPreTargetHandlers(EventHandlerList* list) {
void EventTarget::GetPostTargetHandlers(EventHandlerList* list) {
EventTarget* target = this;
while (target) {
- for (auto it = target->post_target_list_.begin(),
- end = target->post_target_list_.end();
- it != end; ++it) {
- list->push_back(*it);
- }
+ list->insert(list->end(), target->post_target_list_.begin(),
+ target->post_target_list_.end());
target = target->GetParentTarget();
}
}
diff --git a/chromium/ui/events/event_target_unittest.cc b/chromium/ui/events/event_target_unittest.cc
index 200c2db76f0..33af3aed42f 100644
--- a/chromium/ui/events/event_target_unittest.cc
+++ b/chromium/ui/events/event_target_unittest.cc
@@ -60,6 +60,9 @@ TEST(EventTargetTest, HandlerOrdering) {
EXPECT_EQ(list[0], &a11y_handler);
EXPECT_EQ(list[1], &system_handler);
EXPECT_EQ(list[2], &default_handler);
+ target.RemovePreTargetHandler(&default_handler);
+ target.RemovePreTargetHandler(&system_handler);
+ target.RemovePreTargetHandler(&a11y_handler);
}
TEST(EventTargetTest, HandlerOrderingComplex) {
@@ -100,6 +103,14 @@ TEST(EventTargetTest, HandlerOrderingComplex) {
EXPECT_EQ(list[4], &system_handler_3);
EXPECT_EQ(list[5], &default_handler_1);
EXPECT_EQ(list[6], &default_handler_2);
+
+ target.RemovePreTargetHandler(&system_handler_3);
+ target.RemovePreTargetHandler(&default_handler_1);
+ target.RemovePreTargetHandler(&system_handler_2);
+ target.RemovePreTargetHandler(&a11y_handler_2);
+ target.RemovePreTargetHandler(&system_handler_1);
+ target.RemovePreTargetHandler(&default_handler_2);
+ target.RemovePreTargetHandler(&a11y_handler_1);
}
TEST(EventTargetTest, HandlerOrderingAcrossEventTargets) {
@@ -138,6 +149,7 @@ TEST(EventTargetTest, HandlerOrderingAcrossEventTargets) {
// Connect the parent and child in a EventTargetTestAPI.
EventTargetTestApi test_api(child.get());
+ test::TestEventTarget* child_ptr = child.get();
parent.AddChild(std::move(child));
EventHandlerList list;
@@ -159,6 +171,18 @@ TEST(EventTargetTest, HandlerOrderingAcrossEventTargets) {
EXPECT_EQ(list[6], &default_handler_1);
EXPECT_EQ(list[7], &default_handler_2);
EXPECT_EQ(list[8], &default_handler_3);
+
+ parent.RemovePreTargetHandler(&default_handler_1);
+ parent.RemovePreTargetHandler(&system_handler_2);
+ parent.RemovePreTargetHandler(&a11y_handler_2);
+
+ child_ptr->RemovePreTargetHandler(&default_handler_3);
+ child_ptr->RemovePreTargetHandler(&a11y_handler_3);
+ child_ptr->RemovePreTargetHandler(&system_handler_3);
+
+ parent.RemovePreTargetHandler(&system_handler_1);
+ parent.RemovePreTargetHandler(&default_handler_2);
+ parent.RemovePreTargetHandler(&a11y_handler_1);
}
} // namespace
diff --git a/chromium/ui/events/event_unittest.cc b/chromium/ui/events/event_unittest.cc
index 4742a797f60..fee9fc13236 100644
--- a/chromium/ui/events/event_unittest.cc
+++ b/chromium/ui/events/event_unittest.cc
@@ -25,7 +25,6 @@
#if defined(USE_X11)
#include "ui/events/test/events_test_utils_x11.h"
-#include "ui/events/x/events_x_utils.h" // nogncheck
#include "ui/gfx/x/x11.h" // nogncheck
#include "ui/gfx/x/x11_types.h" // nogncheck
#endif
@@ -431,15 +430,6 @@ TEST(EventTest, KeyEventCode) {
#if defined(USE_X11)
namespace {
-class MockTimestampServer : public ui::TimestampServer {
- public:
- Time GetCurrentServerTime() override { return base_time_; }
- void SetBaseTime(Time time) { base_time_ = time; }
-
- private:
- Time base_time_ = 0;
-};
-
void SetKeyEventTimestamp(XEvent* event, int64_t time) {
event->xkey.time = time & UINT32_MAX;
}
@@ -450,29 +440,7 @@ void AdvanceKeyEventTimestamp(XEvent* event) {
} // namespace
-class X11EventTest : public testing::Test {
- public:
- X11EventTest() {}
- ~X11EventTest() override {}
-
- void SetUp() override {
- SetTimestampServer(&server_);
- SetUseFixedTimeForXEventTesting(true);
- }
-
- void TearDown() override {
- SetTimestampServer(nullptr);
- SetUseFixedTimeForXEventTesting(false);
- }
-
- protected:
- MockTimestampServer server_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(X11EventTest);
-};
-
-TEST_F(X11EventTest, AutoRepeat) {
+TEST(EventTest, AutoRepeat) {
const uint16_t kNativeCodeA =
ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A);
const uint16_t kNativeCodeB =
@@ -500,7 +468,6 @@ TEST_F(X11EventTest, AutoRepeat) {
int64_t ticks_base =
(base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds() - 5000;
- server_.SetBaseTime(static_cast<Time>(ticks_base));
SetKeyEventTimestamp(native_event_a_pressed, ticks_base);
SetKeyEventTimestamp(native_event_a_pressed_1500, ticks_base + 1500);
SetKeyEventTimestamp(native_event_a_pressed_3000, ticks_base + 3000);
@@ -788,166 +755,6 @@ TEST(EventTest, PointerDetailsCustomTouch) {
EXPECT_EQ(touch_event.pointer_details(), touch_event_copy.pointer_details());
}
-TEST(EventTest, PointerEventCanConvertFrom) {
- const gfx::Point point;
- const base::TimeTicks time;
-
- // Common mouse events can be converted.
- const EventType mouse_allowed[] = {
- ET_MOUSE_PRESSED, ET_MOUSE_DRAGGED, ET_MOUSE_MOVED,
- ET_MOUSE_ENTERED, ET_MOUSE_EXITED, ET_MOUSE_RELEASED,
- ET_MOUSE_CAPTURE_CHANGED,
- };
- for (size_t i = 0; i < arraysize(mouse_allowed); i++) {
- MouseEvent event(mouse_allowed[i], point, point, time, 0, 0);
- EXPECT_TRUE(PointerEvent::CanConvertFrom(event));
- }
- // Mouse wheel events can be converted.
- MouseWheelEvent event(gfx::Vector2d(), point, point, time, 0, 0);
- EXPECT_TRUE(PointerEvent::CanConvertFrom(event));
-
- // Common touch events can be converted.
- const EventType touch_allowed[] = {
- ET_TOUCH_PRESSED,
- ET_TOUCH_MOVED,
- ET_TOUCH_RELEASED,
- ET_TOUCH_CANCELLED
- };
- for (size_t i = 0; i < arraysize(touch_allowed); i++) {
- TouchEvent event(
- touch_allowed[i], point, time,
- PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
- EXPECT_TRUE(PointerEvent::CanConvertFrom(event));
- }
-
- // Non-mouse non-touch events cannot be converted.
- EXPECT_FALSE(
- PointerEvent::CanConvertFrom(
- KeyEvent(ET_KEY_PRESSED, VKEY_SPACE, EF_NONE)));
-}
-
-TEST(EventTest, PointerEventType) {
- const ui::EventType kMouseTypeMap[][2] = {
- {ui::ET_MOUSE_PRESSED, ui::ET_POINTER_DOWN},
- {ui::ET_MOUSE_DRAGGED, ui::ET_POINTER_MOVED},
- {ui::ET_MOUSE_MOVED, ui::ET_POINTER_MOVED},
- {ui::ET_MOUSE_ENTERED, ui::ET_POINTER_ENTERED},
- {ui::ET_MOUSE_EXITED, ui::ET_POINTER_EXITED},
- {ui::ET_MOUSE_RELEASED, ui::ET_POINTER_UP},
- };
- const ui::EventType kTouchTypeMap[][2] = {
- {ui::ET_TOUCH_PRESSED, ui::ET_POINTER_DOWN},
- {ui::ET_TOUCH_MOVED, ui::ET_POINTER_MOVED},
- {ui::ET_TOUCH_RELEASED, ui::ET_POINTER_UP},
- {ui::ET_TOUCH_CANCELLED, ui::ET_POINTER_CANCELLED},
- };
-
- for (size_t i = 0; i < arraysize(kMouseTypeMap); i++) {
- ui::MouseEvent mouse_event(kMouseTypeMap[i][0], gfx::Point(0, 0),
- gfx::Point(0, 0), base::TimeTicks(), 0, 0);
- ui::PointerEvent pointer_event(mouse_event);
- EXPECT_EQ(kMouseTypeMap[i][1], pointer_event.type());
- EXPECT_FALSE(pointer_event.IsMouseEvent());
- EXPECT_FALSE(pointer_event.IsTouchEvent());
- EXPECT_TRUE(pointer_event.IsPointerEvent());
- }
-
- for (size_t i = 0; i < arraysize(kTouchTypeMap); i++) {
- ui::TouchEvent touch_event(
- kTouchTypeMap[i][0], gfx::Point(0, 0), base::TimeTicks(),
- PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
- ui::PointerEvent pointer_event(touch_event);
- EXPECT_EQ(kTouchTypeMap[i][1], pointer_event.type());
- EXPECT_FALSE(pointer_event.IsMouseEvent());
- EXPECT_FALSE(pointer_event.IsTouchEvent());
- EXPECT_TRUE(pointer_event.IsPointerEvent());
- }
-}
-
-TEST(EventTest, PointerEventId) {
- {
- ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(0, 0),
- gfx::Point(0, 0), base::TimeTicks(), 0, 0);
- ui::PointerEvent pointer_event(mouse_event);
- EXPECT_EQ(pointer_event.pointer_details().id,
- ui::MouseEvent::kMousePointerId);
- }
-
- for (int touch_id = 0; touch_id < 8; touch_id++) {
- ui::TouchEvent touch_event(
- ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), base::TimeTicks(),
- PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, touch_id));
- ui::PointerEvent pointer_event(touch_event);
- EXPECT_EQ(pointer_event.pointer_details().id, touch_id);
- }
-}
-
-TEST(EventTest, PointerDetailsPointer) {
- const float kRadiusX = 10.0f;
- const float kRadiusY = 5.0f;
- const float kForce = 15.0f;
- ui::TouchEvent touch_event(
- ET_TOUCH_PRESSED, gfx::Point(0, 0), ui::EventTimeForNow(),
- PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
- /* pointer_id*/ 0,
- /* radius_x */ kRadiusX,
- /* radius_y */ kRadiusY,
- /* force */ kForce));
- ui::PointerEvent pointer_event_from_touch(touch_event);
- EXPECT_EQ(kRadiusX, pointer_event_from_touch.pointer_details().radius_x);
- EXPECT_EQ(kRadiusY, pointer_event_from_touch.pointer_details().radius_y);
- EXPECT_EQ(kForce, pointer_event_from_touch.pointer_details().force);
- EXPECT_EQ(kRadiusX, pointer_event_from_touch.pointer_details().radius_x);
- EXPECT_EQ(0.0f, pointer_event_from_touch.pointer_details().tilt_x);
- EXPECT_EQ(0.0f, pointer_event_from_touch.pointer_details().tilt_y);
- EXPECT_EQ(EventPointerType::POINTER_TYPE_TOUCH,
- pointer_event_from_touch.pointer_details().pointer_type);
-
- ui::MouseEvent mouse_event(ET_MOUSE_PRESSED, gfx::Point(0, 0),
- gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0);
- ui::PointerEvent pointer_event_from_mouse(mouse_event);
- EXPECT_EQ(mouse_event.pointer_details(),
- pointer_event_from_mouse.pointer_details());
-}
-
-TEST(EventTest, PointerEventClone) {
- {
- ui::PointerEvent ptr_event(ui::TouchEvent(
- ET_TOUCH_PRESSED, gfx::Point(0, 0), ui::EventTimeForNow(),
- PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
- /* pointer_id*/ 0,
- /* radius_x */ 10.0f,
- /* radius_y */ 5.0f,
- /* force */ 15.0f)));
- std::unique_ptr<ui::Event> clone(ui::Event::Clone(ptr_event));
- EXPECT_TRUE(clone->IsPointerEvent());
- ui::PointerEvent* clone_as_ptr = clone->AsPointerEvent();
-
- EXPECT_EQ(ptr_event.type(), clone_as_ptr->type());
- EXPECT_EQ(ptr_event.pointer_details().id,
- clone_as_ptr->pointer_details().id);
- EXPECT_EQ(ptr_event.pointer_details(), clone_as_ptr->pointer_details());
- EXPECT_EQ(ptr_event.location(), clone_as_ptr->location());
- EXPECT_EQ(ptr_event.root_location(), clone_as_ptr->root_location());
- }
-
- {
- ui::PointerEvent ptr_event(
- ui::MouseEvent(ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0),
- ui::EventTimeForNow(), 0, 0));
- std::unique_ptr<ui::Event> clone(ui::Event::Clone(ptr_event));
- EXPECT_TRUE(clone->IsPointerEvent());
- ui::PointerEvent* clone_as_ptr = clone->AsPointerEvent();
-
- EXPECT_EQ(ptr_event.type(), clone_as_ptr->type());
- EXPECT_EQ(ptr_event.pointer_details().id,
- clone_as_ptr->pointer_details().id);
- EXPECT_EQ(ptr_event.pointer_details(), clone_as_ptr->pointer_details());
- EXPECT_EQ(ptr_event.location(), clone_as_ptr->location());
- EXPECT_EQ(ptr_event.root_location(), clone_as_ptr->root_location());
- }
-}
-
TEST(EventTest, MouseEventLatencyUIComponentExists) {
const gfx::Point origin(0, 0);
MouseEvent mouseev(ET_MOUSE_PRESSED, origin, origin, EventTimeForNow(), 0, 0);
@@ -963,104 +770,6 @@ TEST(EventTest, MouseWheelEventLatencyUIComponentExists) {
ui::INPUT_EVENT_LATENCY_UI_COMPONENT, nullptr));
}
-TEST(EventTest, PointerEventToMouseEvent) {
- const struct {
- ui::EventType in_type;
- ui::EventType out_type;
- gfx::Point location;
- gfx::Point root_location;
- int flags;
- int changed_button_flags;
- } kTestData[] = {
- {ui::ET_POINTER_DOWN, ui::ET_MOUSE_PRESSED, gfx::Point(10, 20),
- gfx::Point(110, 120), 0, 0},
- {ui::ET_POINTER_MOVED, ui::ET_MOUSE_MOVED, gfx::Point(20, 10),
- gfx::Point(1, 2), 0, 0},
- {ui::ET_POINTER_MOVED, ui::ET_MOUSE_DRAGGED, gfx::Point(20, 10),
- gfx::Point(1, 2), EF_LEFT_MOUSE_BUTTON, 0},
- {ui::ET_POINTER_MOVED, ui::ET_MOUSE_DRAGGED, gfx::Point(20, 10),
- gfx::Point(1, 2), EF_RIGHT_MOUSE_BUTTON, 0},
- {ui::ET_POINTER_MOVED, ui::ET_MOUSE_DRAGGED, gfx::Point(20, 10),
- gfx::Point(1, 2), EF_MIDDLE_MOUSE_BUTTON, 0},
- {ui::ET_POINTER_ENTERED, ui::ET_MOUSE_ENTERED, gfx::Point(), gfx::Point(),
- EF_MIDDLE_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON, 0},
- {ui::ET_POINTER_EXITED, ui::ET_MOUSE_EXITED, gfx::Point(5, 1),
- gfx::Point(1, 5), EF_RIGHT_MOUSE_BUTTON, 0},
- {ui::ET_POINTER_UP, ui::ET_MOUSE_RELEASED, gfx::Point(1000, 1000),
- gfx::Point(14, 15), EF_MIDDLE_MOUSE_BUTTON, EF_MIDDLE_MOUSE_BUTTON}};
-
- for (size_t i = 0; i < arraysize(kTestData); i++) {
- ui::PointerEvent pointer_event(
- kTestData[i].in_type, kTestData[i].location, kTestData[i].root_location,
- kTestData[i].flags, kTestData[i].changed_button_flags,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0),
- base::TimeTicks());
- ui::MouseEvent mouse_event(pointer_event);
-
- EXPECT_EQ(kTestData[i].out_type, mouse_event.type());
- EXPECT_EQ(kTestData[i].location, mouse_event.location());
- EXPECT_EQ(kTestData[i].root_location, mouse_event.root_location());
- EXPECT_EQ(kTestData[i].flags, mouse_event.flags());
- EXPECT_EQ(kTestData[i].changed_button_flags,
- mouse_event.changed_button_flags());
- }
-}
-
-TEST(EventTest, PointerEventToTouchEventType) {
- ui::EventType kTouchTypeMap[][2] = {
- {ui::ET_POINTER_DOWN, ui::ET_TOUCH_PRESSED},
- {ui::ET_POINTER_MOVED, ui::ET_TOUCH_MOVED},
- {ui::ET_POINTER_UP, ui::ET_TOUCH_RELEASED},
- {ui::ET_POINTER_CANCELLED, ui::ET_TOUCH_CANCELLED},
- };
-
- for (size_t i = 0; i < arraysize(kTouchTypeMap); i++) {
- ui::PointerEvent pointer_event(
- kTouchTypeMap[i][0], gfx::Point(), gfx::Point(), 0, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0),
- base::TimeTicks());
- ui::TouchEvent touch_event(pointer_event);
-
- EXPECT_EQ(kTouchTypeMap[i][1], touch_event.type());
- }
-}
-
-TEST(EventTest, PointerEventToTouchEventDetails) {
- ui::PointerEvent pointer_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 14), EventTimeForNow(),
- PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
- /* pointer_id*/ 15,
- /* radius_x */ 11.5,
- /* radius_y */ 13.5,
- /* force */ 0.0,
- /* twist */ 13.0),
- 0));
- ui::TouchEvent touch_event(pointer_event);
-
- EXPECT_EQ(pointer_event.location(), touch_event.location());
- EXPECT_EQ(pointer_event.flags(), touch_event.flags());
- EXPECT_EQ(pointer_event.pointer_details().id,
- touch_event.pointer_details().id);
- EXPECT_EQ(pointer_event.pointer_details(), touch_event.pointer_details());
- EXPECT_EQ(pointer_event.time_stamp(), touch_event.time_stamp());
-}
-
-TEST(EventTest, PointerEventSourceEventTypeExistsInLatencyInfo) {
- ui::PointerEvent wheel_poniter_event(
- ui::ET_POINTER_WHEEL_CHANGED, gfx::Point(), gfx::Point(), 0, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0),
- ui::EventTimeForNow());
- EXPECT_EQ(wheel_poniter_event.latency()->source_event_type(),
- ui::SourceEventType::WHEEL);
-
- ui::PointerEvent touch_poniter_event(
- ui::ET_TOUCH_PRESSED, gfx::Point(), gfx::Point(), 0, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0),
- ui::EventTimeForNow());
- EXPECT_EQ(touch_poniter_event.latency()->source_event_type(),
- ui::SourceEventType::TOUCH);
-}
-
// Checks that Event.Latency.OS.TOUCH_PRESSED, TOUCH_MOVED,
// and TOUCH_RELEASED histograms are computed properly.
#if defined(USE_X11)
diff --git a/chromium/ui/events/event_utils.cc b/chromium/ui/events/event_utils.cc
index 164fd2285ce..4c4634c4731 100644
--- a/chromium/ui/events/event_utils.cc
+++ b/chromium/ui/events/event_utils.cc
@@ -172,14 +172,6 @@ const char* EventTypeName(EventType type) {
CASE_TYPE(ET_TOUCH_MOVED);
CASE_TYPE(ET_TOUCH_CANCELLED);
CASE_TYPE(ET_DROP_TARGET_EVENT);
- CASE_TYPE(ET_POINTER_DOWN);
- CASE_TYPE(ET_POINTER_MOVED);
- CASE_TYPE(ET_POINTER_UP);
- CASE_TYPE(ET_POINTER_CANCELLED);
- CASE_TYPE(ET_POINTER_ENTERED);
- CASE_TYPE(ET_POINTER_EXITED);
- CASE_TYPE(ET_POINTER_WHEEL_CHANGED);
- CASE_TYPE(ET_POINTER_CAPTURE_CHANGED);
CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
CASE_TYPE(ET_GESTURE_SCROLL_END);
CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
diff --git a/chromium/ui/views/views_exports.cc b/chromium/ui/events/events_exports.cc
index f1ba3f5336e..0bc4c7297e9 100644
--- a/chromium/ui/views/views_exports.cc
+++ b/chromium/ui/events/events_exports.cc
@@ -1,10 +1,10 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file is for including headers that are not included in any other .cc
-// files contained within the ui/views module. We need to include these here so
+// files contained with the ui/events module. We need to include these here so
// that linker will know to include the symbols, defined by these headers, in
// the resulting dynamic library.
-#include "ui/views/pointer_watcher.h"
+#include "ui/events/event_observer.h"
diff --git a/chromium/ui/events/gesture_detection/gesture_configuration.cc b/chromium/ui/events/gesture_detection/gesture_configuration.cc
index 8bc64ed7c6c..9f861a643e5 100644
--- a/chromium/ui/events/gesture_detection/gesture_configuration.cc
+++ b/chromium/ui/events/gesture_detection/gesture_configuration.cc
@@ -67,7 +67,6 @@ GestureConfiguration::GestureConfiguration()
// 2 * max_touch_move_in_pixels_for_click_.
span_slop_(30),
swipe_enabled_(false),
- tab_scrub_activation_delay_in_ms_(200),
two_finger_tap_enabled_(false),
velocity_tracker_strategy_(VelocityTracker::Strategy::STRATEGY_DEFAULT) {
}
diff --git a/chromium/ui/events/gesture_detection/gesture_configuration.h b/chromium/ui/events/gesture_detection/gesture_configuration.h
index 6259021b4e9..0af5c733594 100644
--- a/chromium/ui/events/gesture_detection/gesture_configuration.h
+++ b/chromium/ui/events/gesture_detection/gesture_configuration.h
@@ -161,14 +161,6 @@ class GESTURE_DETECTION_EXPORT GestureConfiguration {
float span_slop() const { return span_slop_; }
bool swipe_enabled() const { return swipe_enabled_; }
void set_swipe_enabled(bool val) { swipe_enabled_ = val; }
-
- // TODO(davemoore): Move into chrome/browser/ui.
- int tab_scrub_activation_delay_in_ms() const {
- return tab_scrub_activation_delay_in_ms_;
- }
- void set_tab_scrub_activation_delay_in_ms(int val) {
- tab_scrub_activation_delay_in_ms_ = val;
- }
bool two_finger_tap_enabled() const { return two_finger_tap_enabled_; }
void set_two_finger_tap_enabled(bool val) { two_finger_tap_enabled_ = val; }
VelocityTracker::Strategy velocity_tracker_strategy() const {
@@ -254,9 +246,6 @@ class GESTURE_DETECTION_EXPORT GestureConfiguration {
int show_press_delay_in_ms_;
float span_slop_;
bool swipe_enabled_;
-
- // TODO(davemoore): Move into chrome/browser/ui.
- int tab_scrub_activation_delay_in_ms_;
bool two_finger_tap_enabled_;
VelocityTracker::Strategy velocity_tracker_strategy_;
diff --git a/chromium/ui/events/gestures/gesture_recognizer.h b/chromium/ui/events/gestures/gesture_recognizer.h
index de966ee36aa..33c65d7d312 100644
--- a/chromium/ui/events/gestures/gesture_recognizer.h
+++ b/chromium/ui/events/gestures/gesture_recognizer.h
@@ -54,13 +54,17 @@ class EVENTS_EXPORT GestureRecognizer {
// |source_device_id|, within
// GestureConfiguration::max_separation_for_gesture_touches_in_pixels of
// |location|, or NULL if no such point exists.
- virtual GestureConsumer* GetTargetForLocation(
- const gfx::PointF& location, int source_device_id) = 0;
+ virtual GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
+ int source_device_id) = 0;
// Cancels all touches except those targeted to |not_cancelled|. If
// |not_cancelled| == nullptr, cancels all touches.
virtual void CancelActiveTouchesExcept(GestureConsumer* not_cancelled) = 0;
+ // Cancels all touches to the specified consumers.
+ virtual void CancelActiveTouchesOn(
+ const std::vector<GestureConsumer*>& consumers) = 0;
+
// Transfer the gesture stream from the drag source (current_consumer) to the
// consumer used for dragging (new_consumer). If |transfer_touches_behavior|
// is kCancel, dispatches cancel events to |current_consumer| to ensure that
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl.cc b/chromium/ui/events/gestures/gesture_recognizer_impl.cc
index 6e811311856..712c3eecad7 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl.cc
@@ -60,11 +60,9 @@ bool RemoveValueFromMap(std::map<Key, T>* map, const Value& value) {
////////////////////////////////////////////////////////////////////////////////
// GestureRecognizerImpl, public:
-GestureRecognizerImpl::GestureRecognizerImpl() {
-}
+GestureRecognizerImpl::GestureRecognizerImpl() = default;
-GestureRecognizerImpl::~GestureRecognizerImpl() {
-}
+GestureRecognizerImpl::~GestureRecognizerImpl() = default;
// Checks if this finger is already down, if so, returns the current target.
// Otherwise, returns NULL.
@@ -74,7 +72,8 @@ GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget(
}
GestureConsumer* GestureRecognizerImpl::GetTargetForLocation(
- const gfx::PointF& location, int source_device_id) {
+ const gfx::PointF& location,
+ int source_device_id) {
const float max_distance =
GestureConfiguration::GetInstance()
->max_separation_for_gesture_touches_in_pixels();
@@ -111,6 +110,14 @@ void GestureRecognizerImpl::CancelActiveTouchesExcept(
CancelActiveTouchesExceptImpl(not_cancelled, kNotifyObservers);
}
+void GestureRecognizerImpl::CancelActiveTouchesOn(
+ const std::vector<GestureConsumer*>& consumers) {
+ for (auto* consumer : consumers) {
+ if (base::ContainsKey(consumer_gesture_provider_, consumer))
+ CancelActiveTouchesImpl(consumer, kNotifyObservers);
+ }
+}
+
void GestureRecognizerImpl::TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
@@ -137,7 +144,7 @@ void GestureRecognizerImpl::TransferEventsTo(
std::vector<int> touchids_targeted_at_current;
- for (const auto& touch_id_target: touch_id_target_) {
+ for (const auto& touch_id_target : touch_id_target_) {
if (touch_id_target.second == current_consumer)
touchids_targeted_at_current.push_back(touch_id_target.first);
}
@@ -337,17 +344,18 @@ bool GestureRecognizerImpl::CancelActiveTouchesImpl(
std::vector<std::unique_ptr<TouchEvent>> cancelling_touches =
GetEventPerPointForConsumer(consumer, ET_TOUCH_CANCELLED);
+ if (cancelling_touches.empty())
+ return false;
for (const std::unique_ptr<TouchEvent>& cancelling_touch : cancelling_touches)
helper->DispatchSyntheticTouchEvent(cancelling_touch.get());
if (should_notify == kNotifyObservers) {
for (GestureRecognizerObserver& observer : observers())
observer.OnActiveTouchesCanceled(consumer);
}
- return !cancelling_touches.empty();
+ return true;
}
-bool GestureRecognizerImpl::CleanupStateForConsumer(
- GestureConsumer* consumer) {
+bool GestureRecognizerImpl::CleanupStateForConsumer(GestureConsumer* consumer) {
bool state_cleaned_up = false;
state_cleaned_up |= RemoveValueFromMap(&touch_id_target_, consumer);
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl.h b/chromium/ui/events/gestures/gesture_recognizer_impl.h
index 36e8fc9f2cc..10b9ef9bbad 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl.h
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl.h
@@ -48,6 +48,8 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
int source_device_id) override;
void CancelActiveTouchesExcept(GestureConsumer* not_cancelled) override;
+ void CancelActiveTouchesOn(
+ const std::vector<GestureConsumer*>& consumers) override;
void TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc b/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc
index d66805dfef0..3455e67dcfd 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl_mac.cc
@@ -42,6 +42,9 @@ GestureConsumer* GestureRecognizerImplMac::GetTargetForLocation(
void GestureRecognizerImplMac::CancelActiveTouchesExcept(
GestureConsumer* not_cancelled) {}
+void GestureRecognizerImplMac::CancelActiveTouchesOn(
+ const std::vector<GestureConsumer*>& consumers) {}
+
void GestureRecognizerImplMac::TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl_mac.h b/chromium/ui/events/gestures/gesture_recognizer_impl_mac.h
index f0c4615f436..f564e3bb733 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl_mac.h
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl_mac.h
@@ -34,6 +34,8 @@ class EVENTS_EXPORT GestureRecognizerImplMac : public GestureRecognizer {
GestureConsumer* GetTargetForLocation(const gfx::PointF& location,
int source_device_id) override;
void CancelActiveTouchesExcept(GestureConsumer* not_cancelled) override;
+ void CancelActiveTouchesOn(
+ const std::vector<GestureConsumer*>& consumers) override;
void TransferEventsTo(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
diff --git a/chromium/ui/events/gestures/gesture_recognizer_impl_unittest.cc b/chromium/ui/events/gestures/gesture_recognizer_impl_unittest.cc
index 6446df7a5c5..35113421061 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_impl_unittest.cc
+++ b/chromium/ui/events/gestures/gesture_recognizer_impl_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/events/gestures/gesture_recognizer_impl.h"
+#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/gestures/gesture_recognizer_observer.h"
@@ -118,14 +119,26 @@ class GestureRecognizerImplTest : public testing::Test {
GestureRecognizerImpl gesture_recognizer_;
TestGestureEventHelper helper_;
std::unique_ptr<TestGestureRecognizerObserver> observer_;
+ base::MessageLoopForUI message_loop_;
DISALLOW_COPY_AND_ASSIGN(GestureRecognizerImplTest);
};
-TEST_F(GestureRecognizerImplTest, CancelActiveTouchEvents) {
+TEST_F(GestureRecognizerImplTest, CancelActiveTouchesNoCancellations) {
GestureConsumer consumer;
gesture_recognizer()->CancelActiveTouches(&consumer);
+ EXPECT_EQ(0, observer()->active_touches_cancelled_call_count());
+ EXPECT_FALSE(observer()->last_cancelled());
+}
+
+TEST_F(GestureRecognizerImplTest, CancelActiveTouches) {
+ GestureConsumer consumer;
+ TouchEvent event(ET_TOUCH_PRESSED, gfx::Point(), base::TimeTicks::Now(),
+ PointerDetails());
+ gesture_recognizer()->ProcessTouchEventPreDispatch(&event, &consumer);
+ gesture_recognizer()->CancelActiveTouches(&consumer);
+
EXPECT_EQ(1, observer()->active_touches_cancelled_call_count());
EXPECT_EQ(&consumer, observer()->last_cancelled());
}
diff --git a/chromium/ui/events/gestures/gesture_recognizer_observer.h b/chromium/ui/events/gestures/gesture_recognizer_observer.h
index 4826cda5bb2..e07a81536de 100644
--- a/chromium/ui/events/gestures/gesture_recognizer_observer.h
+++ b/chromium/ui/events/gestures/gesture_recognizer_observer.h
@@ -13,12 +13,21 @@ namespace ui {
class EVENTS_EXPORT GestureRecognizerObserver : public base::CheckedObserver {
public:
+ // Called when CancelActiveTouchesExcept() is called.
virtual void OnActiveTouchesCanceledExcept(
GestureConsumer* not_cancelled) = 0;
+
+ // Called when TransferEventsTo() happened from |current_consumer| to
+ // |new_consumer|.
virtual void OnEventsTransferred(
GestureConsumer* current_consumer,
GestureConsumer* new_consumer,
TransferTouchesBehavior transfer_touches_behavior) = 0;
+
+ // Called when CancelActiveTouches() cancels touches on |consumer|. This is
+ // not called from CancelActiveTouchesExcept() causes cancel on |consumer|.
+ // Also this is not called when an invocation of CancelActiveTouches() doesn't
+ // cancel anything actually.
virtual void OnActiveTouchesCanceled(GestureConsumer* consumer) = 0;
protected:
diff --git a/chromium/ui/events/keyboard_hook.h b/chromium/ui/events/keyboard_hook.h
index 36e9b88f23e..ca88fec0dfa 100644
--- a/chromium/ui/events/keyboard_hook.h
+++ b/chromium/ui/events/keyboard_hook.h
@@ -32,11 +32,19 @@ class EVENTS_EXPORT KeyboardHook {
// |callback| is called for each key which is intercepted.
// Returns a valid instance if the hook was created and successfully
// registered otherwise nullptr.
- static std::unique_ptr<KeyboardHook> Create(
+ static std::unique_ptr<KeyboardHook> CreateModifierKeyboardHook(
base::Optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget,
KeyEventCallback callback);
+ // Creates a platform-specific KeyboardHook implementation that captures the
+ // play/pause, stop, and next/previous track media keys.
+ // |callback| is called for each key which is intercepted.
+ // Returns a valid instance if the hook was created and successfully
+ // registered otherwise nullptr.
+ static std::unique_ptr<KeyboardHook> CreateMediaKeyboardHook(
+ KeyEventCallback callback);
+
// True if |dom_code| is reserved for an active KeyboardLock request.
virtual bool IsKeyLocked(DomCode dom_code) const = 0;
};
diff --git a/chromium/ui/events/keyboard_hook_base.cc b/chromium/ui/events/keyboard_hook_base.cc
index 56381738b4a..327c2d4117d 100644
--- a/chromium/ui/events/keyboard_hook_base.cc
+++ b/chromium/ui/events/keyboard_hook_base.cc
@@ -34,9 +34,8 @@ bool KeyboardHookBase::ShouldCaptureKeyEvent(DomCode dom_code) const {
return !dom_codes_ || base::ContainsKey(dom_codes_.value(), dom_code);
}
-void KeyboardHookBase::ForwardCapturedKeyEvent(
- std::unique_ptr<KeyEvent> event) {
- key_event_callback_.Run(event.get());
+void KeyboardHookBase::ForwardCapturedKeyEvent(KeyEvent* event) {
+ key_event_callback_.Run(event);
}
} // namespace ui
diff --git a/chromium/ui/events/keyboard_hook_base.h b/chromium/ui/events/keyboard_hook_base.h
index 81ffae2ff9f..29740813551 100644
--- a/chromium/ui/events/keyboard_hook_base.h
+++ b/chromium/ui/events/keyboard_hook_base.h
@@ -29,7 +29,9 @@ class KeyboardHookBase : public KeyboardHook {
bool ShouldCaptureKeyEvent(DomCode dom_code) const;
// Forwards the key event using |key_event_callback_|.
- void ForwardCapturedKeyEvent(std::unique_ptr<KeyEvent> event);
+ // |event| is owned by the calling method and will live until this method
+ // returns.
+ void ForwardCapturedKeyEvent(KeyEvent* event);
const base::Optional<base::flat_set<DomCode>>& dom_codes() {
return dom_codes_;
diff --git a/chromium/ui/events/keycodes/dom/dom_keyboard_layout.cc b/chromium/ui/events/keycodes/dom/dom_keyboard_layout.cc
index 2c227d60203..6f311cce105 100644
--- a/chromium/ui/events/keycodes/dom/dom_keyboard_layout.cc
+++ b/chromium/ui/events/keycodes/dom/dom_keyboard_layout.cc
@@ -38,6 +38,8 @@ const DomCode writing_system_key_domcodes[] = {
const size_t kWritingSystemKeyDomCodeEntries =
base::size(writing_system_key_domcodes);
+const uint32_t kHankakuZenkakuPlaceholder = 0x89d2;
+
// Mapping from Unicode combining characters to corresponding printable
// character.
const static struct {
@@ -81,9 +83,16 @@ base::flat_map<std::string, std::string> DomKeyboardLayout::GetMap() {
continue;
std::string key_str;
- size_t len = base::WriteUnicodeCharacter(unicode, &key_str);
- if (len == 0)
- continue;
+ // Special handling for the Japanese BACKQUOTE, which is an IME key used
+ // to switch between half-width and full-width mode.
+ if (unicode == kHankakuZenkakuPlaceholder) {
+ // 半角/全角 = hankaku/zenkaku = halfwidth/fullwidth
+ key_str = "\u534a\u89d2/\u5168\u89d2";
+ } else {
+ size_t len = base::WriteUnicodeCharacter(unicode, &key_str);
+ if (len == 0)
+ continue;
+ }
dom_map.emplace(KeycodeConverter::DomCodeToCodeString(dom_code), key_str);
}
return dom_map;
@@ -91,8 +100,7 @@ base::flat_map<std::string, std::string> DomKeyboardLayout::GetMap() {
bool DomKeyboardLayout::IsAsciiCapable() {
uint16_t uniA = layout_[DomCode::US_A];
- uint16_t uniBackquote = layout_[DomCode::BACKQUOTE];
- return uniA >= 'a' && uniA <= 'z' && uniBackquote != 0;
+ return uniA >= 'a' && uniA <= 'z';
}
} // namespace ui
diff --git a/chromium/ui/events/keycodes/dom/dom_keyboard_layout.h b/chromium/ui/events/keycodes/dom/dom_keyboard_layout.h
index 6057f597170..2583081644a 100644
--- a/chromium/ui/events/keycodes/dom/dom_keyboard_layout.h
+++ b/chromium/ui/events/keycodes/dom/dom_keyboard_layout.h
@@ -62,6 +62,8 @@ extern const DomCode writing_system_key_domcodes[];
extern const size_t kWritingSystemKeyDomCodeEntries;
+extern const uint32_t kHankakuZenkakuPlaceholder;
+
} // namespace ui
#endif // UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_H_
diff --git a/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_base.cc b/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_base.cc
index e8b1e3f317e..f695bf08a6e 100644
--- a/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_base.cc
+++ b/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_base.cc
@@ -56,6 +56,9 @@ void DomKeyboardLayoutMapBase::PopulateLayout(uint32_t keyboard_layout_index,
unicode_value = dom_key.ToCharacter();
else if (dom_key.IsDeadKey())
unicode_value = dom_key.ToDeadKeyCombiningCharacter();
+ else if (dom_key == ui::DomKey::ZENKAKU_HANKAKU)
+ // Placeholder for hankaku/zenkaku string.
+ unicode_value = kHankakuZenkakuPlaceholder;
if (unicode_value != 0)
layout->AddKeyMapping(dom_code, unicode_value);
diff --git a/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc b/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc
index 4a144c35cda..d7d5b37c5c5 100644
--- a/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc
+++ b/chromium/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc
@@ -102,6 +102,33 @@ ui::DomKey DomKeyboardLayoutMapWin::GetDomKeyFromDomCodeForLayout(
::ToUnicodeEx(virtual_key_code, scan_code, keyboard_state, char_buffer,
base::size(char_buffer), /*wFlags=*/0, keyboard_layout);
+ // Handle special cases for Japanese keyboard layout.
+ if (0x04110411 == reinterpret_cast<unsigned int>(keyboard_layout)) {
+ // Fix value for Japanese yen currency symbol.
+ // Windows returns '\' for both IntlRo and IntlYen, even though IntlYen
+ // should be the yen symbol.
+ if (dom_code == ui::DomCode::INTL_YEN)
+ return ui::DomKey::FromCharacter(0x00a5); // Japanese yen symbol.
+
+ // Special case for Backquote.
+ // Technically, this layout is not completely ASCII-capable because the
+ // Backquote key is used as an IME function key (hankaku/zenkaku) and is
+ // thus not a printable key. However, other than this key, it is a perfectly
+ // usable ASCII-capable layout and it matches the values printed on the
+ // keyboard, so we have special handling to allow this key.
+ if (dom_code == ui::DomCode::BACKQUOTE)
+ return ui::DomKey::ZENKAKU_HANKAKU;
+ }
+
+ // Handle special cases for Korean keyboard layout.
+ if (0x04120412 == reinterpret_cast<unsigned int>(keyboard_layout)) {
+ // Fix value for Korean won currency symbol.
+ // Windows returns '\' for both Backslash and IntlBackslash, even though
+ // IntlBackslash should be the won symbol.
+ if (dom_code == ui::DomCode::INTL_BACKSLASH)
+ return ui::DomKey::FromCharacter(0x20a9); // Korean won symbol.
+ }
+
if (key_type == 1)
return ui::DomKey::FromCharacter(char_buffer[0]);
if (key_type == -1)
diff --git a/chromium/ui/events/mac/keyboard_hook_mac.mm b/chromium/ui/events/mac/keyboard_hook_mac.mm
index e032b634f5e..1da9d4ce421 100644
--- a/chromium/ui/events/mac/keyboard_hook_mac.mm
+++ b/chromium/ui/events/mac/keyboard_hook_mac.mm
@@ -9,11 +9,17 @@
namespace ui {
// static
-std::unique_ptr<KeyboardHook> KeyboardHook::Create(
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
base::Optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget,
KeyEventCallback callback) {
return nullptr;
}
+// static
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateMediaKeyboardHook(
+ KeyEventCallback callback) {
+ return nullptr;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/mojo/event.mojom b/chromium/ui/events/mojo/event.mojom
index 9dafcc23621..b8364e07f79 100644
--- a/chromium/ui/events/mojo/event.mojom
+++ b/chromium/ui/events/mojo/event.mojom
@@ -56,57 +56,6 @@ struct LocationData {
gfx.mojom.PointF root_location;
};
-// TODO(rjkroege,sadrul): Add gesture representation.
-struct PointerData {
- int32 pointer_id;
- int32 changed_button_flags;
- PointerKind kind;
- LocationData location;
- // Some devices (e.g. pen, finger) can extend across multiple pixels
- // at once. |brush_data| provides additional data for this case and
- // is available when |kind| is PEN or TOUCH.
- BrushData? brush_data;
- // Only set for |WHEEL| events.
- WheelData? wheel_data;
-};
-
-// Information payload to support
-// https://developer.mozilla.org/en-US/docs/Web/Events/wheel.
-// TODO(rjkroege): Handle MacOS momentum scrolling.
-struct WheelData {
- WheelMode mode;
- // |delta_x|, |delta_y|, |delta_z| can be in units of pixels, lines, pages
- // or control scaling as controlled by |mode|. Pixel scroll is physical
- // pixels in the coordinate system of the target View.
- float delta_x;
- float delta_y;
- float delta_z;
-};
-
-// Supplementary data to support pointers where the pointer can
-// cover multiple pixels per http://www.w3.org/TR/pointerevents/
-struct BrushData {
- // |width| and |height| are in CSS pixels in the coordinate system of
- // the target View.
- float width;
- float height;
- // |pressure| range is [0,1]. For devices like mice buttons where the
- // pressure is not available, it will be set to 0.5 if the button is down.
- float pressure;
- // |tilt_x| and |tilt_y| are in degrees. See comments in ui::PointerDetails
- // for more information.
- float tilt_x;
- float tilt_y;
- // The normalized tangential pressure (or barrel pressure), typically set by
- // an additional control of the stylus, which has a range of [-1,1], where 0
- // is the neutral position of the control. Always 0 if the device does not
- // support it.
- float tangential_pressure;
- // The clockwise rotation of a pen stylus around its own major axis, in
- // degrees in the range [0,359]. Always 0 if the device does not support it.
- int32 twist;
-};
-
// Data to support gesture events.
// TODO(crbug.com/767087): Expand GestureEvent and GestureEventDetails support.
struct GestureData {
@@ -170,8 +119,6 @@ struct Event {
EventType action;
// A bitfield of kEventFlag* and kMouseEventFlag* values in
// input_event_constants.mojom.
- //
- // TODO(sky): parts of this should move to PointerData.
int32 flags;
// This value accurately orders events w.r.t. to each other but does not
// position them at an absolute time since the TimeTicks origin is only
@@ -179,7 +126,6 @@ struct Event {
mojo_base.mojom.TimeTicks time_stamp;
LatencyInfo latency;
KeyData? key_data;
- PointerData? pointer_data;
GestureData? gesture_data;
ScrollData? scroll_data;
TouchData? touch_data;
diff --git a/chromium/ui/events/mojo/event_constants.mojom b/chromium/ui/events/mojo/event_constants.mojom
index e013bf06a5d..fd0356c6fc2 100644
--- a/chromium/ui/events/mojo/event_constants.mojom
+++ b/chromium/ui/events/mojo/event_constants.mojom
@@ -16,14 +16,6 @@ enum EventType {
UNKNOWN,
KEY_PRESSED,
KEY_RELEASED,
- POINTER_DOWN,
- POINTER_MOVED,
- POINTER_UP,
- POINTER_CANCELLED,
- POINTER_ENTERED,
- POINTER_EXITED,
- POINTER_WHEEL_CHANGED,
- POINTER_CAPTURE_CHANGED,
GESTURE_TAP,
SCROLL,
SCROLL_FLING_START,
@@ -80,13 +72,6 @@ enum PointerKind {
ERASER,
};
-enum WheelMode {
- PIXEL,
- LINE,
- PAGE,
- SCALING,
-};
-
// Phase information used for a ScrollEvent.
// These values match ui::ScrollEventPhase in ui/events/event_constants.h
enum ScrollEventPhase {
diff --git a/chromium/ui/events/mojo/event_struct_traits.cc b/chromium/ui/events/mojo/event_struct_traits.cc
index c5324bbc8f5..ca6e276e4e1 100644
--- a/chromium/ui/events/mojo/event_struct_traits.cc
+++ b/chromium/ui/events/mojo/event_struct_traits.cc
@@ -24,59 +24,6 @@ ui::mojom::LocationDataPtr CreateLocationData(const ui::LocatedEvent* event) {
return location_data;
}
-void UpdateEventLocation(const ui::mojom::PointerData& pointer_data,
- EventUniquePtr* out) {
- // Set the float location, as the constructor only takes a gfx::Point.
- // This uses the event root_location field to store screen pixel
- // coordinates. See http://crbug.com/608547
- out->get()->AsLocatedEvent()->set_location_f(
- pointer_data.location->relative_location);
- out->get()->AsLocatedEvent()->set_root_location_f(
- pointer_data.location->root_location);
-}
-
-bool ReadPointerDetailsDeprecated(ui::mojom::EventType event_type,
- const ui::mojom::PointerData& pointer_data,
- ui::PointerDetails* out) {
- switch (pointer_data.kind) {
- case ui::mojom::PointerKind::MOUSE: {
- if (event_type == ui::mojom::EventType::POINTER_WHEEL_CHANGED ||
- event_type == ui::mojom::EventType::MOUSE_WHEEL_EVENT) {
- *out = ui::PointerDetails(
- ui::EventPointerType::POINTER_TYPE_MOUSE,
- gfx::Vector2d(static_cast<int>(pointer_data.wheel_data->delta_x),
- static_cast<int>(pointer_data.wheel_data->delta_y)),
- ui::MouseEvent::kMousePointerId);
- } else {
- *out = ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE,
- ui::MouseEvent::kMousePointerId);
- }
- return true;
- }
- case ui::mojom::PointerKind::TOUCH:
- case ui::mojom::PointerKind::PEN: {
- ui::EventPointerType pointer_type;
- if (!EnumTraits<ui::mojom::PointerKind, ui::EventPointerType>::FromMojom(
- pointer_data.kind, &pointer_type))
- return false;
- const ui::mojom::BrushData& brush_data = *pointer_data.brush_data;
- *out = ui::PointerDetails(
- pointer_type, pointer_data.pointer_id, brush_data.width,
- brush_data.height, brush_data.pressure, brush_data.twist,
- brush_data.tilt_x, brush_data.tilt_y, brush_data.tangential_pressure);
- return true;
- }
- case ui::mojom::PointerKind::ERASER:
- // TODO(jamescook): Eraser support.
- NOTIMPLEMENTED();
- return false;
- case ui::mojom::PointerKind::UNKNOWN:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
bool ReadScrollData(ui::mojom::EventDataView* event,
base::TimeTicks time_stamp,
EventUniquePtr* out) {
@@ -168,22 +115,6 @@ ui::mojom::EventType TypeConverter<ui::mojom::EventType,
return ui::mojom::EventType::KEY_PRESSED;
case ui::ET_KEY_RELEASED:
return ui::mojom::EventType::KEY_RELEASED;
- case ui::ET_POINTER_DOWN:
- return ui::mojom::EventType::POINTER_DOWN;
- case ui::ET_POINTER_MOVED:
- return ui::mojom::EventType::POINTER_MOVED;
- case ui::ET_POINTER_UP:
- return ui::mojom::EventType::POINTER_UP;
- case ui::ET_POINTER_CANCELLED:
- return ui::mojom::EventType::POINTER_CANCELLED;
- case ui::ET_POINTER_ENTERED:
- return ui::mojom::EventType::POINTER_ENTERED;
- case ui::ET_POINTER_EXITED:
- return ui::mojom::EventType::POINTER_EXITED;
- case ui::ET_POINTER_WHEEL_CHANGED:
- return ui::mojom::EventType::POINTER_WHEEL_CHANGED;
- case ui::ET_POINTER_CAPTURE_CHANGED:
- return ui::mojom::EventType::POINTER_CAPTURE_CHANGED;
case ui::ET_GESTURE_TAP:
return ui::mojom::EventType::GESTURE_TAP;
case ui::ET_SCROLL:
@@ -236,22 +167,6 @@ ui::EventType TypeConverter<ui::EventType, ui::mojom::EventType>::Convert(
return ui::ET_KEY_PRESSED;
case ui::mojom::EventType::KEY_RELEASED:
return ui::ET_KEY_RELEASED;
- case ui::mojom::EventType::POINTER_DOWN:
- return ui::ET_POINTER_DOWN;
- case ui::mojom::EventType::POINTER_MOVED:
- return ui::ET_POINTER_MOVED;
- case ui::mojom::EventType::POINTER_UP:
- return ui::ET_POINTER_UP;
- case ui::mojom::EventType::POINTER_CANCELLED:
- return ui::ET_POINTER_CANCELLED;
- case ui::mojom::EventType::POINTER_ENTERED:
- return ui::ET_POINTER_ENTERED;
- case ui::mojom::EventType::POINTER_EXITED:
- return ui::ET_POINTER_EXITED;
- case ui::mojom::EventType::POINTER_WHEEL_CHANGED:
- return ui::ET_POINTER_WHEEL_CHANGED;
- case ui::mojom::EventType::POINTER_CAPTURE_CHANGED:
- return ui::ET_POINTER_CAPTURE_CHANGED;
case ui::mojom::EventType::GESTURE_TAP:
return ui::ET_GESTURE_TAP;
case ui::mojom::EventType::SCROLL:
@@ -339,81 +254,6 @@ StructTraits<ui::mojom::EventDataView, EventUniquePtr>::key_data(
}
// static
-ui::mojom::PointerDataPtr
-StructTraits<ui::mojom::EventDataView, EventUniquePtr>::pointer_data(
- const EventUniquePtr& event) {
- if (!event->IsPointerEvent())
- return nullptr;
-
- ui::mojom::PointerDataPtr pointer_data(ui::mojom::PointerData::New());
- const ui::PointerEvent* pointer_event = event->AsPointerEvent();
- const ui::PointerDetails* pointer_details = &pointer_event->pointer_details();
- pointer_data->changed_button_flags = pointer_event->changed_button_flags();
- pointer_data->location = CreateLocationData(event->AsLocatedEvent());
- pointer_data->pointer_id = pointer_details->id;
- ui::EventPointerType pointer_type = pointer_details->pointer_type;
-
- switch (pointer_type) {
- case ui::EventPointerType::POINTER_TYPE_MOUSE:
- pointer_data->kind = ui::mojom::PointerKind::MOUSE;
- break;
- case ui::EventPointerType::POINTER_TYPE_TOUCH:
- pointer_data->kind = ui::mojom::PointerKind::TOUCH;
- break;
- case ui::EventPointerType::POINTER_TYPE_PEN:
- pointer_data->kind = ui::mojom::PointerKind::PEN;
- break;
- case ui::EventPointerType::POINTER_TYPE_ERASER:
- pointer_data->kind = ui::mojom::PointerKind::ERASER;
- break;
- case ui::EventPointerType::POINTER_TYPE_UNKNOWN:
- NOTREACHED();
- }
-
- ui::mojom::BrushDataPtr brush_data(ui::mojom::BrushData::New());
- // TODO(rjk): this is in the wrong coordinate system
- brush_data->width = pointer_details->radius_x;
- brush_data->height = pointer_details->radius_y;
- brush_data->pressure = pointer_details->force;
- // In theory only pen events should have tilt, tangential_pressure and twist.
- // In practive a JavaScript PointerEvent could have type touch and still have
- // data in those fields.
- brush_data->tilt_x = pointer_details->tilt_x;
- brush_data->tilt_y = pointer_details->tilt_y;
- brush_data->tangential_pressure = pointer_details->tangential_pressure;
- brush_data->twist = pointer_details->twist;
- pointer_data->brush_data = std::move(brush_data);
-
- // TODO(rjkroege): Plumb raw pointer events on windows.
- // TODO(rjkroege): Handle force-touch on MacOS
- // TODO(rjkroege): Adjust brush data appropriately for Android.
-
- if (event->type() == ui::ET_POINTER_WHEEL_CHANGED) {
- ui::mojom::WheelDataPtr wheel_data(ui::mojom::WheelData::New());
-
- // TODO(rjkroege): Support page scrolling on windows by directly
- // cracking into a mojo event when the native event is available.
- wheel_data->mode = ui::mojom::WheelMode::LINE;
- // TODO(rjkroege): Support precise scrolling deltas.
-
- if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 &&
- pointer_details->offset.x() == 0) {
- wheel_data->delta_x = pointer_details->offset.y();
- wheel_data->delta_y = 0;
- wheel_data->delta_z = 0;
- } else {
- // TODO(rjkroege): support z in ui::Events.
- wheel_data->delta_x = pointer_details->offset.x();
- wheel_data->delta_y = pointer_details->offset.y();
- wheel_data->delta_z = 0;
- }
- pointer_data->wheel_data = std::move(wheel_data);
- }
-
- return pointer_data;
-}
-
-// static
ui::mojom::MouseDataPtr
StructTraits<ui::mojom::EventDataView, EventUniquePtr>::mouse_data(
const EventUniquePtr& event) {
@@ -516,31 +356,6 @@ bool StructTraits<ui::mojom::EventDataView, EventUniquePtr>::Read(
}
break;
}
- case ui::mojom::EventType::POINTER_DOWN:
- case ui::mojom::EventType::POINTER_UP:
- case ui::mojom::EventType::POINTER_MOVED:
- case ui::mojom::EventType::POINTER_CANCELLED:
- case ui::mojom::EventType::POINTER_ENTERED:
- case ui::mojom::EventType::POINTER_EXITED:
- case ui::mojom::EventType::POINTER_WHEEL_CHANGED:
- case ui::mojom::EventType::POINTER_CAPTURE_CHANGED: {
- ui::mojom::PointerDataPtr pointer_data;
- if (!event.ReadPointerData<ui::mojom::PointerDataPtr>(&pointer_data))
- return false;
-
- ui::PointerDetails pointer_details;
- if (!ReadPointerDetailsDeprecated(event.action(), *pointer_data,
- &pointer_details))
- return false;
-
- *out = std::make_unique<ui::PointerEvent>(
- mojo::ConvertTo<ui::EventType>(event.action()), gfx::Point(),
- gfx::Point(), event.flags(), pointer_data->changed_button_flags,
- pointer_details, time_stamp);
-
- UpdateEventLocation(*pointer_data, out);
- break;
- }
case ui::mojom::EventType::GESTURE_TAP:
if (!ReadGestureData(&event, time_stamp, out))
return false;
diff --git a/chromium/ui/events/mojo/event_struct_traits.h b/chromium/ui/events/mojo/event_struct_traits.h
index 1e5d3fb1bbb..113b5e04e8b 100644
--- a/chromium/ui/events/mojo/event_struct_traits.h
+++ b/chromium/ui/events/mojo/event_struct_traits.h
@@ -42,7 +42,6 @@ struct StructTraits<ui::mojom::EventDataView, EventUniquePtr> {
static base::TimeTicks time_stamp(const EventUniquePtr& event);
static const ui::LatencyInfo& latency(const EventUniquePtr& event);
static ui::mojom::KeyDataPtr key_data(const EventUniquePtr& event);
- static ui::mojom::PointerDataPtr pointer_data(const EventUniquePtr& event);
static ui::mojom::GestureDataPtr gesture_data(const EventUniquePtr& event);
static ui::mojom::ScrollDataPtr scroll_data(const EventUniquePtr& event);
static ui::mojom::TouchDataPtr touch_data(const EventUniquePtr& event);
diff --git a/chromium/ui/events/mojo/struct_traits_unittest.cc b/chromium/ui/events/mojo/struct_traits_unittest.cc
index 2c4d62b7b32..d85050bfdf4 100644
--- a/chromium/ui/events/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/events/mojo/struct_traits_unittest.cc
@@ -107,111 +107,6 @@ TEST(StructTraitsTest, KeyEvent) {
}
}
-TEST(StructTraitsTest, PointerEvent) {
- const PointerEvent kTestData[] = {
- // Mouse pointer events:
- {ET_POINTER_DOWN, gfx::Point(10, 10), gfx::Point(20, 30), EF_NONE, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(201)},
- {ET_POINTER_MOVED, gfx::Point(1, 5), gfx::Point(5, 1),
- EF_LEFT_MOUSE_BUTTON, EF_LEFT_MOUSE_BUTTON,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(202)},
- {ET_POINTER_UP, gfx::Point(411, 130), gfx::Point(20, 30),
- EF_MIDDLE_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON, EF_RIGHT_MOUSE_BUTTON,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(203)},
- {ET_POINTER_CANCELLED, gfx::Point(0, 1), gfx::Point(2, 3), EF_ALT_DOWN, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(204)},
- {ET_POINTER_ENTERED, gfx::Point(6, 7), gfx::Point(8, 9), EF_NONE, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(205)},
- {ET_POINTER_EXITED, gfx::Point(10, 10), gfx::Point(20, 30),
- EF_BACK_MOUSE_BUTTON, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(206)},
- {ET_POINTER_CAPTURE_CHANGED, gfx::Point(99, 99), gfx::Point(99, 99),
- EF_CONTROL_DOWN, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(207)},
-
- // Touch pointer events:
- {ET_POINTER_DOWN, gfx::Point(10, 10), gfx::Point(20, 30), EF_NONE, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_TOUCH,
- /* pointer_id */ 1,
- /* radius_x */ 1.0f,
- /* radius_y */ 2.0f,
- /* force */ 3.0f,
- /* twist */ 0,
- /* tilt_x */ 4.0f,
- /* tilt_y */ 5.0f),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(208)},
- {ET_POINTER_CANCELLED, gfx::Point(120, 120), gfx::Point(2, 3), EF_NONE, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_TOUCH,
- /* pointer_id */ 2,
- /* radius_x */ 5.5f,
- /* radius_y */ 4.5f,
- /* force */ 3.5f,
- /* twist */ 0,
- /* tilt_x */ 2.5f,
- /* tilt_y */ 0.5f),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(209)},
-
- // Pen pointer events:
- {ET_POINTER_DOWN, gfx::Point(1, 2), gfx::Point(3, 4), EF_NONE, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_PEN,
- /* pointer_id */ 3,
- /* radius_x */ 1.0f,
- /* radius_y */ 2.0f,
- /* force */ 3.0f,
- /* twist */ 90,
- /* tilt_x */ 4.0f,
- /* tilt_y */ 5.0f,
- /* tangential_pressure */ -1.f),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(210)},
- {ET_POINTER_UP, gfx::Point(5, 6), gfx::Point(7, 8), EF_NONE, 0,
- PointerDetails(EventPointerType::POINTER_TYPE_PEN,
- /* pointer_id */ 3,
- /* radius_x */ 1.0f,
- /* radius_y */ 2.0f,
- /* force */ 3.0f,
- /* twist */ 180,
- /* tilt_x */ 4.0f,
- /* tilt_y */ 5.0f,
- /* tangential_pressure */ 1.f),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(211)},
- };
-
- for (size_t i = 0; i < base::size(kTestData); i++) {
- std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
- std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
- EXPECT_TRUE(output->IsPointerEvent());
-
- const PointerEvent* output_ptr_event = output->AsPointerEvent();
- EXPECT_EQ(kTestData[i].type(), output_ptr_event->type());
- EXPECT_EQ(kTestData[i].flags(), output_ptr_event->flags());
- EXPECT_EQ(kTestData[i].location(), output_ptr_event->location());
- EXPECT_EQ(kTestData[i].root_location(), output_ptr_event->root_location());
- EXPECT_EQ(kTestData[i].pointer_details().id,
- output_ptr_event->pointer_details().id);
- EXPECT_EQ(kTestData[i].changed_button_flags(),
- output_ptr_event->changed_button_flags());
- EXPECT_EQ(kTestData[i].pointer_details(),
- output_ptr_event->pointer_details());
- EXPECT_EQ(kTestData[i].time_stamp(), output_ptr_event->time_stamp());
- }
-}
-
TEST(StructTraitsTest, MouseEvent) {
const MouseEvent kTestData[] = {
{ET_MOUSE_PRESSED, gfx::Point(10, 10), gfx::Point(20, 30),
@@ -260,40 +155,6 @@ TEST(StructTraitsTest, MouseEvent) {
}
}
-TEST(StructTraitsTest, PointerWheelEvent) {
- const MouseWheelEvent kTestData[] = {
- {gfx::Vector2d(11, 15), gfx::Point(3, 4), gfx::Point(40, 30),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(301),
- EF_LEFT_MOUSE_BUTTON, EF_LEFT_MOUSE_BUTTON},
- {gfx::Vector2d(-5, 3), gfx::Point(40, 3), gfx::Point(4, 0),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(302),
- EF_MIDDLE_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON,
- EF_MIDDLE_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON},
- {gfx::Vector2d(1, 0), gfx::Point(3, 4), gfx::Point(40, 30),
- base::TimeTicks() + base::TimeDelta::FromMicroseconds(303), EF_NONE,
- EF_NONE},
- };
-
- for (size_t i = 0; i < base::size(kTestData); i++) {
- std::unique_ptr<Event> expected_copy =
- std::make_unique<PointerEvent>(kTestData[i]);
- std::unique_ptr<Event> output;
- ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
- &expected_copy, &output));
- EXPECT_EQ(ET_POINTER_WHEEL_CHANGED, output->type());
-
- const PointerEvent* output_pointer_event = output->AsPointerEvent();
- EXPECT_EQ(ET_POINTER_WHEEL_CHANGED, output_pointer_event->type());
- EXPECT_EQ(kTestData[i].flags(), output_pointer_event->flags());
- EXPECT_EQ(kTestData[i].location(), output_pointer_event->location());
- EXPECT_EQ(kTestData[i].root_location(),
- output_pointer_event->root_location());
- EXPECT_EQ(kTestData[i].offset(),
- output_pointer_event->pointer_details().offset);
- EXPECT_EQ(kTestData[i].time_stamp(), output_pointer_event->time_stamp());
- }
-}
-
TEST(StructTraitsTest, MouseWheelEvent) {
const MouseWheelEvent kTestData[] = {
{gfx::Vector2d(11, 15), gfx::Point(3, 4), gfx::Point(40, 30),
@@ -309,8 +170,7 @@ TEST(StructTraitsTest, MouseWheelEvent) {
};
for (size_t i = 0; i < base::size(kTestData); i++) {
- std::unique_ptr<Event> expected_copy =
- std::make_unique<MouseWheelEvent>(PointerEvent(kTestData[i]));
+ std::unique_ptr<Event> expected_copy = Event::Clone(kTestData[i]);
std::unique_ptr<Event> output;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
&expected_copy, &output));
@@ -373,7 +233,7 @@ TEST(StructTraitsTest, GestureEvent) {
std::unique_ptr<Event> output;
ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::Event>(
&expected_copy, &output));
- EXPECT_TRUE(output->IsGestureEvent());
+ ASSERT_TRUE(output->IsGestureEvent());
const GestureEvent* output_ptr_event = output->AsGestureEvent();
ExpectEventsEqual(kTestData[i], *output);
diff --git a/chromium/ui/events/ozone/device/device_manager_manual.cc b/chromium/ui/events/ozone/device/device_manager_manual.cc
index 7cee681b283..f4887fdb4aa 100644
--- a/chromium/ui/events/ozone/device/device_manager_manual.cc
+++ b/chromium/ui/events/ozone/device/device_manager_manual.cc
@@ -9,7 +9,10 @@
#include "base/files/file_enumerator.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "ui/events/ozone/device/device_event.h"
#include "ui/events/ozone/device/device_event_observer.h"
@@ -28,12 +31,16 @@ void ScanDevicesOnWorkerThread(std::vector<base::FilePath>* result) {
result->push_back(path);
}
}
-}
+} // namespace
-DeviceManagerManual::DeviceManagerManual() : weak_ptr_factory_(this) {}
+DeviceManagerManual::DeviceManagerManual()
+ : blocking_task_runner_(
+ base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})),
+ watcher_(new base::FilePathWatcher,
+ base::OnTaskRunnerDeleter(blocking_task_runner_)),
+ weak_ptr_factory_(this) {}
-DeviceManagerManual::~DeviceManagerManual() {
-}
+DeviceManagerManual::~DeviceManagerManual() {}
void DeviceManagerManual::ScanDevices(DeviceEventObserver* observer) {
if (!is_watching_) {
@@ -58,11 +65,18 @@ void DeviceManagerManual::RemoveObserver(DeviceEventObserver* observer) {
}
void DeviceManagerManual::StartWatching() {
- if (!watcher_.Watch(base::FilePath(kDevInput), false,
- base::BindRepeating(&DeviceManagerManual::OnWatcherEvent,
- weak_ptr_factory_.GetWeakPtr()))) {
- LOG(ERROR) << "Failed to start FilePathWatcher";
- }
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_.get(), FROM_HERE,
+ base::BindOnce(
+ &base::FilePathWatcher::Watch, base::Unretained(watcher_.get()),
+ base::FilePath(kDevInput), false,
+ base::BindRepeating(&DeviceManagerManual::OnWatcherEventOnUiSequence,
+ base::SequencedTaskRunnerHandle::Get(),
+ weak_ptr_factory_.GetWeakPtr())),
+ base::BindOnce([](bool watch_started) {
+ if (!watch_started)
+ LOG(ERROR) << "Failed to start FilePathWatcher";
+ }));
}
void DeviceManagerManual::InitiateScanDevices() {
@@ -115,4 +129,15 @@ void DeviceManagerManual::OnWatcherEvent(const base::FilePath& path,
InitiateScanDevices();
}
+// static
+void DeviceManagerManual::OnWatcherEventOnUiSequence(
+ scoped_refptr<base::TaskRunner> ui_thread_runner,
+ base::WeakPtr<DeviceManagerManual> device_manager,
+ const base::FilePath& path,
+ bool error) {
+ ui_thread_runner->PostTask(
+ FROM_HERE, BindOnce(&DeviceManagerManual::OnWatcherEvent, device_manager,
+ path, error));
+}
+
} // namespace ui
diff --git a/chromium/ui/events/ozone/device/device_manager_manual.h b/chromium/ui/events/ozone/device/device_manager_manual.h
index 90f8a7ac498..3f432035c44 100644
--- a/chromium/ui/events/ozone/device/device_manager_manual.h
+++ b/chromium/ui/events/ozone/device/device_manager_manual.h
@@ -11,11 +11,14 @@
#include "base/files/file_path_watcher.h"
#include "base/macros.h"
#include "base/observer_list.h"
+
#include "ui/events/ozone/device/device_manager.h"
namespace base {
class FilePath;
-}
+class SequencedTaskRunner;
+struct OnTaskRunnerDeleter;
+} // namespace base
namespace ui {
@@ -34,12 +37,19 @@ class DeviceManagerManual : public DeviceManager {
void InitiateScanDevices();
void OnDevicesScanned(std::vector<base::FilePath>* result);
void OnWatcherEvent(const base::FilePath& path, bool error);
+ static void OnWatcherEventOnUiSequence(
+ scoped_refptr<base::TaskRunner> ui_thread_runner,
+ base::WeakPtr<DeviceManagerManual> device_manager,
+ const base::FilePath& path,
+ bool error);
std::set<base::FilePath> devices_;
- base::FilePathWatcher watcher_;
base::ObserverList<DeviceEventObserver>::Unchecked observers_;
bool is_watching_ = false;
+ const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+ std::unique_ptr<base::FilePathWatcher, base::OnTaskRunnerDeleter> watcher_;
+
base::WeakPtrFactory<DeviceManagerManual> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DeviceManagerManual);
diff --git a/chromium/ui/events/ozone/evdev/capture_device_capabilities.py b/chromium/ui/events/ozone/evdev/capture_device_capabilities.py
index b3b3d3d716e..fd7aeee4972 100755
--- a/chromium/ui/events/ozone/evdev/capture_device_capabilities.py
+++ b/chromium/ui/events/ozone/evdev/capture_device_capabilities.py
@@ -7,6 +7,7 @@
import argparse
import ctypes
+import glob
import evdev
import os
import sys
@@ -52,11 +53,14 @@ def dump_absinfo(out, capabilities, identifier):
out.write('};\n')
-def dump_capabilities(out, dev, identifier):
+def dump_capabilities(out, dev, identifier=None):
capabilities = dev.capabilities()
has_abs = evdev.ecodes.EV_ABS in capabilities
- sysfs_path = '/sys/class/input/' + os.path.basename(dev.fn)
+ basename = os.path.basename(dev.fn)
+ sysfs_path = '/sys/class/input/' + basename
+ if not identifier:
+ identifier = 'kInputDevice_' + basename
# python-evdev is missing some features
uniq = open(sysfs_path + '/device/uniq', 'r').read().strip()
@@ -121,14 +125,20 @@ def dump_capabilities(out, dev, identifier):
def main(argv):
parser = argparse.ArgumentParser()
- parser.add_argument('device')
- parser.add_argument('identifier')
+ parser.add_argument('device', nargs='?')
+ parser.add_argument('identifier', nargs='?')
args = parser.parse_args(argv)
- dev = evdev.InputDevice(args.device)
+ if args.device:
+ devices = [args.device]
+ else:
+ devices = glob.glob('/dev/input/event*')
+
out = sys.stdout
+ for device in devices:
+ dev = evdev.InputDevice(device)
+ dump_capabilities(out, dev, args.identifier)
- dump_capabilities(out, dev, args.identifier)
return 0
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.cc b/chromium/ui/events/ozone/evdev/event_device_info.cc
index c7e5d043d03..76085ec5484 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_info.cc
@@ -73,17 +73,12 @@ bool GetDeviceName(int fd, const base::FilePath& path, std::string* name) {
return true;
}
-bool GetDeviceIdentifiers(int fd,
- const base::FilePath& path,
- uint16_t* vendor,
- uint16_t* product) {
- struct input_id evdev_id;
- if (ioctl(fd, EVIOCGID, &evdev_id) < 0) {
+bool GetDeviceIdentifiers(int fd, const base::FilePath& path, input_id* id) {
+ *id = {};
+ if (ioctl(fd, EVIOCGID, id) < 0) {
PLOG(INFO) << "Failed EVIOCGID (path=" << path.value() << ")";
return false;
}
- *vendor = evdev_id.vendor;
- *product = evdev_id.product;
return true;
}
@@ -190,17 +185,14 @@ bool EventDeviceInfo::Initialize(int fd, const base::FilePath& path) {
if (!GetDeviceName(fd, path, &name_))
return false;
- if (!GetDeviceIdentifiers(fd, path, &vendor_id_, &product_id_))
+ if (!GetDeviceIdentifiers(fd, path, &input_id_))
return false;
GetDevicePhysInfo(fd, path, &phys_);
- device_type_ = GetInputDeviceTypeFromPath(path);
-
- // TODO(spang): Implement these quirks in a better way.
- constexpr uint16_t kGoogleVendorId = 0x18d1;
- if (vendor_id_ == kGoogleVendorId && product_id_ == 0x5030)
- device_type_ = InputDeviceType::INPUT_DEVICE_INTERNAL;
+ device_type_ = GetInputDeviceTypeFromId(input_id_);
+ if (device_type_ == InputDeviceType::INPUT_DEVICE_UNKNOWN)
+ device_type_ = GetInputDeviceTypeFromPath(path);
return true;
}
@@ -267,9 +259,8 @@ void EventDeviceInfo::SetDeviceType(InputDeviceType type) {
device_type_ = type;
}
-void EventDeviceInfo::SetId(uint16_t vendor_id, uint16_t product_id) {
- vendor_id_ = vendor_id;
- product_id_ = product_id;
+void EventDeviceInfo::SetId(input_id id) {
+ input_id_ = id;
}
bool EventDeviceInfo::HasEventType(unsigned int type) const {
@@ -465,6 +456,27 @@ bool EventDeviceInfo::HasGamepad() const {
return support_gamepad_btn && !HasTablet() && !HasKeyboard();
}
+// static
+ui::InputDeviceType EventDeviceInfo::GetInputDeviceTypeFromId(input_id id) {
+ constexpr uint16_t kGoogleVendorId = 0x18d1;
+ constexpr uint16_t kHammerProductId = 0x5030;
+ if (id.bustype == BUS_USB && id.vendor == kGoogleVendorId &&
+ id.product == kHammerProductId)
+ return InputDeviceType::INPUT_DEVICE_INTERNAL;
+
+ switch (id.bustype) {
+ case BUS_I2C:
+ case BUS_I8042:
+ return ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
+ case BUS_USB:
+ return ui::InputDeviceType::INPUT_DEVICE_USB;
+ case BUS_BLUETOOTH:
+ return ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH;
+ default:
+ return ui::InputDeviceType::INPUT_DEVICE_UNKNOWN;
+ }
+}
+
EventDeviceInfo::LegacyAbsoluteDeviceType
EventDeviceInfo::ProbeLegacyAbsoluteDevice() const {
if (!HasAbsXY())
diff --git a/chromium/ui/events/ozone/evdev/event_device_info.h b/chromium/ui/events/ozone/evdev/event_device_info.h
index e7624594c05..ab7867c279b 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info.h
+++ b/chromium/ui/events/ozone/evdev/event_device_info.h
@@ -69,7 +69,7 @@ class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
void SetAbsMtSlots(unsigned int code, const std::vector<int32_t>& values);
void SetAbsMtSlot(unsigned int code, unsigned int slot, uint32_t value);
void SetDeviceType(InputDeviceType type);
- void SetId(uint16_t vendor_id, uint16_t product_id);
+ void SetId(input_id id);
// Check events this device can generate.
bool HasEventType(unsigned int type) const;
@@ -94,8 +94,9 @@ class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
// Device identification.
const std::string& name() const { return name_; }
const std::string& phys() const { return phys_; }
- uint16_t vendor_id() const { return vendor_id_; }
- uint16_t product_id() const { return product_id_; }
+ uint16_t bustype() const { return input_id_.bustype; }
+ uint16_t vendor_id() const { return input_id_.vendor; }
+ uint16_t product_id() const { return input_id_.product; }
// Check input device properties.
bool HasProp(unsigned int code) const;
@@ -147,6 +148,9 @@ class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
// The device type (internal or external.)
InputDeviceType device_type() const { return device_type_; }
+ // Determines InputDeviceType from device identification.
+ static InputDeviceType GetInputDeviceTypeFromId(input_id id);
+
private:
enum class LegacyAbsoluteDeviceType {
TOUCHPAD,
@@ -175,8 +179,7 @@ class EVENTS_OZONE_EVDEV_EXPORT EventDeviceInfo {
// Device identification.
std::string name_;
- uint16_t vendor_id_;
- uint16_t product_id_;
+ input_id input_id_ = {};
// Device evdev physical property containing the output for EVIOCGPHYS that is
// (supposed to be) stable between reboots and hotplugs.
diff --git a/chromium/ui/events/ozone/evdev/event_device_info_unittest.cc b/chromium/ui/events/ozone/evdev/event_device_info_unittest.cc
index 576c488ad6b..4248eecbe4f 100644
--- a/chromium/ui/events/ozone/evdev/event_device_info_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_info_unittest.cc
@@ -15,18 +15,7 @@
namespace ui {
-class EventDeviceInfoTest : public testing::Test {
- public:
- EventDeviceInfoTest();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EventDeviceInfoTest);
-};
-
-EventDeviceInfoTest::EventDeviceInfoTest() {
-}
-
-TEST_F(EventDeviceInfoTest, BasicUsbGamepad) {
+TEST(EventDeviceInfoTest, BasicUsbGamepad) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kXboxGamepad, &devinfo));
@@ -36,9 +25,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbGamepad) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_TRUE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicCrosKeyboard) {
+TEST(EventDeviceInfoTest, BasicCrosKeyboard) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kLinkKeyboard, &devinfo));
@@ -48,9 +39,11 @@ TEST_F(EventDeviceInfoTest, BasicCrosKeyboard) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicCrosTouchscreen) {
+TEST(EventDeviceInfoTest, BasicCrosTouchscreen) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kLinkTouchscreen, &devinfo));
@@ -60,9 +53,11 @@ TEST_F(EventDeviceInfoTest, BasicCrosTouchscreen) {
EXPECT_TRUE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicCrosTouchpad) {
+TEST(EventDeviceInfoTest, BasicCrosTouchpad) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kLinkTouchpad, &devinfo));
@@ -72,9 +67,11 @@ TEST_F(EventDeviceInfoTest, BasicCrosTouchpad) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicUsbKeyboard) {
+TEST(EventDeviceInfoTest, BasicUsbKeyboard) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kHpUsbKeyboard, &devinfo));
@@ -84,9 +81,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbKeyboard) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicUsbKeyboard_Extra) {
+TEST(EventDeviceInfoTest, BasicUsbKeyboard_Extra) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kHpUsbKeyboard_Extra, &devinfo));
@@ -96,9 +95,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbKeyboard_Extra) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicUsbMouse) {
+TEST(EventDeviceInfoTest, BasicUsbMouse) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kLogitechUsbMouse, &devinfo));
@@ -108,9 +109,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbMouse) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicUsbTouchscreen) {
+TEST(EventDeviceInfoTest, BasicUsbTouchscreen) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kMimoTouch2Touchscreen, &devinfo));
@@ -120,9 +123,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbTouchscreen) {
EXPECT_TRUE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicUsbTablet) {
+TEST(EventDeviceInfoTest, BasicUsbTablet) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kWacomIntuosPtS_Pen, &devinfo));
@@ -132,9 +137,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbTablet) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_TRUE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, BasicUsbTouchpad) {
+TEST(EventDeviceInfoTest, BasicUsbTouchpad) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kWacomIntuosPtS_Finger, &devinfo));
@@ -144,9 +151,11 @@ TEST_F(EventDeviceInfoTest, BasicUsbTouchpad) {
EXPECT_FALSE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, HybridKeyboardWithMouse) {
+TEST(EventDeviceInfoTest, HybridKeyboardWithMouse) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kLogitechTouchKeyboardK400, &devinfo));
@@ -159,7 +168,7 @@ TEST_F(EventDeviceInfoTest, HybridKeyboardWithMouse) {
EXPECT_FALSE(devinfo.HasGamepad());
}
-TEST_F(EventDeviceInfoTest, AbsoluteMouseTouchscreen) {
+TEST(EventDeviceInfoTest, AbsoluteMouseTouchscreen) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kElo_TouchSystems_2700, &devinfo));
@@ -170,9 +179,11 @@ TEST_F(EventDeviceInfoTest, AbsoluteMouseTouchscreen) {
EXPECT_TRUE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_USB, devinfo.device_type());
}
-TEST_F(EventDeviceInfoTest, OnScreenStylus) {
+TEST(EventDeviceInfoTest, OnScreenStylus) {
EventDeviceInfo devinfo;
EXPECT_TRUE(CapabilitiesToDeviceInfo(kWilsonBeachActiveStylus, &devinfo));
@@ -182,6 +193,36 @@ TEST_F(EventDeviceInfoTest, OnScreenStylus) {
EXPECT_TRUE(devinfo.HasTouchscreen());
EXPECT_FALSE(devinfo.HasTablet());
EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
+}
+
+TEST(EventDeviceInfoTest, HammerKeyboard) {
+ EventDeviceInfo devinfo;
+ EXPECT_TRUE(CapabilitiesToDeviceInfo(kHammerKeyboard, &devinfo));
+
+ EXPECT_TRUE(devinfo.HasKeyboard());
+ EXPECT_FALSE(devinfo.HasMouse());
+ EXPECT_FALSE(devinfo.HasTouchpad());
+ EXPECT_FALSE(devinfo.HasTouchscreen());
+ EXPECT_FALSE(devinfo.HasTablet());
+ EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
+}
+
+TEST(EventDeviceInfoTest, HammerTouchpad) {
+ EventDeviceInfo devinfo;
+ EXPECT_TRUE(CapabilitiesToDeviceInfo(kHammerTouchpad, &devinfo));
+
+ EXPECT_FALSE(devinfo.HasKeyboard());
+ EXPECT_FALSE(devinfo.HasMouse());
+ EXPECT_TRUE(devinfo.HasTouchpad());
+ EXPECT_FALSE(devinfo.HasTouchscreen());
+ EXPECT_FALSE(devinfo.HasTablet());
+ EXPECT_FALSE(devinfo.HasGamepad());
+
+ EXPECT_EQ(ui::InputDeviceType::INPUT_DEVICE_INTERNAL, devinfo.device_type());
}
} // namespace ui
diff --git a/chromium/ui/events/ozone/evdev/event_device_test_util.cc b/chromium/ui/events/ozone/evdev/event_device_test_util.cc
index e72c4e7b7e6..0d08e6a2906 100644
--- a/chromium/ui/events/ozone/evdev/event_device_test_util.cc
+++ b/chromium/ui/events/ozone/evdev/event_device_test_util.cc
@@ -81,18 +81,18 @@ bool ParseBitfield(const std::string& bitfield,
// Captured from HJC Game ZD - V gamepad.
const DeviceAbsoluteAxis kHJCGamepadAbsAxes[] = {
- {ABS_X, {128, 0, 255, 15, 0}}, {ABS_Y, {128, 0, 255, 15, 0}},
- {ABS_Z, {128, 0, 255, 15, 0}}, {ABS_RZ, {128, 0, 255, 15, 0}},
- {ABS_HAT0X, {0, -1, 1, 0, 0}}, {ABS_HAT0Y, {0, 1, 1, 0, 0}}};
-
+ {ABS_X, {0, 0, 255, 0, 15, 0}}, {ABS_Y, {0, 0, 255, 0, 15, 0}},
+ {ABS_Z, {0, 0, 255, 0, 15, 0}}, {ABS_RZ, {0, 0, 255, 0, 15, 0}},
+ {ABS_HAT0X, {0, -1, 1, 0, 0, 0}}, {ABS_HAT0Y, {0, -1, 1, 0, 0, 0}},
+};
const DeviceCapabilities kHJCGamepad = {
/* path */
- "/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2/1-2.2:1.0/"
- "input/input38/event11",
+ "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/"
+ "0003:11C5:5506.0005/input/input11/event8",
/* name */ "HJC Game ZD - V",
- /* phys */ "usb-0000:00:14.0-2.2/input0",
+ /* phys */ "usb-0000:00:14.0-1/input0",
/* uniq */ "",
- /* bustype */ "0011",
+ /* bustype */ "0003",
/* vendor */ "11c5",
/* product */ "5506",
/* version */ "0111",
@@ -111,23 +111,22 @@ const DeviceCapabilities kHJCGamepad = {
// Captured from Xbox 360 gamepad.
const DeviceAbsoluteAxis kXboxGamepadAbsAxes[] = {
- {ABS_X, {0, -32768, 32767, 16, 128}},
- {ABS_Y, {0, -32768, 32767, 16, 128}},
- {ABS_Z, {0, 0, 255, 0, 0}},
- {ABS_RX, {0, -32768, 32767, 16, 128}},
- {ABS_RY, {0, -32768, 32767, 16, 128}},
- {ABS_RZ, {0, 0, 255, 0, 0}},
- {ABS_HAT0X, {0, -1, 1, 0, 0}},
- {ABS_HAT0Y, {0, -1, 1, 0, 0}}};
-
+ {ABS_X, {0, -32768, 32767, 16, 128, 0}},
+ {ABS_Y, {0, -32768, 32767, 16, 128, 0}},
+ {ABS_Z, {0, 0, 255, 0, 0, 0}},
+ {ABS_RX, {0, -32768, 32767, 16, 128, 0}},
+ {ABS_RY, {0, -32768, 32767, 16, 128, 0}},
+ {ABS_RZ, {0, 0, 255, 0, 0, 0}},
+ {ABS_HAT0X, {0, -1, 1, 0, 0, 0}},
+ {ABS_HAT0Y, {0, -1, 1, 0, 0, 0}},
+};
const DeviceCapabilities kXboxGamepad = {
/* path */
- "/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2/1-2.2:1.0/"
- "input/input38/event11",
+ "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/input/input9/event8",
/* name */ "Microsoft X-Box 360 pad",
- /* phys */ "usb-0000:00:14.0-2.2/input0",
+ /* phys */ "usb-0000:00:14.0-1/input0",
/* uniq */ "",
- /* bustype */ "0011",
+ /* bustype */ "0003",
/* vendor */ "045e",
/* product */ "028e",
/* version */ "0114",
@@ -139,24 +138,24 @@ const DeviceCapabilities kXboxGamepad = {
/* msc */ "0",
/* sw */ "0",
/* led */ "0",
- /* ff */ "0",
+ /* ff */ "107030000 0",
kXboxGamepadAbsAxes,
arraysize(kXboxGamepadAbsAxes),
};
// Captured from iBuffalo gamepad.
const DeviceAbsoluteAxis kiBuffaloGamepadAbsAxes[] = {
- {ABS_X, {128, 0, 255, 0, 15}},
- {ABS_Y, {128, 0, 255, 0, 15}}};
-
+ {ABS_X, {0, 0, 255, 0, 15, 0}},
+ {ABS_Y, {0, 0, 255, 0, 15, 0}},
+};
const DeviceCapabilities kiBuffaloGamepad = {
/* path */
- "/devices/pci0000:00/0000:00:14.0/usb3/3-14/3-14:1.0/0003:0583:2060.0011/"
- "input/input30/event14",
- /* name */ "USB,2-axis 8-button gamepad",
- /* phys */ "usb-0000:00:14.0-14/input0",
+ "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/"
+ "1-1:1.0/0003:0583:2060.0004/input/input10/event8",
+ /* name */ "USB,2-axis 8-button gamepad ",
+ /* phys */ "usb-0000:00:14.0-1/input0",
/* uniq */ "",
- /* bustype */ "0011",
+ /* bustype */ "0003",
/* vendor */ "0583",
/* product */ "2060",
/* version */ "0110",
@@ -175,8 +174,8 @@ const DeviceCapabilities kiBuffaloGamepad = {
// Captured from Pixelbook.
const DeviceAbsoluteAxis kEveTouchScreenAbsAxes[] = {
- {ABS_X, {4624, 0, 10368, 0, 0, 40}},
- {ABS_Y, {2177, 0, 6912, 0, 0, 40}},
+ {ABS_X, {0, 0, 10368, 0, 0, 40}},
+ {ABS_Y, {0, 0, 6912, 0, 0, 40}},
{ABS_PRESSURE, {0, 0, 255, 0, 0, 0}},
{ABS_MT_SLOT, {0, 0, 9, 0, 0, 0}},
{ABS_MT_TOUCH_MAJOR, {0, 0, 255, 0, 0, 1}},
@@ -184,9 +183,10 @@ const DeviceAbsoluteAxis kEveTouchScreenAbsAxes[] = {
{ABS_MT_ORIENTATION, {0, 0, 1, 0, 0, 0}},
{ABS_MT_POSITION_X, {0, 0, 10368, 0, 0, 40}},
{ABS_MT_POSITION_Y, {0, 0, 6912, 0, 0, 40}},
- {ABS_MT_TOOL_TYPE, {0, 0, 2, 0, 0}},
- {ABS_MT_PRESSURE, {0, 0, 255, 0, 0, 0}}};
-
+ {ABS_MT_TOOL_TYPE, {0, 0, 2, 0, 0, 0}},
+ {ABS_MT_TRACKING_ID, {0, 0, 65535, 0, 0, 0}},
+ {ABS_MT_PRESSURE, {0, 0, 255, 0, 0, 0}},
+};
const DeviceCapabilities kEveTouchScreen = {
/* path */
"/sys/devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/"
@@ -627,19 +627,76 @@ const DeviceCapabilities kEveStylus = {
arraysize(kEveStylusAbsAxes),
};
-ui::InputDeviceType InputDeviceTypeFromBusType(int bustype) {
- switch (bustype) {
- case BUS_I8042:
- case BUS_I2C:
- return ui::InputDeviceType::INPUT_DEVICE_INTERNAL;
- case BUS_USB:
- case 0x1D: // Used in kLogitechTouchKeyboardK400 but not listed in input.h.
- return ui::InputDeviceType::INPUT_DEVICE_USB;
- default:
- NOTREACHED() << "Unexpected bus type";
- return ui::InputDeviceType::INPUT_DEVICE_UNKNOWN;
- }
-}
+const DeviceCapabilities kHammerKeyboard = {
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/0003:18D1:5030.0002/"
+ "input/input10/event9",
+ /* name */ "Google Inc. Hammer",
+ /* phys */ "usb-0000:00:14.0-7/input0",
+ /* uniq */ "410020000d57345436313920",
+ /* bustype */ "0003",
+ /* vendor */ "18d1",
+ /* product */ "5030",
+ /* version */ "0100",
+ /* prop */ "0",
+ /* ev */ "100013",
+ /* key */
+ "88 0 0 0 0 0 1000000000007 ff000000000007ff febeffdfffefffff "
+ "fffffffffffffffe",
+ /* rel */ "0",
+ /* abs */ "0",
+ /* msc */ "10",
+ /* sw */ "0",
+ /* led */ "0",
+ /* ff */ "0",
+};
+
+const DeviceAbsoluteAxis kHammerTouchpadAbsAxes[] = {
+ {ABS_X, {0, 0, 2160, 0, 0, 21}},
+ {ABS_Y, {0, 0, 1080, 0, 0, 14}},
+ {ABS_PRESSURE, {0, 0, 255, 0, 0, 0}},
+ {ABS_MT_SLOT, {0, 0, 9, 0, 0, 0}},
+ {ABS_MT_TOUCH_MAJOR, {0, 0, 255, 0, 0, 3}},
+ {ABS_MT_TOUCH_MINOR, {0, 0, 255, 0, 0, 3}},
+ {ABS_MT_ORIENTATION, {0, 0, 1, 0, 0, 0}},
+ {ABS_MT_POSITION_X, {0, 0, 2160, 0, 0, 21}},
+ {ABS_MT_POSITION_Y, {0, 0, 1080, 0, 0, 14}},
+ {ABS_MT_TRACKING_ID, {0, 0, 65535, 0, 0, 0}},
+ {ABS_MT_PRESSURE, {0, 0, 255, 0, 0, 0}},
+};
+const DeviceCapabilities kHammerTouchpad = {
+ /* path */
+ "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.2/0003:18D1:5030.0003/"
+ "input/input11/event10",
+ /* name */ "Google Inc. Hammer Touchpad",
+ /* phys */ "usb-0000:00:14.0-7/input2",
+ /* uniq */ "410020000d57345436313920",
+ /* bustype */ "0003",
+ /* vendor */ "18d1",
+ /* product */ "5030",
+ /* version */ "0100",
+ /* prop */ "5",
+ /* ev */ "1b",
+ /* key */ "e520 10000 0 0 0 0",
+ /* rel */ "0",
+ /* abs */ "673800001000003",
+ /* msc */ "20",
+ /* sw */ "0",
+ /* led */ "0",
+ /* ff */ "0",
+ kHammerTouchpadAbsAxes,
+ arraysize(kHammerTouchpadAbsAxes),
+};
+
+// NB: Please use the capture_device_capabilities.py script to add more
+// test data here. This will help ensure the data matches what the kernel
+// reports for a real device and is entered correctly.
+//
+// For Chrome OS, you can run the script by installing a test image and running:
+// DEVICE_IP=<your device IP>
+// cd ui/events/ozone/evdev/
+// scp capture_device_capabilities.py "root@${DEVICE_IP}:/tmp/"
+// ssh "root@${DEVICE_IP}" /tmp/capture_device_capabilities.py
bool CapabilitiesToDeviceInfo(const DeviceCapabilities& capabilities,
EventDeviceInfo* devinfo) {
@@ -695,17 +752,14 @@ bool CapabilitiesToDeviceInfo(const DeviceCapabilities& capabilities,
devinfo->SetAbsMtSlots(code, zero_slots);
}
- int bustype = 0;
- sscanf(capabilities.bustype, "%x", &bustype);
- devinfo->SetDeviceType(InputDeviceTypeFromBusType(bustype));
-
- int vendor_id = 0;
- int product_id = 0;
+ input_id id = {};
+ sscanf(capabilities.vendor, "%" SCNx16, &id.vendor);
+ sscanf(capabilities.product, "%" SCNx16, &id.product);
+ sscanf(capabilities.bustype, "%" SCNx16, &id.bustype);
+ sscanf(capabilities.version, "%" SCNx16, &id.version);
+ devinfo->SetId(id);
+ devinfo->SetDeviceType(EventDeviceInfo::GetInputDeviceTypeFromId(id));
- sscanf(capabilities.vendor, "%x", &vendor_id);
- sscanf(capabilities.product, "%x", &product_id);
- devinfo->SetId(static_cast<uint16_t>(vendor_id),
- static_cast<uint16_t>(product_id));
return true;
}
diff --git a/chromium/ui/events/ozone/evdev/event_device_test_util.h b/chromium/ui/events/ozone/evdev/event_device_test_util.h
index ee075ec7831..00eb3479c7e 100644
--- a/chromium/ui/events/ozone/evdev/event_device_test_util.h
+++ b/chromium/ui/events/ozone/evdev/event_device_test_util.h
@@ -77,6 +77,8 @@ extern const DeviceCapabilities kLogitechTouchKeyboardK400;
extern const DeviceCapabilities kElo_TouchSystems_2700;
extern const DeviceCapabilities kWilsonBeachActiveStylus;
extern const DeviceCapabilities kEveStylus;
+extern const DeviceCapabilities kHammerKeyboard;
+extern const DeviceCapabilities kHammerTouchpad;
} // namspace ui
diff --git a/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc b/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
index c12adbcc9a3..3cb9f5dc11e 100644
--- a/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
+++ b/chromium/ui/events/ozone/evdev/gamepad_event_converter_evdev_unittest.cc
@@ -188,49 +188,90 @@ TEST_F(GamepadEventConverterEvdevTest, iBuffaloGamepadEvents) {
CreateDevice(kiBuffaloGamepad);
struct input_event mock_kernel_queue[] = {
- {{1493141044, 176725}, EV_MSC, 4, 90002},
- {{1493141044, 176725}, EV_KEY, 289, 1},
- {{1493141044, 176725}, EV_SYN, SYN_REPORT},
- {{1493141044, 256722}, EV_MSC, 4, 90002},
- {{1493141044, 256722}, EV_KEY, 289, 0},
- {{1493141044, 256722}, EV_SYN, SYN_REPORT},
- {{1493141044, 400713}, EV_MSC, 4, 90001},
- {{1493141044, 400713}, EV_KEY, 288, 1},
- {{1493141044, 400713}, EV_SYN, SYN_REPORT},
- {{1493141044, 480725}, EV_MSC, 4, 90001},
- {{1493141044, 480725}, EV_KEY, 288, 0},
- {{1493141044, 480725}, EV_SYN, SYN_REPORT},
- {{1493141044, 704716}, EV_MSC, 4, 90003},
- {{1493141044, 704716}, EV_KEY, 290, 1},
- {{1493141044, 704716}, EV_SYN, SYN_REPORT},
- {{1493141044, 768721}, EV_MSC, 4, 90003},
- {{1493141044, 768721}, EV_KEY, 290, 0},
- {{1493141044, 768721}, EV_SYN, SYN_REPORT},
- {{1493141044, 960715}, EV_MSC, 4, 90004},
- {{1493141044, 960715}, EV_KEY, 291, 1},
- {{1493141044, 960715}, EV_SYN, SYN_REPORT},
- {{1493141045, 48714}, EV_MSC, 4, 90004},
- {{1493141045, 48714}, EV_KEY, 291, 0},
- {{1493141045, 48714}, EV_SYN, SYN_REPORT},
- {{1493141046, 520730}, EV_ABS, 1, 255},
- {{1493141046, 520730}, EV_SYN, SYN_REPORT},
- {{1493141046, 648727}, EV_ABS, 1, 128},
- {{1493141046, 648727}, EV_SYN, SYN_REPORT},
- {{1493141046, 848730}, EV_ABS, 1, 0},
- {{1493141046, 848730}, EV_SYN, SYN_REPORT},
- {{1493141046, 992726}, EV_ABS, 1, 128},
- {{1493141046, 992726}, EV_SYN, SYN_REPORT},
- {{1493141047, 224727}, EV_ABS, 0, 0},
- {{1493141047, 224727}, EV_SYN, SYN_REPORT},
- {{1493141047, 344724}, EV_ABS, 0, 128},
- {{1493141047, 344724}, EV_SYN, SYN_REPORT},
- {{1493141047, 552720}, EV_ABS, 0, 255},
- {{1493141047, 552720}, EV_SYN, SYN_REPORT},
- {{1493141047, 696726}, EV_ABS, 0, 128},
- {{1493141047, 696726}, EV_SYN, SYN_REPORT},
- {{1493141047, 920727}, EV_MSC, 4, 90006},
- {{1493141047, 920727}, EV_KEY, 293, 1},
- {{1493141047, 920727}, EV_SYN, SYN_REPORT},
+ {{1539898801, 229742}, EV_MSC, MSC_SCAN, 589825},
+ {{1539898801, 229742}, EV_KEY, BTN_JOYSTICK, 1},
+ {{1539898801, 229742}, EV_SYN, SYN_REPORT, 0},
+ {{1539898801, 309742}, EV_MSC, MSC_SCAN, 589825},
+ {{1539898801, 309742}, EV_KEY, BTN_JOYSTICK, 0},
+ {{1539898801, 309742}, EV_SYN, SYN_REPORT, 0},
+ {{1539898802, 453726}, EV_MSC, MSC_SCAN, 589826},
+ {{1539898802, 453726}, EV_KEY, BTN_THUMB, 1},
+ {{1539898802, 453726}, EV_SYN, SYN_REPORT, 0},
+ {{1539898802, 517580}, EV_MSC, MSC_SCAN, 589826},
+ {{1539898802, 517580}, EV_KEY, BTN_THUMB, 0},
+ {{1539898802, 517580}, EV_SYN, SYN_REPORT, 0},
+ {{1539898803, 949749}, EV_MSC, MSC_SCAN, 589827},
+ {{1539898803, 949749}, EV_KEY, BTN_THUMB2, 1},
+ {{1539898803, 949749}, EV_SYN, SYN_REPORT, 0},
+ {{1539898803, 997741}, EV_MSC, MSC_SCAN, 589827},
+ {{1539898803, 997741}, EV_KEY, BTN_THUMB2, 0},
+ {{1539898803, 997741}, EV_SYN, SYN_REPORT, 0},
+ {{1539898805, 397581}, EV_MSC, MSC_SCAN, 589828},
+ {{1539898805, 397581}, EV_KEY, BTN_TOP, 1},
+ {{1539898805, 397581}, EV_SYN, SYN_REPORT, 0},
+ {{1539898805, 461689}, EV_MSC, MSC_SCAN, 589828},
+ {{1539898805, 461689}, EV_KEY, BTN_TOP, 0},
+ {{1539898805, 461689}, EV_SYN, SYN_REPORT, 0},
+ {{1539898806, 429752}, EV_MSC, MSC_SCAN, 589829},
+ {{1539898806, 429752}, EV_KEY, BTN_TOP2, 1},
+ {{1539898806, 429752}, EV_SYN, SYN_REPORT, 0},
+ {{1539898806, 589760}, EV_MSC, MSC_SCAN, 589829},
+ {{1539898806, 589760}, EV_KEY, BTN_TOP2, 0},
+ {{1539898806, 589760}, EV_SYN, SYN_REPORT, 0},
+ {{1539898807, 309762}, EV_MSC, MSC_SCAN, 589830},
+ {{1539898807, 309762}, EV_KEY, BTN_PINKIE, 1},
+ {{1539898807, 309762}, EV_SYN, SYN_REPORT, 0},
+ {{1539898807, 381640}, EV_MSC, MSC_SCAN, 589830},
+ {{1539898807, 381640}, EV_KEY, BTN_PINKIE, 0},
+ {{1539898807, 381640}, EV_SYN, SYN_REPORT, 0},
+ {{1539898808, 925751}, EV_MSC, MSC_SCAN, 589831},
+ {{1539898808, 925751}, EV_KEY, BTN_BASE, 1},
+ {{1539898808, 925751}, EV_SYN, SYN_REPORT, 0},
+ {{1539898809, 13752}, EV_MSC, MSC_SCAN, 589831},
+ {{1539898809, 13752}, EV_KEY, BTN_BASE, 0},
+ {{1539898809, 13752}, EV_SYN, SYN_REPORT, 0},
+ {{1539898810, 285649}, EV_MSC, MSC_SCAN, 589832},
+ {{1539898810, 285649}, EV_KEY, BTN_BASE2, 1},
+ {{1539898810, 285649}, EV_SYN, SYN_REPORT, 0},
+ {{1539898810, 397761}, EV_MSC, MSC_SCAN, 589832},
+ {{1539898810, 397761}, EV_KEY, BTN_BASE2, 0},
+ {{1539898810, 397761}, EV_SYN, SYN_REPORT, 0},
+ {{1539898818, 53678}, EV_ABS, ABS_Y, 128},
+ {{1539898818, 53678}, EV_SYN, SYN_REPORT, 0},
+ {{1539898818, 141760}, EV_ABS, ABS_Y, 127},
+ {{1539898818, 141760}, EV_SYN, SYN_REPORT, 0},
+ {{1539898818, 149780}, EV_ABS, ABS_Y, 128},
+ {{1539898818, 149780}, EV_SYN, SYN_REPORT, 0},
+ {{1539898818, 229671}, EV_ABS, ABS_Y, 255},
+ {{1539898818, 229671}, EV_SYN, SYN_REPORT, 0},
+ {{1539898820, 541685}, EV_ABS, ABS_X, 128},
+ {{1539898820, 541685}, EV_SYN, SYN_REPORT, 0},
+ {{1539898820, 597795}, EV_ABS, ABS_X, 127},
+ {{1539898820, 597795}, EV_SYN, SYN_REPORT, 0},
+ {{1539898820, 605799}, EV_ABS, ABS_X, 128},
+ {{1539898820, 605799}, EV_SYN, SYN_REPORT, 0},
+ {{1539898820, 685800}, EV_ABS, ABS_X, 127},
+ {{1539898820, 685800}, EV_SYN, SYN_REPORT, 0},
+ {{1539898820, 693792}, EV_ABS, ABS_X, 128},
+ {{1539898820, 693792}, EV_SYN, SYN_REPORT, 0},
+ {{1539898820, 725788}, EV_ABS, ABS_X, 255},
+ {{1539898820, 725788}, EV_SYN, SYN_REPORT, 0},
+ {{1539898823, 333802}, EV_ABS, ABS_Y, 128},
+ {{1539898823, 333802}, EV_SYN, SYN_REPORT, 0},
+ {{1539898823, 469796}, EV_ABS, ABS_Y, 0},
+ {{1539898823, 469796}, EV_SYN, SYN_REPORT, 0},
+ {{1539898823, 789788}, EV_ABS, ABS_X, 128},
+ {{1539898823, 789788}, EV_SYN, SYN_REPORT, 0},
+ {{1539898824, 501696}, EV_ABS, ABS_X, 255},
+ {{1539898824, 501696}, EV_SYN, SYN_REPORT, 0},
+ {{1539898824, 949713}, EV_ABS, ABS_X, 128},
+ {{1539898824, 949713}, EV_SYN, SYN_REPORT, 0},
+ {{1539898825, 45805}, EV_ABS, ABS_X, 0},
+ {{1539898825, 45805}, EV_SYN, SYN_REPORT, 0},
+ {{1539898825, 133800}, EV_ABS, ABS_Y, 128},
+ {{1539898825, 133800}, EV_SYN, SYN_REPORT, 0},
+ {{1539898825, 189693}, EV_ABS, ABS_Y, 255},
+ {{1539898825, 189693}, EV_SYN, SYN_REPORT, 0},
};
// Advance test tick clock so the above events are strictly in the past.
@@ -238,23 +279,32 @@ TEST_F(GamepadEventConverterEvdevTest, iBuffaloGamepadEvents) {
clock.SetNowSeconds(1493141048);
struct ExpectedEvent expected_events[] = {
- {GamepadEventType::BUTTON, 1, 1}, {GamepadEventType::FRAME, 0, 0},
- {GamepadEventType::BUTTON, 1, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 0, 1}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 0, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 1, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 1, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 2, 1}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 2, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 3, 1}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 3, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 6, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 6, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 7, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 7, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 4, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 4, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 5, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 5, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 13, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 15, 1}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 13, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 12, 1}, {GamepadEventType::FRAME, 0, 0},
- {GamepadEventType::BUTTON, 12, 0}, {GamepadEventType::FRAME, 0, 0},
- {GamepadEventType::BUTTON, 14, 1}, {GamepadEventType::FRAME, 0, 0},
- {GamepadEventType::BUTTON, 14, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 15, 0}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 15, 1}, {GamepadEventType::FRAME, 0, 0},
{GamepadEventType::BUTTON, 15, 0}, {GamepadEventType::FRAME, 0, 0},
- {GamepadEventType::BUTTON, 7, 1}, {GamepadEventType::FRAME, 0, 0}};
+ {GamepadEventType::BUTTON, 14, 1}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 12, 0}, {GamepadEventType::FRAME, 0, 0},
+ {GamepadEventType::BUTTON, 13, 1}, {GamepadEventType::FRAME, 0, 0}};
for (unsigned i = 0; i < arraysize(mock_kernel_queue); ++i) {
dev->ProcessEvent(mock_kernel_queue[i]);
diff --git a/chromium/ui/events/ozone/keyboard_hook_ozone.cc b/chromium/ui/events/ozone/keyboard_hook_ozone.cc
index 04a190a3ed0..991b7d720d9 100644
--- a/chromium/ui/events/ozone/keyboard_hook_ozone.cc
+++ b/chromium/ui/events/ozone/keyboard_hook_ozone.cc
@@ -46,7 +46,7 @@ bool KeyboardHookOzone::Register() {
} // namespace
// static
-std::unique_ptr<KeyboardHook> KeyboardHook::Create(
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
base::Optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget,
KeyEventCallback callback) {
@@ -60,4 +60,10 @@ std::unique_ptr<KeyboardHook> KeyboardHook::Create(
return keyboard_hook;
}
+// static
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateMediaKeyboardHook(
+ KeyEventCallback callback) {
+ return nullptr;
+}
+
} // namespace ui
diff --git a/chromium/ui/events/platform/x11/x11_event_source.cc b/chromium/ui/events/platform/x11/x11_event_source.cc
index a68188d77dc..7e9f6df4762 100644
--- a/chromium/ui/events/platform/x11/x11_event_source.cc
+++ b/chromium/ui/events/platform/x11/x11_event_source.cc
@@ -100,7 +100,6 @@ X11EventSource::X11EventSource(X11EventSourceDelegate* delegate,
distribution_(0, 999) {
DCHECK(!instance_);
instance_ = this;
- SetTimestampServer(this);
DCHECK(delegate_);
DCHECK(display_);
@@ -111,7 +110,6 @@ X11EventSource::X11EventSource(X11EventSourceDelegate* delegate,
X11EventSource::~X11EventSource() {
DCHECK_EQ(this, instance_);
instance_ = nullptr;
- SetTimestampServer(nullptr);
if (dummy_initialized_)
XDestroyWindow(display_, dummy_window_);
}
diff --git a/chromium/ui/events/platform/x11/x11_event_source.h b/chromium/ui/events/platform/x11/x11_event_source.h
index c2ee795b68f..e818c4acfa8 100644
--- a/chromium/ui/events/platform/x11/x11_event_source.h
+++ b/chromium/ui/events/platform/x11/x11_event_source.h
@@ -14,7 +14,6 @@
#include "base/optional.h"
#include "build/build_config.h"
#include "ui/events/events_export.h"
-#include "ui/events/x/events_x_utils.h"
#include "ui/gfx/x/x11_types.h"
using Time = unsigned long;
@@ -47,7 +46,7 @@ class X11EventSourceDelegate {
// Receives X11 events and sends them to X11EventSourceDelegate. Handles
// receiving, pre-process and post-processing XEvents.
-class EVENTS_EXPORT X11EventSource : TimestampServer {
+class EVENTS_EXPORT X11EventSource {
public:
X11EventSource(X11EventSourceDelegate* delegate, XDisplay* display);
~X11EventSource();
@@ -83,7 +82,7 @@ class EVENTS_EXPORT X11EventSource : TimestampServer {
// Explicitly asks the X11 server for the current timestamp, and updates
// |last_seen_server_time_| with this value.
- Time GetCurrentServerTime() override;
+ Time GetCurrentServerTime();
protected:
// Extracts cookie data from |xevent| if it's of GenericType, and dispatches
diff --git a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
index e8edd738938..6d6b14f51a0 100644
--- a/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
+++ b/chromium/ui/events/platform/x11/x11_hotplug_event_handler.cc
@@ -19,7 +19,7 @@
#include "base/process/launch.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/events/devices/device_data_manager.h"
diff --git a/chromium/ui/events/win/events_win_utils.cc b/chromium/ui/events/win/events_win_utils.cc
index 4025b905b62..fba2f13eb82 100644
--- a/chromium/ui/events/win/events_win_utils.cc
+++ b/chromium/ui/events/win/events_win_utils.cc
@@ -3,12 +3,12 @@
// found in the LICENSE file.
#include <stdint.h>
-#include <windowsx.h>
#include "ui/events/event_constants.h"
#include "base/logging.h"
#include "base/time/time.h"
+#include "base/win/windowsx_shim.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
diff --git a/chromium/ui/events/win/keyboard_hook_win.h b/chromium/ui/events/win/keyboard_hook_win.h
deleted file mode 100644
index 627ba313b17..00000000000
--- a/chromium/ui/events/win/keyboard_hook_win.h
+++ /dev/null
@@ -1,52 +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_EVENTS_WIN_KEYBOARD_HOOK_WIN_H_
-#define UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_H_
-
-#include <memory>
-
-#include <windows.h>
-
-#include "base/containers/flat_set.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/optional.h"
-#include "ui/events/event.h"
-#include "ui/events/events_export.h"
-#include "ui/events/keyboard_hook_base.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-
-namespace ui {
-
-// Exposes a method to drive the Windows KeyboardHook implementation by feeding
-// it key event data. This method is used by both the low-level keyboard hook
-// and by unit tests which simulate the hooked behavior w/o actually installing
-// a hook (doing so would cause problems with test parallelization).
-class EVENTS_EXPORT KeyboardHookWin : public KeyboardHookBase {
- public:
- KeyboardHookWin(base::Optional<base::flat_set<DomCode>> dom_codes,
- KeyEventCallback callback);
- ~KeyboardHookWin() override;
-
- // Create a KeyboardHookWin instance which does not register a low-level hook.
- static std::unique_ptr<KeyboardHookWin> CreateForTesting(
- base::Optional<base::flat_set<DomCode>> dom_codes,
- KeyEventCallback callback);
-
- // Called when a key event message is delivered via the low-level hook.
- // Exposed here to allow for testing w/o engaging the low-level hook.
- // Returns true if the message was handled.
- virtual bool ProcessKeyEventMessage(WPARAM w_param,
- DWORD vk,
- DWORD scan_code,
- DWORD time_stamp) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(KeyboardHookWin);
-};
-
-} // namespace ui
-
-#endif // UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_H_
diff --git a/chromium/ui/events/win/keyboard_hook_win_base.cc b/chromium/ui/events/win/keyboard_hook_win_base.cc
new file mode 100644
index 00000000000..1841b06dcf9
--- /dev/null
+++ b/chromium/ui/events/win/keyboard_hook_win_base.cc
@@ -0,0 +1,81 @@
+// 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/events/win/keyboard_hook_win_base.h"
+
+namespace ui {
+
+KeyboardHookWinBase::KeyboardHookWinBase(
+ base::Optional<base::flat_set<DomCode>> dom_codes,
+ KeyEventCallback callback,
+ bool enable_hook_registration)
+ : KeyboardHookBase(std::move(dom_codes), std::move(callback)),
+ enable_hook_registration_(enable_hook_registration) {}
+
+KeyboardHookWinBase::~KeyboardHookWinBase() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (!enable_hook_registration_)
+ return;
+
+ if (!UnhookWindowsHookEx(hook_))
+ DPLOG(ERROR) << "UnhookWindowsHookEx failed";
+}
+
+bool KeyboardHookWinBase::Register(HOOKPROC hook_proc) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // If the hook was created for testing, |Register()| should not be called.
+ DCHECK(enable_hook_registration_);
+
+ DCHECK(!hook_);
+
+ // Don't register hooks when there is a debugger to avoid painful user input
+ // delays.
+ if (IsDebuggerPresent())
+ return false;
+
+ // Per MSDN this Hook procedure will be called in the context of the thread
+ // which installed it.
+ hook_ = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc,
+ /*hMod=*/nullptr,
+ /*dwThreadId=*/0);
+ DPLOG_IF(ERROR, !hook_) << "SetWindowsHookEx failed";
+
+ return hook_ != nullptr;
+}
+
+// static
+LRESULT CALLBACK
+KeyboardHookWinBase::ProcessKeyEvent(KeyboardHookWinBase* instance,
+ int code,
+ WPARAM w_param,
+ LPARAM l_param) {
+ // If there is an error unhooking, this method could be called with a null
+ // |instance_|. Ensure we have a valid instance and that |code| is correct
+ // before proceeding.
+ if (!instance || code != HC_ACTION)
+ return CallNextHookEx(nullptr, code, w_param, l_param);
+
+ DCHECK_CALLED_ON_VALID_THREAD(instance->thread_checker_);
+
+ KBDLLHOOKSTRUCT* ll_hooks = reinterpret_cast<KBDLLHOOKSTRUCT*>(l_param);
+
+ // This vkey represents both a vkey and a location on the keyboard such as
+ // VK_LCONTROL or VK_RCONTROL.
+ DWORD vk = ll_hooks->vkCode;
+
+ // Apply the extended flag prior to passing |scan_code| since |instance_| does
+ // not have access to the low-level hook flags.
+ DWORD scan_code = ll_hooks->scanCode;
+ if (ll_hooks->flags & LLKHF_EXTENDED)
+ scan_code |= 0xE000;
+
+ if (instance->ProcessKeyEventMessage(w_param, vk, scan_code, ll_hooks->time))
+ return 1;
+
+ return CallNextHookEx(nullptr, code, w_param, l_param);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/win/keyboard_hook_win_base.h b/chromium/ui/events/win/keyboard_hook_win_base.h
new file mode 100644
index 00000000000..c9da794ae06
--- /dev/null
+++ b/chromium/ui/events/win/keyboard_hook_win_base.h
@@ -0,0 +1,74 @@
+// 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_EVENTS_WIN_KEYBOARD_HOOK_WIN_BASE_H_
+#define UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_BASE_H_
+
+#include <memory>
+
+#include <windows.h>
+
+#include "base/containers/flat_set.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/threading/thread_checker.h"
+#include "ui/events/event.h"
+#include "ui/events/events_export.h"
+#include "ui/events/keyboard_hook_base.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+
+namespace ui {
+
+// Exposes a method to drive the Windows KeyboardHook implementation by feeding
+// it key event data. This method is used by both the low-level keyboard hook
+// and by unit tests which simulate the hooked behavior w/o actually installing
+// a hook (doing so would cause problems with test parallelization).
+class EVENTS_EXPORT KeyboardHookWinBase : public KeyboardHookBase {
+ public:
+ KeyboardHookWinBase(base::Optional<base::flat_set<DomCode>> dom_codes,
+ KeyEventCallback callback,
+ bool enable_hook_registration);
+ ~KeyboardHookWinBase() override;
+
+ // Create a KeyboardHookWinBase instance which does not register a
+ // low-level hook and captures modifier keys.
+ static std::unique_ptr<KeyboardHookWinBase>
+ CreateModifierKeyboardHookForTesting(
+ base::Optional<base::flat_set<DomCode>> dom_codes,
+ KeyEventCallback callback);
+
+ // Create a KeyboardHookWinBase instance which does not register a
+ // low-level hook and captures media keys.
+ static std::unique_ptr<KeyboardHookWinBase> CreateMediaKeyboardHookForTesting(
+ KeyEventCallback callback);
+
+ // Called when a key event message is delivered via the low-level hook.
+ // Exposed here to allow for testing w/o engaging the low-level hook.
+ // Returns true if the message was handled.
+ virtual bool ProcessKeyEventMessage(WPARAM w_param,
+ DWORD vk,
+ DWORD scan_code,
+ DWORD time_stamp) = 0;
+
+ protected:
+ bool Register(HOOKPROC hook_proc);
+ bool enable_hook_registration() const { return enable_hook_registration_; }
+
+ static LRESULT CALLBACK ProcessKeyEvent(KeyboardHookWinBase* instance,
+ int code,
+ WPARAM w_param,
+ LPARAM l_param);
+
+ private:
+ const bool enable_hook_registration_ = true;
+ HHOOK hook_ = nullptr;
+ THREAD_CHECKER(thread_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(KeyboardHookWinBase);
+};
+
+} // namespace ui
+
+#endif // UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_BASE_H_
diff --git a/chromium/ui/events/win/media_keyboard_hook_win.cc b/chromium/ui/events/win/media_keyboard_hook_win.cc
new file mode 100644
index 00000000000..141ac572cd7
--- /dev/null
+++ b/chromium/ui/events/win/media_keyboard_hook_win.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/events/win/keyboard_hook_win_base.h"
+
+#include "ui/events/event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/win/events_win_utils.h"
+
+namespace ui {
+
+namespace {
+
+bool IsMediaKey(DWORD vk) {
+ return vk == VK_MEDIA_NEXT_TRACK || vk == VK_MEDIA_PREV_TRACK ||
+ vk == VK_MEDIA_PLAY_PAUSE || vk == VK_MEDIA_STOP;
+}
+
+class MediaKeyboardHookWinImpl : public KeyboardHookWinBase {
+ public:
+ MediaKeyboardHookWinImpl(KeyEventCallback callback,
+ bool enable_hook_registration);
+ ~MediaKeyboardHookWinImpl() override;
+
+ // KeyboardHookWinBase implementation.
+ bool ProcessKeyEventMessage(WPARAM w_param,
+ DWORD vk,
+ DWORD scan_code,
+ DWORD time_stamp) override;
+
+ bool Register();
+
+ private:
+ static LRESULT CALLBACK ProcessKeyEvent(int code,
+ WPARAM w_param,
+ LPARAM l_param);
+
+ static MediaKeyboardHookWinImpl* instance_;
+
+ // Tracks the last non-located key down seen in order to determine if the
+ // current key event should be marked as a repeated key press.
+ DWORD last_key_down_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaKeyboardHookWinImpl);
+};
+
+// static
+MediaKeyboardHookWinImpl* MediaKeyboardHookWinImpl::instance_ = nullptr;
+
+MediaKeyboardHookWinImpl::MediaKeyboardHookWinImpl(
+ KeyEventCallback callback,
+ bool enable_hook_registration)
+ : KeyboardHookWinBase(
+ base::Optional<base::flat_set<DomCode>>(
+ {DomCode::MEDIA_PLAY_PAUSE, DomCode::MEDIA_STOP,
+ DomCode::MEDIA_TRACK_NEXT, DomCode::MEDIA_TRACK_PREVIOUS}),
+ std::move(callback),
+ enable_hook_registration) {}
+
+MediaKeyboardHookWinImpl::~MediaKeyboardHookWinImpl() {
+ if (!enable_hook_registration())
+ return;
+
+ DCHECK_EQ(instance_, this);
+ instance_ = nullptr;
+}
+
+bool MediaKeyboardHookWinImpl::Register() {
+ // Only one instance of this class can be registered at a time.
+ DCHECK(!instance_);
+ instance_ = this;
+
+ return KeyboardHookWinBase::Register(
+ reinterpret_cast<HOOKPROC>(&MediaKeyboardHookWinImpl::ProcessKeyEvent));
+}
+
+// static
+LRESULT CALLBACK MediaKeyboardHookWinImpl::ProcessKeyEvent(int code,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return KeyboardHookWinBase::ProcessKeyEvent(instance_, code, w_param,
+ l_param);
+}
+
+bool MediaKeyboardHookWinImpl::ProcessKeyEventMessage(WPARAM w_param,
+ DWORD vk,
+ DWORD scan_code,
+ DWORD time_stamp) {
+ if (!IsMediaKey(vk))
+ return false;
+
+ bool is_repeat = false;
+ MSG msg = {nullptr, w_param, vk, GetLParamFromScanCode(scan_code),
+ time_stamp};
+ EventType event_type = EventTypeFromMSG(msg);
+ if (event_type == ET_KEY_PRESSED) {
+ is_repeat = (last_key_down_ == vk);
+ last_key_down_ = vk;
+ } else {
+ DCHECK_EQ(event_type, ET_KEY_RELEASED);
+ last_key_down_ = 0;
+ }
+
+ std::unique_ptr<KeyEvent> key_event =
+ std::make_unique<KeyEvent>(KeyEventFromMSG(msg));
+ if (is_repeat)
+ key_event->set_flags(key_event->flags() | EF_IS_REPEAT);
+ ForwardCapturedKeyEvent(key_event.get());
+
+ // If the event is handled, don't propagate to the OS.
+ return key_event->handled();
+}
+
+} // namespace
+
+// static
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateMediaKeyboardHook(
+ KeyEventCallback callback) {
+ std::unique_ptr<MediaKeyboardHookWinImpl> keyboard_hook =
+ std::make_unique<MediaKeyboardHookWinImpl>(
+ std::move(callback),
+ /*enable_hook_registration=*/true);
+
+ if (!keyboard_hook->Register())
+ return nullptr;
+
+ return keyboard_hook;
+}
+
+std::unique_ptr<KeyboardHookWinBase>
+KeyboardHookWinBase::CreateMediaKeyboardHookForTesting(
+ KeyEventCallback callback) {
+ return std::make_unique<MediaKeyboardHookWinImpl>(
+ std::move(callback),
+ /*enable_hook_registration=*/false);
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/win/media_keyboard_hook_win_interactive_test.cc b/chromium/ui/events/win/media_keyboard_hook_win_interactive_test.cc
new file mode 100644
index 00000000000..18a2df90466
--- /dev/null
+++ b/chromium/ui/events/win/media_keyboard_hook_win_interactive_test.cc
@@ -0,0 +1,120 @@
+// 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/events/keyboard_hook.h"
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+
+namespace ui {
+
+class MediaKeyboardHookWinInteractiveTest : public testing::Test {
+ public:
+ MediaKeyboardHookWinInteractiveTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
+
+ protected:
+ void SetUp() override {
+ keyboard_hook_ = KeyboardHook::CreateMediaKeyboardHook(base::BindRepeating(
+ &MediaKeyboardHookWinInteractiveTest::HandleKeyEvent,
+ base::Unretained(this)));
+ ASSERT_NE(nullptr, keyboard_hook_);
+ }
+
+ // Loop until we've received |num_events| key events from the hook.
+ void WaitForKeyEvents(uint32_t num_events) {
+ if (key_events_.size() >= num_events)
+ return;
+
+ num_key_events_to_wait_for_ = num_events;
+ key_event_wait_loop_.Run();
+ }
+
+ void SendKeyDown(KeyboardCode code) {
+ INPUT input;
+ input.type = INPUT_KEYBOARD;
+ input.ki.wVk = code;
+ input.ki.time = time_stamp_++;
+ input.ki.dwFlags = 0;
+ SendInput(1, &input, sizeof(INPUT));
+ }
+
+ void SendKeyUp(KeyboardCode code) {
+ INPUT input;
+ input.type = INPUT_KEYBOARD;
+ input.ki.wVk = code;
+ input.ki.time = time_stamp_++;
+ input.ki.dwFlags = KEYEVENTF_KEYUP;
+ SendInput(1, &input, sizeof(INPUT));
+ }
+
+ // Expect that we have received the correct number of key events.
+ void ExpectReceivedEventsCount(uint32_t count) {
+ EXPECT_EQ(count, key_events_.size());
+ }
+
+ // Expect that the key event received at |index| has the specified key code
+ // and type.
+ void ExpectReceivedEvent(uint32_t index, KeyboardCode code, EventType type) {
+ ASSERT_LT(index, key_events_.size());
+ KeyEvent* key_event = &key_events_.at(index);
+ EXPECT_EQ(code, key_event->key_code());
+ EXPECT_EQ(type, key_event->type());
+ }
+
+ private:
+ void HandleKeyEvent(KeyEvent* key_event) {
+ key_events_.push_back(*key_event);
+ key_event->SetHandled();
+
+ // If we've received the events we're waiting for, stop waiting.
+ if (key_event_wait_loop_.running() &&
+ key_events_.size() >= num_key_events_to_wait_for_) {
+ key_event_wait_loop_.Quit();
+ }
+ }
+
+ std::vector<KeyEvent> key_events_;
+ std::unique_ptr<KeyboardHook> keyboard_hook_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ base::RunLoop key_event_wait_loop_;
+ uint32_t num_key_events_to_wait_for_ = 0;
+ DWORD time_stamp_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaKeyboardHookWinInteractiveTest);
+};
+
+// Test that we catch the different media key events.
+TEST_F(MediaKeyboardHookWinInteractiveTest, AllMediaKeysAreCaught) {
+ SendKeyDown(ui::VKEY_MEDIA_PLAY_PAUSE);
+ SendKeyUp(ui::VKEY_MEDIA_PLAY_PAUSE);
+ SendKeyDown(ui::VKEY_MEDIA_STOP);
+ SendKeyUp(ui::VKEY_MEDIA_STOP);
+ SendKeyDown(ui::VKEY_MEDIA_NEXT_TRACK);
+ SendKeyUp(ui::VKEY_MEDIA_NEXT_TRACK);
+ SendKeyDown(ui::VKEY_MEDIA_PREV_TRACK);
+ SendKeyUp(ui::VKEY_MEDIA_PREV_TRACK);
+
+ // We should receive 8 different key events.
+ WaitForKeyEvents(8);
+}
+
+// Test that the received events have the proper state.
+TEST_F(MediaKeyboardHookWinInteractiveTest, CallbackReceivesProperEvents) {
+ // Send a key down event and validate it when received through the hook.
+ SendKeyDown(ui::VKEY_MEDIA_PLAY_PAUSE);
+ WaitForKeyEvents(1);
+ ExpectReceivedEvent(/*index=*/0, ui::VKEY_MEDIA_PLAY_PAUSE, ET_KEY_PRESSED);
+
+ // Send a key up event and validate it when received through the hook.
+ SendKeyUp(ui::VKEY_MEDIA_PLAY_PAUSE);
+ WaitForKeyEvents(2);
+ ExpectReceivedEvent(/*index=*/1, ui::VKEY_MEDIA_PLAY_PAUSE, ET_KEY_RELEASED);
+}
+
+} // namespace ui \ No newline at end of file
diff --git a/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc b/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc
new file mode 100644
index 00000000000..d0438771a84
--- /dev/null
+++ b/chromium/ui/events/win/media_keyboard_hook_win_unittest.cc
@@ -0,0 +1,206 @@
+// 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 <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event.h"
+#include "ui/events/keyboard_hook.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/win/keyboard_hook_win_base.h"
+
+namespace ui {
+
+class MediaKeyboardHookWinTest : public testing::Test {
+ public:
+ MediaKeyboardHookWinTest();
+ ~MediaKeyboardHookWinTest() override;
+
+ // testing::Test overrides.
+ void SetUp() override;
+
+ void HandleKeyPress(KeyEvent* key_event);
+
+ protected:
+ KeyboardHookWinBase* keyboard_hook() { return keyboard_hook_.get(); }
+
+ uint32_t next_time_stamp() { return time_stamp_++; }
+
+ std::vector<KeyEvent>* key_events() { return &key_events_; }
+
+ // Used for sending key events which are handled by the hook.
+ void SendMediaKeyDownEvent(KeyboardCode key_code,
+ DomCode dom_code,
+ int repeat_count = 1);
+ void SendMediaKeyUpEvent(KeyboardCode key_code, DomCode dom_code);
+
+ // Set the return value for the HandleKeyPress callback.
+ void StartHandlingKeys() { should_handle_keys_ = true; }
+ void StopHandlingKeys() { should_handle_keys_ = false; }
+
+ private:
+ uint32_t time_stamp_ = 0;
+ std::unique_ptr<KeyboardHookWinBase> keyboard_hook_;
+ std::vector<KeyEvent> key_events_;
+ bool should_handle_keys_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaKeyboardHookWinTest);
+};
+
+MediaKeyboardHookWinTest::MediaKeyboardHookWinTest() = default;
+
+MediaKeyboardHookWinTest::~MediaKeyboardHookWinTest() = default;
+
+void MediaKeyboardHookWinTest::SetUp() {
+ keyboard_hook_ = KeyboardHookWinBase::CreateMediaKeyboardHookForTesting(
+ base::BindRepeating(&MediaKeyboardHookWinTest::HandleKeyPress,
+ base::Unretained(this)));
+}
+
+void MediaKeyboardHookWinTest::HandleKeyPress(KeyEvent* key_event) {
+ key_events_.push_back(*key_event);
+ if (should_handle_keys_)
+ key_event->SetHandled();
+}
+
+void MediaKeyboardHookWinTest::SendMediaKeyDownEvent(KeyboardCode key_code,
+ DomCode dom_code,
+ int repeat_count /*=1*/) {
+ ASSERT_GT(repeat_count, 0);
+ // This should only be used when we're handling keys.
+ ASSERT_TRUE(should_handle_keys_);
+
+ for (int i = 0; i < repeat_count; i++) {
+ ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYDOWN, key_code,
+ KeycodeConverter::DomCodeToNativeKeycode(dom_code), next_time_stamp()));
+ }
+}
+
+void MediaKeyboardHookWinTest::SendMediaKeyUpEvent(KeyboardCode key_code,
+ DomCode dom_code) {
+ // This should only be used when we're handling keys.
+ ASSERT_TRUE(should_handle_keys_);
+
+ ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYUP, key_code, KeycodeConverter::DomCodeToNativeKeycode(dom_code),
+ next_time_stamp()));
+}
+
+void VerifyKeyEvent(KeyEvent* key_event,
+ KeyboardCode non_located_key_code,
+ DomCode dom_code,
+ bool key_down,
+ bool is_repeat) {
+ if (key_down) {
+ ASSERT_EQ(key_event->type(), ET_KEY_PRESSED);
+ ASSERT_EQ(key_event->is_repeat(), is_repeat);
+ } else {
+ ASSERT_EQ(key_event->type(), ET_KEY_RELEASED);
+ ASSERT_FALSE(key_event->is_repeat());
+ }
+ ASSERT_EQ(key_event->key_code(), non_located_key_code);
+ ASSERT_EQ(key_event->code(), dom_code);
+}
+
+TEST_F(MediaKeyboardHookWinTest, SimpleKeypressTest) {
+ const KeyboardCode key_code = KeyboardCode::VKEY_MEDIA_PLAY_PAUSE;
+ const DomCode dom_code = DomCode::MEDIA_PLAY_PAUSE;
+ SendMediaKeyDownEvent(key_code, dom_code);
+ ASSERT_EQ(key_events()->size(), 1u);
+ SendMediaKeyUpEvent(key_code, dom_code);
+ ASSERT_EQ(key_events()->size(), 2u);
+
+ KeyEvent down_event = key_events()->at(0);
+ ASSERT_NO_FATAL_FAILURE(
+ VerifyKeyEvent(&down_event, key_code, dom_code, true, false));
+
+ KeyEvent up_event = key_events()->at(1);
+ ASSERT_NO_FATAL_FAILURE(
+ VerifyKeyEvent(&up_event, key_code, dom_code, false, false));
+}
+
+TEST_F(MediaKeyboardHookWinTest, RepeatingKeypressTest) {
+ const int repeat_count = 10;
+ const KeyboardCode key_code = KeyboardCode::VKEY_MEDIA_PLAY_PAUSE;
+ const DomCode dom_code = DomCode::MEDIA_PLAY_PAUSE;
+ SendMediaKeyDownEvent(key_code, dom_code, repeat_count);
+ ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count);
+ SendMediaKeyUpEvent(key_code, dom_code);
+ ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1);
+
+ bool should_repeat = false;
+ for (int i = 0; i < repeat_count; i++) {
+ KeyEvent event = key_events()->at(i);
+ ASSERT_NO_FATAL_FAILURE(
+ VerifyKeyEvent(&event, key_code, dom_code, true, should_repeat));
+ should_repeat = true;
+ }
+
+ KeyEvent up_event = key_events()->at(repeat_count);
+ ASSERT_NO_FATAL_FAILURE(
+ VerifyKeyEvent(&up_event, key_code, dom_code, false, false));
+}
+
+TEST_F(MediaKeyboardHookWinTest, UnhandledKeysArePropagated) {
+ StopHandlingKeys();
+
+ // Ensure media keys are propagated to the OS.
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYDOWN, KeyboardCode::VKEY_MEDIA_STOP,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::MEDIA_STOP),
+ next_time_stamp()));
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYUP, KeyboardCode::VKEY_MEDIA_STOP,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::MEDIA_STOP),
+ next_time_stamp()));
+
+ StartHandlingKeys();
+
+ // Ensure media keys are not propagated to the OS.
+ ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYDOWN, KeyboardCode::VKEY_MEDIA_STOP,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::MEDIA_STOP),
+ next_time_stamp()));
+ ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYUP, KeyboardCode::VKEY_MEDIA_STOP,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::MEDIA_STOP),
+ next_time_stamp()));
+}
+
+TEST_F(MediaKeyboardHookWinTest, NonInterceptedKeysTest) {
+ // Here we try a few keys we do not expect to be intercepted / handled.
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYDOWN, KeyboardCode::VKEY_RSHIFT,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::SHIFT_RIGHT),
+ next_time_stamp()));
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYUP, KeyboardCode::VKEY_RSHIFT,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::SHIFT_RIGHT),
+ next_time_stamp()));
+
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYDOWN, KeyboardCode::VKEY_ESCAPE,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::ESCAPE),
+ next_time_stamp()));
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYUP, KeyboardCode::VKEY_ESCAPE,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::ESCAPE),
+ next_time_stamp()));
+
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYDOWN, KeyboardCode::VKEY_A,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A),
+ next_time_stamp()));
+ ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
+ WM_KEYUP, KeyboardCode::VKEY_A,
+ KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A),
+ next_time_stamp()));
+}
+
+} // namespace ui
diff --git a/chromium/ui/events/win/keyboard_hook_win.cc b/chromium/ui/events/win/modifier_keyboard_hook_win.cc
index 042e295679c..f1f5af47a7a 100644
--- a/chromium/ui/events/win/keyboard_hook_win.cc
+++ b/chromium/ui/events/win/modifier_keyboard_hook_win.cc
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/events/win/keyboard_hook_win.h"
+#include "ui/events/win/keyboard_hook_win_base.h"
#include <utility>
#include "base/logging.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "base/threading/thread_checker.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
@@ -108,14 +107,14 @@ bool IsModifierKey(DWORD vk) {
return IsAltKey(vk) || IsControlKey(vk) || IsWindowsKey(vk);
}
-class KeyboardHookWinImpl : public KeyboardHookWin {
+class ModifierKeyboardHookWinImpl : public KeyboardHookWinBase {
public:
- KeyboardHookWinImpl(base::Optional<base::flat_set<DomCode>> dom_codes,
- KeyEventCallback callback,
- bool enable_hook_registration);
- ~KeyboardHookWinImpl() override;
+ ModifierKeyboardHookWinImpl(base::Optional<base::flat_set<DomCode>> dom_codes,
+ KeyEventCallback callback,
+ bool enable_hook_registration);
+ ~ModifierKeyboardHookWinImpl() override;
- // KeyboardHookWin implementation.
+ // KeyboardHookWinBase implementation.
bool ProcessKeyEventMessage(WPARAM w_param,
DWORD vk,
DWORD scan_code,
@@ -132,11 +131,7 @@ class KeyboardHookWinImpl : public KeyboardHookWin {
void ClearModifierStates();
- static KeyboardHookWinImpl* instance_;
-
- THREAD_CHECKER(thread_checker_);
-
- HHOOK hook_ = nullptr;
+ static ModifierKeyboardHookWinImpl* instance_;
// Tracks the last non-located key down seen in order to determine if the
// current key event should be marked as a repeated key press.
@@ -148,59 +143,40 @@ class KeyboardHookWinImpl : public KeyboardHookWin {
// This sequence occurs on the initial keypress and every repeat.
int altgr_sequence_count_ = 0;
- const bool enable_hook_registration_ = true;
-
- DISALLOW_COPY_AND_ASSIGN(KeyboardHookWinImpl);
+ DISALLOW_COPY_AND_ASSIGN(ModifierKeyboardHookWinImpl);
};
// static
-KeyboardHookWinImpl* KeyboardHookWinImpl::instance_ = nullptr;
+ModifierKeyboardHookWinImpl* ModifierKeyboardHookWinImpl::instance_ = nullptr;
-KeyboardHookWinImpl::KeyboardHookWinImpl(
+ModifierKeyboardHookWinImpl::ModifierKeyboardHookWinImpl(
base::Optional<base::flat_set<DomCode>> dom_codes,
KeyEventCallback callback,
bool enable_hook_registration)
- : KeyboardHookWin(std::move(dom_codes), std::move(callback)),
- enable_hook_registration_(enable_hook_registration) {}
-
-KeyboardHookWinImpl::~KeyboardHookWinImpl() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ : KeyboardHookWinBase(std::move(dom_codes),
+ std::move(callback),
+ enable_hook_registration) {}
+ModifierKeyboardHookWinImpl::~ModifierKeyboardHookWinImpl() {
ClearModifierStates();
- if (!enable_hook_registration_)
+ if (!enable_hook_registration())
return;
DCHECK_EQ(instance_, this);
instance_ = nullptr;
-
- if (!UnhookWindowsHookEx(hook_))
- DPLOG(ERROR) << "UnhookWindowsHookEx failed";
}
-bool KeyboardHookWinImpl::Register() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- // If the hook was created for testing, |Register()| should not be called.
- DCHECK(enable_hook_registration_);
-
+bool ModifierKeyboardHookWinImpl::Register() {
// Only one instance of this class can be registered at a time.
DCHECK(!instance_);
instance_ = this;
- // Per MSDN this Hook procedure will be called in the context of the thread
- // which installed it.
- hook_ = SetWindowsHookEx(
- WH_KEYBOARD_LL,
- reinterpret_cast<HOOKPROC>(&KeyboardHookWinImpl::ProcessKeyEvent),
- /*hMod=*/nullptr,
- /*dwThreadId=*/0);
- DPLOG_IF(ERROR, !hook_) << "SetWindowsHookEx failed";
-
- return hook_ != nullptr;
+ return KeyboardHookWinBase::Register(reinterpret_cast<HOOKPROC>(
+ &ModifierKeyboardHookWinImpl::ProcessKeyEvent));
}
-void KeyboardHookWinImpl::ClearModifierStates() {
+void ModifierKeyboardHookWinImpl::ClearModifierStates() {
BYTE keyboard_state[kKeyboardStateArraySize] = {0};
if (!GetKeyboardState(keyboard_state)) {
DPLOG(ERROR) << "GetKeyboardState() failed: ";
@@ -221,10 +197,10 @@ void KeyboardHookWinImpl::ClearModifierStates() {
DPLOG(ERROR) << "SetKeyboardState() failed: ";
}
-bool KeyboardHookWinImpl::ProcessKeyEventMessage(WPARAM w_param,
- DWORD vk,
- DWORD scan_code,
- DWORD time_stamp) {
+bool ModifierKeyboardHookWinImpl::ProcessKeyEventMessage(WPARAM w_param,
+ DWORD vk,
+ DWORD scan_code,
+ DWORD time_stamp) {
// The |vk| delivered to the low-level hook includes a location which is
// needed to track individual keystates such as when both left and right
// control keys are pressed. Make sure that location information was retained
@@ -288,12 +264,13 @@ bool KeyboardHookWinImpl::ProcessKeyEventMessage(WPARAM w_param,
std::make_unique<KeyEvent>(KeyEventFromMSG(msg));
if (is_repeat)
key_event->set_flags(key_event->flags() | EF_IS_REPEAT);
- ForwardCapturedKeyEvent(std::move(key_event));
+ ForwardCapturedKeyEvent(key_event.get());
return true;
}
-void KeyboardHookWinImpl::UpdateModifierState(DWORD vk, bool is_key_down) {
+void ModifierKeyboardHookWinImpl::UpdateModifierState(DWORD vk,
+ bool is_key_down) {
BYTE keyboard_state[kKeyboardStateArraySize] = {0};
if (!GetKeyboardState(keyboard_state)) {
DPLOG(ERROR) << "GetKeyboardState() failed: ";
@@ -318,46 +295,24 @@ void KeyboardHookWinImpl::UpdateModifierState(DWORD vk, bool is_key_down) {
}
// static
-LRESULT CALLBACK KeyboardHookWinImpl::ProcessKeyEvent(int code,
- WPARAM w_param,
- LPARAM l_param) {
- // If there is an error unhooking, this method could be called with a null
- // |instance_|. Ensure we have a valid instance and that |code| is correct
- // before proceeding.
- if (!instance_ || code != HC_ACTION)
- return CallNextHookEx(nullptr, code, w_param, l_param);
-
- DCHECK_CALLED_ON_VALID_THREAD(instance_->thread_checker_);
-
- KBDLLHOOKSTRUCT* ll_hooks = reinterpret_cast<KBDLLHOOKSTRUCT*>(l_param);
-
- // This vkey represents both a vkey and a location on the keyboard such as
- // VK_LCONTROL or VK_RCONTROL.
- DWORD vk = ll_hooks->vkCode;
-
- // Apply the extended flag prior to passing |scan_code| since |instance_| does
- // not have access to the low-level hook flags.
- DWORD scan_code = ll_hooks->scanCode;
- if (ll_hooks->flags & LLKHF_EXTENDED)
- scan_code |= 0xE000;
-
- if (instance_->ProcessKeyEventMessage(w_param, vk, scan_code, ll_hooks->time))
- return 1;
-
- return CallNextHookEx(nullptr, code, w_param, l_param);
+LRESULT CALLBACK ModifierKeyboardHookWinImpl::ProcessKeyEvent(int code,
+ WPARAM w_param,
+ LPARAM l_param) {
+ return KeyboardHookWinBase::ProcessKeyEvent(instance_, code, w_param,
+ l_param);
}
} // namespace
// static
-std::unique_ptr<KeyboardHook> KeyboardHook::Create(
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
base::Optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget,
KeyEventCallback callback) {
- std::unique_ptr<KeyboardHookWinImpl> keyboard_hook =
- std::make_unique<KeyboardHookWinImpl>(std::move(dom_codes),
- std::move(callback),
- /*enable_hook_registration=*/true);
+ std::unique_ptr<ModifierKeyboardHookWinImpl> keyboard_hook =
+ std::make_unique<ModifierKeyboardHookWinImpl>(
+ std::move(dom_codes), std::move(callback),
+ /*enable_hook_registration=*/true);
if (!keyboard_hook->Register())
return nullptr;
@@ -365,19 +320,13 @@ std::unique_ptr<KeyboardHook> KeyboardHook::Create(
return keyboard_hook;
}
-std::unique_ptr<KeyboardHookWin> KeyboardHookWin::CreateForTesting(
+std::unique_ptr<KeyboardHookWinBase>
+KeyboardHookWinBase::CreateModifierKeyboardHookForTesting(
base::Optional<base::flat_set<DomCode>> dom_codes,
KeyEventCallback callback) {
- return std::make_unique<KeyboardHookWinImpl>(
+ return std::make_unique<ModifierKeyboardHookWinImpl>(
std::move(dom_codes), std::move(callback),
/*enable_hook_registration=*/false);
}
-KeyboardHookWin::KeyboardHookWin(
- base::Optional<base::flat_set<DomCode>> dom_codes,
- KeyEventCallback callback)
- : KeyboardHookBase(std::move(dom_codes), std::move(callback)) {}
-
-KeyboardHookWin::~KeyboardHookWin() = default;
-
} // namespace ui
diff --git a/chromium/ui/events/win/keyboard_hook_win_unittest.cc b/chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc
index d8f3deaa805..ff1dcf4a1da 100644
--- a/chromium/ui/events/win/keyboard_hook_win_unittest.cc
+++ b/chromium/ui/events/win/modifier_keyboard_hook_win_unittest.cc
@@ -15,15 +15,15 @@
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/keyboard_layout.h"
-#include "ui/events/win/keyboard_hook_win.h"
+#include "ui/events/win/keyboard_hook_win_base.h"
#include "ui/events/win/system_event_state_lookup.h"
namespace ui {
-class KeyboardHookWinTest : public testing::Test {
+class ModifierKeyboardHookWinTest : public testing::Test {
public:
- KeyboardHookWinTest();
- ~KeyboardHookWinTest() override;
+ ModifierKeyboardHookWinTest();
+ ~ModifierKeyboardHookWinTest() override;
// testing::Test overrides.
void SetUp() override;
@@ -31,7 +31,7 @@ class KeyboardHookWinTest : public testing::Test {
void HandleKeyPress(KeyEvent* key_event);
protected:
- KeyboardHookWin* keyboard_hook() { return keyboard_hook_.get(); }
+ KeyboardHookWinBase* keyboard_hook() { return keyboard_hook_.get(); }
uint32_t next_time_stamp() { return time_stamp_++; }
@@ -47,34 +47,35 @@ class KeyboardHookWinTest : public testing::Test {
private:
uint32_t time_stamp_ = 0;
- std::unique_ptr<KeyboardHookWin> keyboard_hook_;
+ std::unique_ptr<KeyboardHookWinBase> keyboard_hook_;
std::vector<KeyEvent> key_events_;
std::unique_ptr<ScopedKeyboardLayout> keyboard_layout_;
- DISALLOW_COPY_AND_ASSIGN(KeyboardHookWinTest);
+ DISALLOW_COPY_AND_ASSIGN(ModifierKeyboardHookWinTest);
};
-KeyboardHookWinTest::KeyboardHookWinTest() = default;
+ModifierKeyboardHookWinTest::ModifierKeyboardHookWinTest() = default;
-KeyboardHookWinTest::~KeyboardHookWinTest() = default;
+ModifierKeyboardHookWinTest::~ModifierKeyboardHookWinTest() = default;
-void KeyboardHookWinTest::SetUp() {
- keyboard_hook_ = KeyboardHookWin::CreateForTesting(
+void ModifierKeyboardHookWinTest::SetUp() {
+ keyboard_hook_ = KeyboardHookWinBase::CreateModifierKeyboardHookForTesting(
base::Optional<base::flat_set<DomCode>>(),
- base::BindRepeating(&KeyboardHookWinTest::HandleKeyPress,
+ base::BindRepeating(&ModifierKeyboardHookWinTest::HandleKeyPress,
base::Unretained(this)));
keyboard_layout_ = std::make_unique<ScopedKeyboardLayout>(
KeyboardLayout::KEYBOARD_LAYOUT_ENGLISH_US);
}
-void KeyboardHookWinTest::HandleKeyPress(KeyEvent* key_event) {
+void ModifierKeyboardHookWinTest::HandleKeyPress(KeyEvent* key_event) {
key_events_.push_back(*key_event);
}
-void KeyboardHookWinTest::SendModifierKeyDownEvent(KeyboardCode key_code,
- DomCode dom_code,
- int repeat_count /*=1*/) {
+void ModifierKeyboardHookWinTest::SendModifierKeyDownEvent(
+ KeyboardCode key_code,
+ DomCode dom_code,
+ int repeat_count /*=1*/) {
// Ensure we have a valid repeat count and the modifer passed in contains
// location information.
DCHECK_GT(repeat_count, 0);
@@ -88,8 +89,8 @@ void KeyboardHookWinTest::SendModifierKeyDownEvent(KeyboardCode key_code,
}
}
-void KeyboardHookWinTest::SendModifierKeyUpEvent(KeyboardCode key_code,
- DomCode dom_code) {
+void ModifierKeyboardHookWinTest::SendModifierKeyUpEvent(KeyboardCode key_code,
+ DomCode dom_code) {
// Ensure we have a valid repeat count and the modifer passed in contains
// location information.
DCHECK_NE(key_code, KeyboardCode::VKEY_CONTROL);
@@ -116,7 +117,7 @@ void VerifyKeyEvent(KeyEvent* key_event,
ASSERT_EQ(key_event->code(), dom_code);
}
-TEST_F(KeyboardHookWinTest, SimpleLeftControlKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleLeftControlKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_LCONTROL;
const DomCode dom_code = DomCode::CONTROL_LEFT;
SendModifierKeyDownEvent(key_code, dom_code);
@@ -136,7 +137,7 @@ TEST_F(KeyboardHookWinTest, SimpleLeftControlKeypressTest) {
ASSERT_FALSE(up_event.IsControlDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingLeftControlKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingLeftControlKeypressTest) {
const int repeat_count = 10;
const KeyboardCode key_code = KeyboardCode::VKEY_LCONTROL;
const DomCode dom_code = DomCode::CONTROL_LEFT;
@@ -161,7 +162,7 @@ TEST_F(KeyboardHookWinTest, RepeatingLeftControlKeypressTest) {
ASSERT_FALSE(up_event.IsControlDown());
}
-TEST_F(KeyboardHookWinTest, SimpleRightControlKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleRightControlKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_RCONTROL;
const DomCode dom_code = DomCode::CONTROL_RIGHT;
SendModifierKeyDownEvent(key_code, dom_code);
@@ -181,7 +182,7 @@ TEST_F(KeyboardHookWinTest, SimpleRightControlKeypressTest) {
ASSERT_FALSE(up_event.IsControlDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingRightControlKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingRightControlKeypressTest) {
const int repeat_count = 10;
const KeyboardCode key_code = KeyboardCode::VKEY_RCONTROL;
const DomCode dom_code = DomCode::CONTROL_RIGHT;
@@ -206,7 +207,7 @@ TEST_F(KeyboardHookWinTest, RepeatingRightControlKeypressTest) {
ASSERT_FALSE(up_event.IsControlDown());
}
-TEST_F(KeyboardHookWinTest, SimpleLifoControlSequenceTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleLifoControlSequenceTest) {
const KeyboardCode left_key_code = KeyboardCode::VKEY_LCONTROL;
const DomCode left_dom_code = DomCode::CONTROL_LEFT;
const KeyboardCode right_key_code = KeyboardCode::VKEY_RCONTROL;
@@ -253,7 +254,7 @@ TEST_F(KeyboardHookWinTest, SimpleLifoControlSequenceTest) {
ASSERT_FALSE(event.IsControlDown());
}
-TEST_F(KeyboardHookWinTest, SimpleFifoControlSequenceTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleFifoControlSequenceTest) {
const KeyboardCode left_key_code = KeyboardCode::VKEY_LCONTROL;
const DomCode left_dom_code = DomCode::CONTROL_LEFT;
const KeyboardCode right_key_code = KeyboardCode::VKEY_RCONTROL;
@@ -299,7 +300,7 @@ TEST_F(KeyboardHookWinTest, SimpleFifoControlSequenceTest) {
ASSERT_FALSE(event.IsControlDown());
}
-TEST_F(KeyboardHookWinTest, SimpleLeftAltKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleLeftAltKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_LMENU;
const DomCode dom_code = DomCode::ALT_LEFT;
SendModifierKeyDownEvent(key_code, dom_code);
@@ -318,7 +319,7 @@ TEST_F(KeyboardHookWinTest, SimpleLeftAltKeypressTest) {
ASSERT_FALSE(up_event.IsAltDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingLeftAltKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingLeftAltKeypressTest) {
const int repeat_count = 10;
const KeyboardCode key_code = KeyboardCode::VKEY_LMENU;
const DomCode dom_code = DomCode::ALT_LEFT;
@@ -343,7 +344,7 @@ TEST_F(KeyboardHookWinTest, RepeatingLeftAltKeypressTest) {
ASSERT_FALSE(up_event.IsAltDown());
}
-TEST_F(KeyboardHookWinTest, SimpleRightAltKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleRightAltKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_RMENU;
const DomCode dom_code = DomCode::ALT_LEFT;
SendModifierKeyDownEvent(key_code, dom_code);
@@ -362,7 +363,7 @@ TEST_F(KeyboardHookWinTest, SimpleRightAltKeypressTest) {
ASSERT_FALSE(up_event.IsAltDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingRightAltKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingRightAltKeypressTest) {
const int repeat_count = 10;
const KeyboardCode key_code = KeyboardCode::VKEY_RMENU;
const DomCode dom_code = DomCode::ALT_RIGHT;
@@ -387,7 +388,7 @@ TEST_F(KeyboardHookWinTest, RepeatingRightAltKeypressTest) {
ASSERT_FALSE(up_event.IsAltDown());
}
-TEST_F(KeyboardHookWinTest, SimpleLifoAltSequenceTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleLifoAltSequenceTest) {
const KeyboardCode left_key_code = KeyboardCode::VKEY_LMENU;
const DomCode left_dom_code = DomCode::ALT_LEFT;
const KeyboardCode right_key_code = KeyboardCode::VKEY_RMENU;
@@ -429,7 +430,7 @@ TEST_F(KeyboardHookWinTest, SimpleLifoAltSequenceTest) {
ASSERT_FALSE(event.IsAltDown());
}
-TEST_F(KeyboardHookWinTest, SimpleFifoAltSequenceTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleFifoAltSequenceTest) {
const KeyboardCode left_key_code = KeyboardCode::VKEY_LMENU;
const DomCode left_dom_code = DomCode::ALT_LEFT;
const KeyboardCode right_key_code = KeyboardCode::VKEY_RMENU;
@@ -471,7 +472,7 @@ TEST_F(KeyboardHookWinTest, SimpleFifoAltSequenceTest) {
ASSERT_FALSE(event.IsAltDown());
}
-TEST_F(KeyboardHookWinTest, SimpleLeftWinKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleLeftWinKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_LWIN;
const DomCode dom_code = DomCode::META_LEFT;
SendModifierKeyDownEvent(key_code, dom_code);
@@ -491,7 +492,7 @@ TEST_F(KeyboardHookWinTest, SimpleLeftWinKeypressTest) {
ASSERT_FALSE(up_event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingLeftWinKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingLeftWinKeypressTest) {
const int repeat_count = 10;
const KeyboardCode key_code = KeyboardCode::VKEY_LWIN;
const DomCode dom_code = DomCode::META_LEFT;
@@ -517,7 +518,7 @@ TEST_F(KeyboardHookWinTest, RepeatingLeftWinKeypressTest) {
ASSERT_FALSE(up_event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, SimpleRightWinKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleRightWinKeypressTest) {
const KeyboardCode key_code = KeyboardCode::VKEY_RWIN;
const DomCode dom_code = DomCode::META_RIGHT;
SendModifierKeyDownEvent(key_code, dom_code);
@@ -537,7 +538,7 @@ TEST_F(KeyboardHookWinTest, SimpleRightWinKeypressTest) {
ASSERT_FALSE(up_event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingRightWinKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingRightWinKeypressTest) {
const int repeat_count = 10;
const KeyboardCode key_code = KeyboardCode::VKEY_RWIN;
const DomCode dom_code = DomCode::META_RIGHT;
@@ -563,7 +564,7 @@ TEST_F(KeyboardHookWinTest, RepeatingRightWinKeypressTest) {
ASSERT_FALSE(up_event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, SimpleLifoWinSequenceTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleLifoWinSequenceTest) {
const KeyboardCode left_key_code = KeyboardCode::VKEY_LWIN;
const DomCode left_dom_code = DomCode::META_LEFT;
const KeyboardCode right_key_code = KeyboardCode::VKEY_RWIN;
@@ -605,7 +606,7 @@ TEST_F(KeyboardHookWinTest, SimpleLifoWinSequenceTest) {
ASSERT_FALSE(event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, SimpleFifoWinSequenceTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleFifoWinSequenceTest) {
const KeyboardCode left_key_code = KeyboardCode::VKEY_LWIN;
const DomCode left_dom_code = DomCode::META_LEFT;
const KeyboardCode right_key_code = KeyboardCode::VKEY_RWIN;
@@ -647,7 +648,7 @@ TEST_F(KeyboardHookWinTest, SimpleFifoWinSequenceTest) {
ASSERT_FALSE(event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, CombinedModifierLifoSequenceKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, CombinedModifierLifoSequenceKeypressTest) {
const KeyboardCode first_key_code = KeyboardCode::VKEY_LCONTROL;
const DomCode first_dom_code = DomCode::CONTROL_LEFT;
const KeyboardCode second_key_code = KeyboardCode::VKEY_RWIN;
@@ -730,7 +731,7 @@ TEST_F(KeyboardHookWinTest, CombinedModifierLifoSequenceKeypressTest) {
ASSERT_FALSE(event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, CombinedModifierFifoSequenceKeypressTest) {
+TEST_F(ModifierKeyboardHookWinTest, CombinedModifierFifoSequenceKeypressTest) {
const KeyboardCode first_key_code = KeyboardCode::VKEY_RCONTROL;
const DomCode first_dom_code = DomCode::CONTROL_RIGHT;
const KeyboardCode second_key_code = KeyboardCode::VKEY_LWIN;
@@ -813,7 +814,7 @@ TEST_F(KeyboardHookWinTest, CombinedModifierFifoSequenceKeypressTest) {
ASSERT_FALSE(event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, VerifyPlatformModifierStateTest) {
+TEST_F(ModifierKeyboardHookWinTest, VerifyPlatformModifierStateTest) {
SendModifierKeyDownEvent(KeyboardCode::VKEY_LCONTROL, DomCode::CONTROL_LEFT);
ASSERT_TRUE(win::IsCtrlPressed());
ASSERT_FALSE(win::IsAltPressed());
@@ -850,7 +851,7 @@ TEST_F(KeyboardHookWinTest, VerifyPlatformModifierStateTest) {
ASSERT_TRUE(win::IsAltRightPressed());
}
-TEST_F(KeyboardHookWinTest, SimpleAltGrKeyPressTest) {
+TEST_F(ModifierKeyboardHookWinTest, SimpleAltGrKeyPressTest) {
ScopedKeyboardLayout keyboard_layout(KeyboardLayout::KEYBOARD_LAYOUT_GERMAN);
// AltGr produces two events, an injected, modified scan code for VK_LCONTROL,
@@ -909,7 +910,7 @@ TEST_F(KeyboardHookWinTest, SimpleAltGrKeyPressTest) {
ASSERT_FALSE(event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, RepeatingAltGrKeyPressTest) {
+TEST_F(ModifierKeyboardHookWinTest, RepeatingAltGrKeyPressTest) {
ScopedKeyboardLayout keyboard_layout(KeyboardLayout::KEYBOARD_LAYOUT_GERMAN);
// AltGr produces two events, an injected, modified scan code for VK_LCONTROL,
@@ -1010,7 +1011,7 @@ TEST_F(KeyboardHookWinTest, RepeatingAltGrKeyPressTest) {
ASSERT_FALSE(event.IsCommandDown());
}
-TEST_F(KeyboardHookWinTest, VerifyAltGrPlatformModifierStateTest) {
+TEST_F(ModifierKeyboardHookWinTest, VerifyAltGrPlatformModifierStateTest) {
ScopedKeyboardLayout keyboard_layout(KeyboardLayout::KEYBOARD_LAYOUT_GERMAN);
// AltGr produces two events, an injected, modified scan code for VK_LCONTROL,
@@ -1052,7 +1053,7 @@ TEST_F(KeyboardHookWinTest, VerifyAltGrPlatformModifierStateTest) {
ASSERT_FALSE(win::IsWindowsKeyPressed());
}
-TEST_F(KeyboardHookWinTest, NonInterceptedKeysTest) {
+TEST_F(ModifierKeyboardHookWinTest, NonInterceptedKeysTest) {
// Here we try a few keys we do not expect to be intercepted / handled.
ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage(
WM_KEYDOWN, KeyboardCode::VKEY_RSHIFT,
diff --git a/chromium/ui/events/x/events_x.cc b/chromium/ui/events/x/events_x.cc
index 62530318bc2..b8df7b02091 100644
--- a/chromium/ui/events/x/events_x.cc
+++ b/chromium/ui/events/x/events_x.cc
@@ -81,7 +81,9 @@ int EventFlagsFromNative(const PlatformEvent& native_event) {
}
base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
- return EventTimeFromXEvent(*native_event);
+ base::TimeTicks timestamp = EventTimeFromXEvent(*native_event);
+ ValidateEventTimeClock(&timestamp);
+ return timestamp;
}
gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
diff --git a/chromium/ui/events/x/events_x_unittest.cc b/chromium/ui/events/x/events_x_unittest.cc
index 3419309a22a..897c5c5cb94 100644
--- a/chromium/ui/events/x/events_x_unittest.cc
+++ b/chromium/ui/events/x/events_x_unittest.cc
@@ -76,15 +76,6 @@ float ComputeRotationAngle(float twist) {
return rotation_angle;
}
-class MockTimestampServer : public ui::TimestampServer {
- public:
- Time GetCurrentServerTime() override { return base_time_; }
- void SetBaseTime(Time time) { base_time_ = time; }
-
- private:
- Time base_time_ = 0;
-};
-
} // namespace
class EventsXTest : public testing::Test {
@@ -93,15 +84,13 @@ class EventsXTest : public testing::Test {
~EventsXTest() override {}
void SetUp() override {
- SetTimestampServer(&server_);
DeviceDataManagerX11::CreateInstance();
ui::TouchFactory::GetInstance()->ResetForTest();
+ ResetTimestampRolloverCountersForTesting();
}
-
- void TearDown() override { SetTimestampServer(nullptr); }
+ void TearDown() override { ResetTimestampRolloverCountersForTesting(); }
private:
- MockTimestampServer server_;
DISALLOW_COPY_AND_ASSIGN(EventsXTest);
};
@@ -553,4 +542,52 @@ TEST_F(EventsXTest, IgnoresMotionEventForMouseWheelScroll) {
EXPECT_EQ(ui::ET_UNKNOWN, ui::EventTypeFromNative(xev));
}
+namespace {
+
+// Returns a fake TimeTicks based on the given millisecond offset.
+base::TimeTicks TimeTicksFromMillis(int64_t millis) {
+ return base::TimeTicks() + base::TimeDelta::FromMilliseconds(millis);
+}
+
+} // namespace
+
+TEST_F(EventsXTest, TimestampRolloverAndAdjustWhenDecreasing) {
+ XEvent event;
+ InitButtonEvent(&event, true, gfx::Point(5, 10), 1, 0);
+
+ test::ScopedEventTestTickClock clock;
+ clock.SetNowTicks(TimeTicksFromMillis(0x100000001));
+ ResetTimestampRolloverCountersForTesting();
+
+ event.xbutton.time = 0xFFFFFFFF;
+ EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromNative(&event));
+
+ clock.SetNowTicks(TimeTicksFromMillis(0x100000007));
+ ResetTimestampRolloverCountersForTesting();
+
+ event.xbutton.time = 3;
+ EXPECT_EQ(TimeTicksFromMillis(0x100000000 + 3),
+ ui::EventTimeFromNative(&event));
+}
+
+TEST_F(EventsXTest, NoTimestampRolloverWhenMonotonicIncreasing) {
+ XEvent event;
+ InitButtonEvent(&event, true, gfx::Point(5, 10), 1, 0);
+
+ test::ScopedEventTestTickClock clock;
+ clock.SetNowTicks(TimeTicksFromMillis(10));
+ ResetTimestampRolloverCountersForTesting();
+
+ event.xbutton.time = 6;
+ EXPECT_EQ(TimeTicksFromMillis(6), ui::EventTimeFromNative(&event));
+ event.xbutton.time = 7;
+ EXPECT_EQ(TimeTicksFromMillis(7), ui::EventTimeFromNative(&event));
+
+ clock.SetNowTicks(TimeTicksFromMillis(0x100000005));
+ ResetTimestampRolloverCountersForTesting();
+
+ event.xbutton.time = 0xFFFFFFFF;
+ EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromNative(&event));
+}
+
} // namespace ui
diff --git a/chromium/ui/events/x/events_x_utils.cc b/chromium/ui/events/x/events_x_utils.cc
index 8dec888198a..86fbd1937c6 100644
--- a/chromium/ui/events/x/events_x_utils.cc
+++ b/chromium/ui/events/x/events_x_utils.cc
@@ -27,25 +27,6 @@
namespace {
-ui::TimestampServer* g_timestamp_server = nullptr;
-bool g_use_fixed_time_for_testing = false;
-
-// Clamps a TimeDelta to be within [-30 seconds, 30 seconds].
-base::TimeDelta ClampDeltaFromExternalSource(const base::TimeDelta& delta) {
- // Ignore pathologically long deltas. External source is probably having
- // issues.
- constexpr base::TimeDelta pathologically_long_duration =
- base::TimeDelta::FromSeconds(30);
- if (delta > pathologically_long_duration)
- return base::TimeDelta();
-
- // Ignore negative deltas. External source is probably having issues.
- if (delta < -pathologically_long_duration)
- return base::TimeDelta();
-
- return delta;
-}
-
// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
const int kWheelScrollAmount = 53;
@@ -327,36 +308,40 @@ bool GetGestureTimes(const XEvent& xev, double* start_time, double* end_time) {
return true;
}
+int64_t g_last_seen_timestamp_ms = 0;
+int64_t g_rollover_ms = 0;
+
+// Takes Xlib Time and returns a time delta that is immune to timer rollover.
+// This function is not thread safe as we do not use a lock.
base::TimeTicks TimeTicksFromXEventTime(Time timestamp) {
- // There's no way to convert from an X time to a base::TimeTicks without
- // knowing the current X server time.
- if (!g_timestamp_server)
- return base::TimeTicks();
-
- // X11 uses a uint32_t on the wire protocol. Xlib casts this to an unsigned
- // long by prepending with 0s. We cast back to a uint32_t so that subtraction
- // works properly when the timestamp overflows back to 0.
- uint32_t event_server_time_ms = static_cast<uint32_t>(timestamp);
- uint32_t current_server_time_ms =
- static_cast<uint32_t>(g_timestamp_server->GetCurrentServerTime());
-
- // On X11, event times are in X11 Server time. To convert to base::TimeTicks,
- // we perform a round-trip to the X11 Server, subtract the two times to get a
- // TimeDelta, and then subtract that from base::TimeTicks::Now(). Since we're
- // working with units of time from an external source, we clamp the TimeDelta
- // to reasonable values.
- int64_t delta_ms = static_cast<int64_t>(current_server_time_ms) -
- static_cast<int64_t>(event_server_time_ms);
- base::TimeDelta delta = base::TimeDelta::FromMilliseconds(delta_ms);
- base::TimeDelta sanitized = ClampDeltaFromExternalSource(delta);
-
- base::TimeTicks now;
- if (g_use_fixed_time_for_testing)
- now = base::TimeTicks() + base::TimeDelta::FromDays(1);
- else
- now = base::TimeTicks::Now();
-
- return now - sanitized;
+ int64_t timestamp64 = timestamp;
+
+ if (!timestamp)
+ return ui::EventTimeForNow();
+
+ // If this is the first event that we get, assume the time stamp roll-over
+ // might have happened before the process was started.
+ // Register a rollover if the distance between last timestamp and current one
+ // is larger than half the width. This avoids false rollovers even in a case
+ // where X server delivers reasonably close events out-of-order.
+ bool had_recent_rollover =
+ !g_last_seen_timestamp_ms ||
+ g_last_seen_timestamp_ms - timestamp64 > (UINT32_MAX >> 1);
+
+ g_last_seen_timestamp_ms = timestamp64;
+ if (!had_recent_rollover)
+ return base::TimeTicks() +
+ base::TimeDelta::FromMilliseconds(g_rollover_ms + timestamp);
+
+ DCHECK(timestamp64 <= UINT32_MAX)
+ << "X11 Time does not roll over 32 bit, the below logic is likely wrong";
+
+ base::TimeTicks now_ticks = ui::EventTimeForNow();
+ int64_t now_ms = (now_ticks - base::TimeTicks()).InMilliseconds();
+
+ g_rollover_ms = now_ms & ~static_cast<int64_t>(UINT32_MAX);
+ uint32_t delta = static_cast<uint32_t>(now_ms - timestamp);
+ return base::TimeTicks() + base::TimeDelta::FromMilliseconds(now_ms - delta);
}
} // namespace
@@ -846,16 +831,9 @@ bool IsAltPressed() {
return XModifierStateWatcher::GetInstance()->state() & Mod1Mask;
}
-void SetTimestampServer(TimestampServer* server) {
- // This method must be setting or unsetting a timestamp server. It should
- // never replace an existing timestamp server, nor change from
- // nullptr->nullptr.
- CHECK(!!g_timestamp_server ^ !!server);
- g_timestamp_server = server;
-}
-
-void SetUseFixedTimeForXEventTesting(bool use_fixed_time) {
- g_use_fixed_time_for_testing = use_fixed_time;
+void ResetTimestampRolloverCountersForTesting() {
+ g_last_seen_timestamp_ms = 0;
+ g_rollover_ms = 0;
}
} // namespace ui
diff --git a/chromium/ui/events/x/events_x_utils.h b/chromium/ui/events/x/events_x_utils.h
index ad11a08a17a..64814e87715 100644
--- a/chromium/ui/events/x/events_x_utils.h
+++ b/chromium/ui/events/x/events_x_utils.h
@@ -16,8 +16,6 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/x/x11_types.h"
-using Time = unsigned long;
-
namespace ui {
// Gets the EventType from a XEvent.
@@ -93,18 +91,6 @@ EVENTS_X_EXPORT bool IsAltPressed();
EVENTS_X_EXPORT void ResetTimestampRolloverCountersForTesting();
-// Conversion from X Time to base::TimeTicks requires checking the current X
-// Server Time. This functionality is provided by X11EventSource, but due to odd
-// layering that cannot be referenced directly.
-class TimestampServer {
- public:
- virtual Time GetCurrentServerTime() = 0;
-};
-EVENTS_X_EXPORT void SetTimestampServer(TimestampServer* server);
-
-// Allows tests to force a fixed time..
-EVENTS_X_EXPORT void SetUseFixedTimeForXEventTesting(bool use_fixed_time);
-
} // namespace ui
#endif // UI_EVENTS_X_EVENTS_X_UTILS_H_
diff --git a/chromium/ui/events/x/keyboard_hook_x11.cc b/chromium/ui/events/x/keyboard_hook_x11.cc
index 588124adf14..0df8bcb474e 100644
--- a/chromium/ui/events/x/keyboard_hook_x11.cc
+++ b/chromium/ui/events/x/keyboard_hook_x11.cc
@@ -156,7 +156,7 @@ void KeyboardHookX11::CaptureKeyForDomCode(DomCode dom_code) {
} // namespace
// static
-std::unique_ptr<KeyboardHook> KeyboardHook::Create(
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
base::Optional<base::flat_set<DomCode>> dom_codes,
gfx::AcceleratedWidget accelerated_widget,
KeyboardHook::KeyEventCallback callback) {
@@ -169,4 +169,10 @@ std::unique_ptr<KeyboardHook> KeyboardHook::Create(
return keyboard_hook;
}
+// static
+std::unique_ptr<KeyboardHook> KeyboardHook::CreateMediaKeyboardHook(
+ KeyEventCallback callback) {
+ return nullptr;
+}
+
} // namespace ui
diff --git a/chromium/ui/file_manager/BUILD.gn b/chromium/ui/file_manager/BUILD.gn
index 99433199a4b..97493014ffa 100644
--- a/chromium/ui/file_manager/BUILD.gn
+++ b/chromium/ui/file_manager/BUILD.gn
@@ -30,6 +30,10 @@ component("file_manager") {
}
group("closure_compile") {
+ # Subfolders' closure_compile groups bundle the non-test "module" type-check
+ # groups as well as unittests and test_support.
+ testonly = true
+
deps = [
"audio_player/elements:closure_compile",
"audio_player/js:closure_compile",
@@ -50,9 +54,14 @@ group("closure_compile") {
}
group("unit_test_data") {
+ testonly = true
deps = [
+ "base/js:unit_tests",
+ "file_manager/background/js:unit_tests",
"file_manager/common/js:unit_tests",
"file_manager/foreground/js:unit_tests",
+ "file_manager/foreground/js/metadata:unit_tests",
+ "file_manager/foreground/js/ui:unit_tests",
"gallery/js:unit_tests",
"gallery/js/image_editor:unit_tests",
"image_loader:unit_tests",
diff --git a/chromium/ui/file_manager/audio_player/elements/BUILD.gn b/chromium/ui/file_manager/audio_player/elements/BUILD.gn
index 3b3a5045c23..cc51218fe21 100644
--- a/chromium/ui/file_manager/audio_player/elements/BUILD.gn
+++ b/chromium/ui/file_manager/audio_player/elements/BUILD.gn
@@ -31,7 +31,7 @@ js_library("audio_player") {
js_library("control_panel") {
deps = [
":repeat_button",
- "//third_party/polymer/v1_0/components-chromium/paper-slider:paper-slider-extracted",
+ "//ui/webui/resources/cr_elements/cr_slider:cr_slider",
"//ui/webui/resources/js:assert",
]
}
diff --git a/chromium/ui/file_manager/audio_player/js/BUILD.gn b/chromium/ui/file_manager/audio_player/js/BUILD.gn
index 89c18c22f10..ddf897af313 100644
--- a/chromium/ui/file_manager/audio_player/js/BUILD.gn
+++ b/chromium/ui/file_manager/audio_player/js/BUILD.gn
@@ -18,10 +18,8 @@ js_library("closure_compile_externs") {
sources = []
externs_list = [
"$externs_path/chrome_extensions.js",
- "$externs_path/metrics_private.js",
"../../externs/audio_player_foreground.js",
"../../externs/platform.js",
- "//third_party/analytics/externs.js",
]
}
diff --git a/chromium/ui/file_manager/base/js/BUILD.gn b/chromium/ui/file_manager/base/js/BUILD.gn
index b71798141bb..2103bf75b51 100644
--- a/chromium/ui/file_manager/base/js/BUILD.gn
+++ b/chromium/ui/file_manager/base/js/BUILD.gn
@@ -3,25 +3,78 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//third_party/closure_compiler/js_unit_tests.gni")
visibility = [ "//ui/file_manager/*" ]
-js_type_check("closure_compile") {
+group("closure_compile") {
+ testonly = true
deps = [
+ ":closure_compile_module",
+ ":test_support_type_check",
+ ]
+}
+
+js_type_check("closure_compile_module") {
+ deps = [
+ ":error_counter",
":filtered_volume_manager",
]
}
+js_type_check("test_support_type_check") {
+ testonly = true
+ deps = [
+ ":mock_chrome",
+ ":test_error_reporting",
+ ]
+}
+
+js_library("error_counter") {
+}
+
js_library("filtered_volume_manager") {
deps = [
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:file_manager_private",
"//ui/file_manager/externs:volume_manager",
"//ui/file_manager/file_manager/common/js:async_util",
"//ui/file_manager/file_manager/common/js:files_app_entry_types",
- "//ui/file_manager/file_manager/common/js:volume_manager_common",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js/cr/ui:array_data_model",
]
externs_list =
[ "//ui/file_manager/externs/background/volume_manager_factory.js" ]
}
+
+js_library("mock_chrome") {
+ testonly = true
+}
+
+js_library("test_error_reporting") {
+ testonly = true
+ deps = [
+ # Note we allow targets depending on test_error_reporting to access
+ # webui_resource_test transitively.
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
+js_library("volume_manager_types") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ ]
+}
+
+js_unittest("volume_manager_types_unittest") {
+ deps = [
+ ":volume_manager_types",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
+js_unit_tests("unit_tests") {
+ deps = [
+ ":volume_manager_types_unittest",
+ ]
+}
diff --git a/chromium/ui/file_manager/externs/BUILD.gn b/chromium/ui/file_manager/externs/BUILD.gn
index dad5e37013e..469bb945445 100644
--- a/chromium/ui/file_manager/externs/BUILD.gn
+++ b/chromium/ui/file_manager/externs/BUILD.gn
@@ -33,7 +33,7 @@ js_library("volume_manager") {
sources = []
# Encapsulate volume_manager.js and its dependencies. Note this should really
- # depend on volume_manager_common.js as well, but that's not an extern.
+ # depend on volume_manager_types.js as well, but that's not an extern.
externs_list = [
"entry_location.js",
"volume_info.js",
diff --git a/chromium/ui/file_manager/file_manager/background/js/BUILD.gn b/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
index a645f6897d8..4732f285269 100644
--- a/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//third_party/closure_compiler/js_unit_tests.gni")
# TODO(tapted): This folder should be restricted to file_manager, but related
# apps currently depend on background_base, which depends on
@@ -17,16 +18,26 @@ related_apps = [
"//ui/file_manager/video_player/*",
]
+group("closure_compile") {
+ testonly = true
+ deps = [
+ ":closure_compile_module",
+ ":test_support_type_check",
+ ":unit_tests_type_check",
+ ]
+}
+
# Default to private.
visibility = [ ":*" ]
-js_type_check("closure_compile") {
+js_type_check("closure_compile_module") {
deps = [
":app_window_wrapper",
":app_windows",
":background",
":background_base",
":closure_compile_externs",
+ ":crostini",
":device_handler",
":drive_sync_handler",
":duplicate_finder",
@@ -40,8 +51,8 @@ js_type_check("closure_compile") {
":media_import_handler",
":media_scanner",
":metadata_proxy",
- ":mock_volume_manager",
":progress_center",
+ ":runtime_loaded_test_util",
":task_queue",
":test_util_base",
":volume_info_impl",
@@ -52,25 +63,35 @@ js_type_check("closure_compile") {
]
}
+js_type_check("test_support_type_check") {
+ testonly = true
+ deps = [
+ ":mock_drive_sync_handler",
+ ":mock_file_operation_manager",
+ ":mock_media_scanner",
+ ":mock_progress_center",
+ ":mock_volume_manager",
+ ":test_import_history",
+ ]
+}
+
js_library("closure_compile_externs") {
sources = []
externs_list = [
"$externs_path/metrics_private.js",
+ "../../../externs/background/drive_sync_handler.js",
"../../../externs/background/file_browser_background.js",
"../../../externs/background/file_browser_background_full.js",
+ "../../../externs/background/file_operation_manager.js",
"../../../externs/background/import_history.js",
"../../../externs/background/import_runner.js",
"../../../externs/background/media_scanner.js",
+ "../../../externs/background/progress_center.js",
"../../../externs/background_window.js",
"../../../externs/css_rule.js",
- "../../../externs/entry_location.js",
"../../../externs/file_operation_progress_event.js",
"../../../externs/launcher_search_provider.js",
"../../../externs/platform.js",
- "../../../externs/volume_info.js",
- "../../../externs/volume_info_list.js",
- "../../../externs/volume_manager.js",
- "//third_party/analytics/externs.js",
]
}
@@ -90,6 +111,7 @@ js_library("background") {
deps = [
":app_windows",
":background_base",
+ ":crostini",
":device_handler",
":drive_sync_handler",
":duplicate_finder",
@@ -103,7 +125,7 @@ js_library("background") {
"../../common/js:files_app_entry_types",
"../../common/js:metrics",
"../../common/js:util",
- "../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
]
}
@@ -118,6 +140,22 @@ js_library("background_base") {
]
}
+js_library("crostini") {
+ deps = [
+ "../../common/js:metrics",
+ "//ui/file_manager/base/js:volume_manager_types",
+ "//ui/file_manager/externs:volume_manager",
+ ]
+}
+
+js_unittest("crostini_unittest") {
+ deps = [
+ ":crostini",
+ "../../common/js:mock_entry",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("device_handler") {
deps = [
":volume_manager_factory",
@@ -128,9 +166,39 @@ js_library("device_handler") {
]
}
+js_unittest("device_handler_unittest") {
+ deps = [
+ ":device_handler",
+ ":mock_volume_manager",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ]
+}
+
+js_library("mock_drive_sync_handler") {
+ testonly = true
+ deps = [
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [ "../../../externs/background/drive_sync_handler.js" ]
+}
+
js_library("drive_sync_handler") {
deps = [
":progress_center",
+ "//ui/file_manager/file_manager/common/js:async_util",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [ "../../../externs/background/drive_sync_handler.js" ]
+}
+
+js_unittest("drive_sync_handler_unittest") {
+ deps = [
+ ":drive_sync_handler",
+ ":mock_progress_center",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -144,10 +212,22 @@ js_library("duplicate_finder") {
]
}
+js_unittest("duplicate_finder_unittest") {
+ deps = [
+ ":duplicate_finder",
+ ":mock_volume_manager",
+ ":test_import_history",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ]
+}
+
js_library("entry_location_impl") {
deps = [
- "../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
]
+ externs_list = [ "../../../externs/entry_location.js" ]
}
js_library("file_operation_handler") {
@@ -158,11 +238,32 @@ js_library("file_operation_handler") {
]
}
+js_library("mock_file_operation_manager") {
+ testonly = true
+ deps = [
+ ":file_operation_manager",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [ "../../../externs/background/file_operation_manager.js" ]
+}
+
js_library("file_operation_manager") {
deps = [
":file_operation_util",
":volume_manager_factory",
"//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [ "../../../externs/background/file_operation_manager.js" ]
+}
+
+js_unittest("file_operation_manager_unittest") {
+ deps = [
+ ":file_operation_manager",
+ ":metadata_proxy",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
]
}
@@ -172,6 +273,8 @@ js_library("file_operation_util") {
"../../common/js:async_util",
"../../common/js:util",
]
+ externs_list =
+ [ "//ui/file_manager/externs/file_operation_progress_event.js" ]
}
js_library("metadata_proxy") {
@@ -184,10 +287,17 @@ js_library("import_history") {
deps = [
":metadata_proxy",
"../../common/js:importer_common",
- "../../common/js:metrics",
- "../../common/js:metrics_events",
"../../common/js:util",
]
+ externs_list = [ "../../../externs/background/import_history.js" ]
+}
+
+js_unittest("import_history_unittest") {
+ deps = [
+ ":import_history",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ]
}
js_library("launcher") {
@@ -218,11 +328,29 @@ js_library("media_import_handler") {
]
}
+js_library("mock_media_scanner") {
+ testonly = true
+ deps = [
+ ":media_scanner",
+ ":test_import_history",
+ ]
+ externs_list = [ "../../../externs/background/media_scanner.js" ]
+}
+
js_library("media_scanner") {
deps = [
":file_operation_util",
"../../common/js:importer_common",
]
+ externs_list = [ "../../../externs/background/media_scanner.js" ]
+}
+
+js_unittest("media_scanner_unittest") {
+ deps = [
+ ":media_scanner",
+ ":mock_media_scanner",
+ "//ui/file_manager/file_manager/common/js:test_importer_common",
+ ]
}
js_library("mock_volume_manager") {
@@ -236,13 +364,24 @@ js_library("mock_volume_manager") {
]
}
+js_library("mock_progress_center") {
+ testonly = true
+ deps = [
+ ":progress_center",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [ "//ui/file_manager/externs/background/progress_center.js" ]
+}
+
js_library("progress_center") {
deps = [
"../../common/js:async_util",
"../../common/js:progress_center_common",
"../../common/js:util",
"../../foreground/js/ui:progress_center_panel",
+ "//ui/webui/resources/js/cr:event_target",
]
+ externs_list = [ "//ui/file_manager/externs/background/progress_center.js" ]
}
js_library("task_queue") {
@@ -252,24 +391,50 @@ js_library("task_queue") {
]
}
+js_unittest("task_queue_unittest") {
+ deps = [
+ ":task_queue",
+ "../../common/js:importer_common",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/base/js:volume_manager_types",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+}
+
js_library("test_util_base") {
+}
+
+js_library("test_import_history") {
+ testonly = true
+ deps = [
+ ":import_history",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
+js_library("runtime_loaded_test_util") {
# TODO(tapted): Move this target to //ui/file_manager/base. It is used in the
- # background page of all |related_apps|, but accessed via extension messaging.
- # So it doesn't need to be visible as a closure dependency, except for the
- # "unpacked" test framework.
+ # background page of all |related_apps|, but loaded at runtime by
+ # :test_util_base via extension messaging, so doesn't need to be depended on
+ # except by the closure compilation target. The exception is the "unpacked"
+ # test framework, which copies some testing functions into its test context.
visibility += [ "//ui/file_manager/file_manager/test/js:test_util" ]
deps = [
":app_windows",
+ ":test_util_base",
"../../../externs:webview_tag",
- "../../common/js:error_util",
+ "//ui/file_manager/base/js:error_counter",
]
}
js_library("volume_info_impl") {
deps = [
- "../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
]
+ externs_list = [ "../../../externs/volume_info.js" ]
}
js_library("volume_info_list_impl") {
@@ -280,6 +445,7 @@ js_library("volume_info_list_impl") {
"//ui/webui/resources/js/cr:ui",
"//ui/webui/resources/js/cr/ui:array_data_model",
]
+ externs_list = [ "../../../externs/volume_info_list.js" ]
}
js_library("volume_manager_impl") {
@@ -289,6 +455,7 @@ js_library("volume_manager_impl") {
":volume_manager_util",
"../../common/js:async_util",
]
+ externs_list = [ "../../../externs/volume_manager.js" ]
}
js_library("volume_manager_factory") {
@@ -297,12 +464,34 @@ js_library("volume_manager_factory") {
]
}
+js_unittest("volume_manager_unittest") {
+ deps = [
+ ":volume_manager_factory",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ ]
+}
+
js_library("volume_manager_util") {
deps = [
":volume_info_impl",
"../../common/js:metrics",
- "../../common/js:metrics_events",
"../../common/js:util",
- "../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
+ ]
+}
+
+js_unit_tests("unit_tests") {
+ deps = [
+ ":crostini_unittest",
+ ":device_handler_unittest",
+ ":drive_sync_handler_unittest",
+ ":duplicate_finder_unittest",
+ ":file_operation_manager_unittest",
+ ":import_history_unittest",
+ ":media_scanner_unittest",
+ ":task_queue_unittest",
+ ":volume_manager_unittest",
]
}
diff --git a/chromium/ui/file_manager/file_manager/common/js/BUILD.gn b/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
index f4b2fdf8e92..6b93293fada 100644
--- a/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/common/js/BUILD.gn
@@ -8,38 +8,49 @@ import("//third_party/closure_compiler/js_unit_tests.gni")
# TODO(tapted): This entire folder should move to //ui/file_manager/base.
visibility = [ "//ui/file_manager/*" ]
+group("closure_compile") {
+ testonly = true
+ deps = [
+ ":closure_compile_module",
+ ":test_support_type_check",
+ ":unit_tests_type_check",
+ ]
+}
+
js_type_check("closure_compile_module") {
deps = [
":async_util",
- ":error_util",
":file_type",
":files_app_entry_types",
":importer_common",
":lru_cache",
":metrics",
":metrics_base",
- ":metrics_events",
":mock_entry",
":progress_center_common",
- ":unittest_util",
":util",
- ":volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
+ ]
+}
+
+js_type_check("test_support_type_check") {
+ testonly = true
+ deps = [
+ ":test_importer_common",
+ ":unittest_util",
]
}
js_library("async_util") {
}
-js_library("async_util_unittest") {
+js_unittest("async_util_unittest") {
deps = [
":async_util",
- ":unittest_util",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
-js_library("error_util") {
-}
-
js_library("files_app_entry_types") {
deps = [
"../../../externs:file_manager_private",
@@ -47,18 +58,20 @@ js_library("files_app_entry_types") {
externs_list = [ "../../../externs/volume_info.js" ]
}
-js_library("files_app_entry_types_unittest") {
+js_unittest("files_app_entry_types_unittest") {
deps = [
":files_app_entry_types",
- ":unittest_util",
- ":volume_manager_common",
+ ":mock_entry",
+ ":util",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/base/js:volume_manager_types",
]
}
js_library("file_type") {
deps = [
":files_app_entry_types",
- ":volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
]
}
@@ -70,31 +83,32 @@ js_library("importer_common") {
visibility = [ "//ui/file_manager/file_manager/*" ]
deps = [
":file_type",
- ":volume_manager_common",
"../../../externs:volume_manager",
+ "//ui/file_manager/base/js:volume_manager_types",
]
externs_list = [
- "//third_party/analytics/externs.js",
- "../../../externs/volume_info_list.js",
"../../../externs/background_window.js",
"../../../externs/background/file_browser_background.js",
]
}
js_library("test_importer_common") {
+ testonly = true
deps = [
":importer_common",
":unittest_util",
+ "//ui/file_manager/base/js:test_error_reporting",
]
visibility = []
visibility = [ "//ui/file_manager/file_manager/*" ]
}
-js_library("importer_common_unittest") {
+js_unittest("importer_common_unittest") {
deps = [
":mock_entry",
":test_importer_common",
":util",
+ "//ui/file_manager/base/js:mock_chrome",
"//ui/file_manager/file_manager/background/js:mock_volume_manager",
]
}
@@ -102,7 +116,7 @@ js_library("importer_common_unittest") {
js_library("lru_cache") {
}
-js_library("lru_cache_unittest") {
+js_unittest("lru_cache_unittest") {
deps = [
":lru_cache",
"//ui/webui/resources/js:webui_resource_test",
@@ -110,24 +124,17 @@ js_library("lru_cache_unittest") {
}
js_library("metrics") {
+ visibility = []
+ visibility = [ "//ui/file_manager/file_manager/*" ]
deps = [
":metrics_base",
"../../../externs:file_manager_private",
"//ui/webui/resources/js:assert",
]
- externs_list = [
- "$externs_path/metrics_private.js",
- "//third_party/analytics/externs.js",
- ]
}
js_library("metrics_base") {
-}
-
-js_library("metrics_events") {
- deps = [
- ":metrics_base",
- ]
+ externs_list = [ "$externs_path/metrics_private.js" ]
}
js_library("mock_entry") {
@@ -141,6 +148,11 @@ js_library("progress_center_common") {
}
js_library("unittest_util") {
+ testonly = true
+
+ # Only files app tests use this util file.
+ visibility = []
+ visibility = [ "//ui/file_manager/file_manager/*" ]
deps = [
"//ui/webui/resources/js:webui_resource_test",
]
@@ -150,8 +162,8 @@ js_library("unittest_util") {
js_library("util") {
deps = [
":files_app_entry_types",
- ":volume_manager_common",
"../../../externs:file_manager_private",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/webui/resources/js:load_time_data",
"//ui/webui/resources/js:util",
"//ui/webui/resources/js/cr:event_target",
@@ -165,17 +177,13 @@ js_library("util") {
]
}
-js_library("util_unittest") {
+js_unittest("util_unittest") {
deps = [
+ ":files_app_entry_types",
":mock_entry",
":unittest_util",
":util",
- ]
-}
-
-js_library("volume_manager_common") {
- deps = [
- "//ui/webui/resources/js:assert",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager",
]
}
@@ -188,17 +196,3 @@ js_unit_tests("unit_tests") {
":util_unittest",
]
}
-
-js_type_check("test_support_type_check") {
- deps = [
- ":test_importer_common",
- ]
-}
-
-group("closure_compile") {
- deps = [
- ":closure_compile_module",
- ":test_support_type_check",
- ":unit_tests_type_check",
- ]
-}
diff --git a/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn b/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn
new file mode 100644
index 00000000000..d2d7430c305
--- /dev/null
+++ b/chromium/ui/file_manager/file_manager/cws_widget/BUILD.gn
@@ -0,0 +1,50 @@
+# 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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":app_installer",
+ ":cws_webview_client",
+ ":cws_widget_container",
+ ":cws_widget_container_error_dialog",
+ ":cws_widget_container_platform_delegate",
+ ]
+}
+
+js_library("app_installer") {
+ deps = [
+ ":cws_widget_container_platform_delegate",
+ ]
+}
+
+js_library("cws_widget_container") {
+ deps = [
+ ":app_installer",
+ ":cws_webview_client",
+ ":cws_widget_container_error_dialog",
+ ]
+}
+
+js_library("cws_widget_container_error_dialog") {
+ deps = [
+ "//ui/webui/resources/js/cr/ui:dialogs",
+ ]
+}
+
+js_library("cws_widget_container_platform_delegate") {
+}
+
+js_library("cws_webview_client") {
+ deps = [
+ ":cws_widget_container_platform_delegate",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [
+ "$externs_path/chrome_extensions.js",
+ "../../externs/webview_tag.js",
+ ]
+}
diff --git a/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn b/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 2823093fb10..dfa0c48d7c9 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -10,6 +10,16 @@ visibility = [
"//ui/file_manager/file_manager/test/*",
]
+group("closure_compile") {
+ testonly = true
+ visibility += [ "//ui/file_manager:closure_compile" ]
+ deps = [
+ ":closure_compile_module",
+ ":test_support_type_check",
+ ":unit_tests_type_check",
+ ]
+}
+
js_type_check("closure_compile_module") {
deps = [
":actions_controller",
@@ -18,7 +28,6 @@ js_type_check("closure_compile_module") {
":closure_compile_externs",
":column_visibility_controller",
":constants",
- ":crostini",
":dialog_action_controller",
":dialog_type",
":directory_contents",
@@ -74,12 +83,11 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js",
"$externs_path/web_animations.js",
"../../../externs/app_window_common.js",
+ "../../../externs/background/crostini.js",
"../../../externs/background/drive_sync_handler.js",
"../../../externs/background/file_browser_background.js",
"../../../externs/background/file_browser_background_full.js",
"../../../externs/background/file_operation_manager.js",
- "../../../externs/background/import_history.js",
- "../../../externs/background/import_history_enum.js",
"../../../externs/background/import_runner.js",
"../../../externs/background/media_import_handler.js",
"../../../externs/background/media_scanner.js",
@@ -90,7 +98,6 @@ js_library("closure_compile_externs") {
"../../../externs/command_handler_deps.js",
"../../../externs/css_rule.js",
"../../../externs/directory_change_event.js",
- "../../../externs/drag_target.js",
"../../../externs/entries_changed_event.js",
"../../../externs/gallery_foreground.js",
"../../../externs/menu_item_update_event.js",
@@ -100,6 +107,17 @@ js_library("closure_compile_externs") {
]
}
+js_type_check("test_support_type_check") {
+ testonly = true
+ deps = [
+ ":mock_actions_model",
+ ":mock_directory_model",
+ ":mock_folder_shortcut_data_model",
+ ":mock_navigation_list_model",
+ ":mock_thumbnail_loader",
+ ]
+}
+
js_library("actions_controller") {
deps = [
":actions_model",
@@ -122,6 +140,46 @@ js_library("actions_model") {
"ui:list_container",
"//ui/webui/resources/js:cr",
]
+ externs_list = [ "../../../externs/background/drive_sync_handler.js" ]
+}
+
+js_library("mock_actions_model") {
+ testonly = true
+ deps = [
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+}
+
+js_library("mock_directory_model") {
+ testonly = true
+ deps = [
+ ":directory_contents",
+ ":directory_model",
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ "//ui/file_manager/file_manager/common/js:util",
+ ]
+}
+
+js_library("mock_folder_shortcut_data_model") {
+ testonly = true
+ deps = [
+ "//ui/file_manager/file_manager/common/js:mock_entry",
+ ]
+}
+
+js_library("mock_navigation_list_model") {
+ testonly = true
+ deps = [
+ ":navigation_list_model",
+ ]
+}
+
+js_library("mock_thumbnail_loader") {
+ testonly = true
+ deps = [
+ ":thumbnail_loader",
+ ]
}
js_library("app_state_controller") {
@@ -135,8 +193,8 @@ js_library("app_state_controller") {
js_library("column_visibility_controller") {
deps = [
":directory_model",
- "../../common/js:volume_manager_common",
"ui:file_manager_ui",
+ "//ui/file_manager/base/js:volume_manager_types",
]
}
@@ -158,10 +216,6 @@ js_library("dialog_action_controller") {
]
}
-js_library("crostini") {
- deps = []
-}
-
js_library("dialog_type") {
}
@@ -172,8 +226,8 @@ js_library("directory_contents") {
"../../common/js:async_util",
"../../common/js:metrics",
"../../common/js:util",
- "../../common/js:volume_manager_common",
"metadata:metadata_model",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js/cr/ui:array_data_model",
]
@@ -184,9 +238,12 @@ js_library("directory_model") {
":directory_contents",
":file_watcher",
"../../common/js:importer_common",
- "../../common/js:metrics_events",
"ui:file_list_selection_model",
]
+ externs_list = [
+ "../../../externs/background/file_operation_manager.js",
+ "../../../externs/entries_changed_event.js",
+ ]
}
js_library("navigation_uma") {
@@ -228,6 +285,13 @@ js_library("file_list_model") {
]
}
+js_unittest("file_list_model_unittest") {
+ deps = [
+ ":file_list_model",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("file_manager") {
deps = [
":app_state_controller",
@@ -292,9 +356,9 @@ js_library("file_selection") {
":directory_model",
"../../common/js:file_type",
"../../common/js:util",
- "../../common/js:volume_manager_common",
"metadata:metadata_model",
"ui:list_container",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:cr",
]
@@ -302,7 +366,6 @@ js_library("file_selection") {
js_library("file_tasks") {
deps = [
- ":crostini",
":directory_model",
":task_history",
"metadata:metadata_model",
@@ -331,7 +394,7 @@ js_library("file_watcher") {
deps = [
"../../common/js:async_util",
"../../common/js:util",
- "../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/webui/resources/js:assert",
]
}
@@ -339,10 +402,10 @@ js_library("file_watcher") {
js_library("folder_shortcuts_data_model") {
deps = [
"//ui/file_manager/base/js:filtered_volume_manager",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/file_manager/common/js:async_util",
"//ui/file_manager/file_manager/common/js:metrics",
"//ui/file_manager/file_manager/common/js:util",
- "//ui/file_manager/file_manager/common/js:volume_manager_common",
]
}
@@ -383,7 +446,7 @@ js_library("last_modified_controller") {
js_library("launch_param") {
deps = [
":dialog_type",
- "../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
]
}
@@ -392,8 +455,8 @@ js_library("list_thumbnail_loader") {
":directory_model",
":file_list_model",
":thumbnail_loader",
- "../../common/js:volume_manager_common",
"metadata:thumbnail_model",
+ "//ui/file_manager/base/js:volume_manager_types",
]
}
@@ -476,6 +539,16 @@ js_library("providers_model") {
]
}
+js_unittest("providers_model_unittest") {
+ deps = [
+ ":providers_model",
+ "//ui/file_manager/base/js:mock_chrome",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/file_manager/file_manager/background/js:mock_volume_manager",
+ "//ui/webui/resources/js:load_time_data",
+ ]
+}
+
js_library("quick_view_controller") {
deps = [
":dialog_type",
@@ -546,6 +619,15 @@ js_library("spinner_controller") {
]
}
+js_unittest("spinner_controller_unittest") {
+ deps = [
+ ":spinner_controller",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:util",
+ ]
+}
+
js_library("task_controller") {
deps = [
":dialog_type",
@@ -576,12 +658,11 @@ js_library("thumbnail_loader") {
]
}
-js_library("thumbnail_loader_unittest") {
+js_unittest("thumbnail_loader_unittest") {
deps = [
":thumbnail_loader",
"../../common/js:mock_entry",
- "../../common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -610,14 +691,9 @@ js_library("webui_command_extender") {
js_unit_tests("unit_tests") {
deps = [
+ ":file_list_model_unittest",
+ ":providers_model_unittest",
+ ":spinner_controller_unittest",
":thumbnail_loader_unittest",
]
}
-
-group("closure_compile") {
- visibility += [ "*" ]
- deps = [
- ":closure_compile_module",
- ":unit_tests_type_check",
- ]
-}
diff --git a/chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn b/chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
index a698efc533c..484fd968bc2 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
@@ -3,11 +3,12 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//third_party/closure_compiler/js_unit_tests.gni")
# TODO(tapted): This entire folder should move to //ui/file_manager/base.
visibility = [ "//ui/file_manager/*" ]
-js_type_check("closure_compile") {
+js_type_check("closure_compile_module") {
deps = [
":byte_reader",
":closure_compile_externs",
@@ -39,9 +40,7 @@ js_library("closure_compile_externs") {
sources = []
externs_list = [
"../../../../externs/app_window_common.js",
- "../../../../externs/entry_location.js",
"../../../../externs/platform.js",
- "../../../../externs/volume_info.js",
]
}
@@ -104,6 +103,13 @@ js_library("id3_parser") {
js_library("image_orientation") {
}
+js_unittest("image_orientation_unittest") {
+ deps = [
+ ":image_orientation",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("image_parsers") {
deps = [
":metadata_parser",
@@ -118,6 +124,13 @@ js_library("metadata_cache_item") {
]
}
+js_unittest("metadata_cache_item_unittest") {
+ deps = [
+ ":metadata_cache_item",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("metadata_cache_set") {
deps = [
":metadata_cache_item",
@@ -196,3 +209,27 @@ js_library("thumbnail_model") {
":metadata_model",
]
}
+
+js_unittest("thumbnail_model_unittest") {
+ deps = [
+ ":thumbnail_model",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
+js_unit_tests("unit_tests") {
+ deps = [
+ ":image_orientation_unittest",
+ ":metadata_cache_item_unittest",
+ ":thumbnail_model_unittest",
+ ]
+}
+
+group("closure_compile") {
+ testonly = true
+ deps = [
+ ":closure_compile_module",
+ ":unit_tests_type_check",
+ ]
+}
diff --git a/chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index 3462ef36301..c3cac1513c0 100644
--- a/chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -3,10 +3,20 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
+import("//third_party/closure_compiler/js_unit_tests.gni")
visibility = [ "//ui/file_manager/file_manager/foreground/*" ]
-js_type_check("closure_compile") {
+group("closure_compile") {
+ testonly = true
+ visibility += [ "//ui/file_manager:closure_compile" ]
+ deps = [
+ ":closure_compile_module",
+ ":unit_tests_type_check",
+ ]
+}
+
+js_type_check("closure_compile_module") {
deps = [
":actions_submenu",
":banners",
@@ -52,7 +62,6 @@ js_library("closure_compile_externs") {
"../../../../externs/background/file_browser_background.js",
"../../../../externs/background/file_operation_manager.js",
"../../../../externs/background/import_history.js",
- "../../../../externs/background/import_history_enum.js",
"../../../../externs/background_window.js",
"../../../../externs/chrome_echo_private.js",
"../../../../externs/chrome_webstore_widget_private.js",
@@ -64,7 +73,6 @@ js_library("closure_compile_externs") {
"../../../../externs/paper_elements.js",
"../../../../externs/platform.js",
"../../../../externs/search_item.js",
- "//third_party/analytics/externs.js",
]
}
@@ -77,11 +85,19 @@ js_library("actions_submenu") {
]
}
+js_unittest("actions_submenu_unittest") {
+ deps = [
+ ":actions_submenu",
+ "..:mock_actions_model",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("banners") {
deps = [
"..:directory_model",
"../../../common/js:util",
- "../../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js/cr:event_target",
]
@@ -127,8 +143,8 @@ js_library("directory_tree") {
"..:directory_model",
"..:navigation_list_model",
"../../../common/js:util",
- "../../../common/js:volume_manager_common",
"../metadata:metadata_model",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/webui/resources/js/cr/ui:context_menu_button",
"//ui/webui/resources/js/cr/ui:context_menu_handler",
"//ui/webui/resources/js/cr/ui:menu",
@@ -141,6 +157,7 @@ js_library("drag_selector") {
"//ui/webui/resources/js/cr:ui",
"//ui/webui/resources/js/cr/ui:list",
]
+ externs_list = [ "../../../../externs/drag_target.js" ]
}
js_library("empty_folder") {
@@ -167,6 +184,7 @@ js_library("file_grid") {
"../metadata:metadata_model",
"//ui/webui/resources/js/cr/ui:grid",
]
+ externs_list = [ "../../../../externs/background/import_history.js" ]
}
js_library("file_list_selection_model") {
@@ -176,6 +194,13 @@ js_library("file_list_selection_model") {
]
}
+js_unittest("file_list_selection_model_unittest") {
+ deps = [
+ ":file_list_selection_model",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("file_manager_dialog_base") {
deps = [
"//ui/webui/resources/js:cr",
@@ -207,11 +232,12 @@ js_library("file_manager_ui") {
":providers_menu",
":search_box",
":suggest_apps_dialog",
- "..:launch_param",
- "..:providers_model",
- "../../../common/js:util",
- "../../elements:files_toggle_ripple",
- "../../elements:files_tooltip",
+ "//ui/file_manager/file_manager/common/js:util",
+ "//ui/file_manager/file_manager/foreground/elements:files_toast",
+ "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple",
+ "//ui/file_manager/file_manager/foreground/elements:files_tooltip",
+ "//ui/file_manager/file_manager/foreground/js:launch_param",
+ "//ui/file_manager/file_manager/foreground/js:providers_model",
"//ui/webui/resources/js:i18n_template_no_process",
"//ui/webui/resources/js:util",
"//ui/webui/resources/js/cr/ui:context_menu_button",
@@ -237,6 +263,14 @@ js_library("file_table") {
"//ui/webui/resources/js:cr",
"//ui/webui/resources/js/cr/ui:table",
]
+ externs_list = [ "../../../../externs/background/import_history.js" ]
+}
+
+js_unittest("file_table_unittest") {
+ deps = [
+ ":file_table",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
}
js_library("file_table_list") {
@@ -257,6 +291,14 @@ js_library("file_tap_handler") {
]
}
+js_unittest("file_tap_handler_unittest") {
+ deps = [
+ ":file_tap_handler",
+ "//ui/file_manager/base/js:test_error_reporting",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
# TODO(tapted): Move this into //ui/file_manager/base.
js_library("files_alert_dialog") {
visibility += [ "//ui/file_manager/gallery/*" ]
@@ -306,7 +348,7 @@ js_library("location_line") {
"../../../common/js:files_app_entry_types",
"../../../common/js:metrics",
"../../../common/js:util",
- "../../../common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:volume_manager",
]
}
@@ -361,7 +403,16 @@ js_library("suggest_apps_dialog") {
"..:web_store_utils",
"../../../common/js:metrics",
"../../../common/js:util",
- "../../../common/js:volume_manager_common",
- "//components/chrome_apps/webstore_widget/cws_widget:cws_widget_container",
+ "../../../cws_widget:cws_widget_container",
+ "//ui/file_manager/base/js:volume_manager_types",
+ ]
+}
+
+js_unit_tests("unit_tests") {
+ deps = [
+ ":actions_submenu_unittest",
+ ":file_list_selection_model_unittest",
+ ":file_table_unittest",
+ ":file_tap_handler_unittest",
]
}
diff --git a/chromium/ui/file_manager/file_manager/test/BUILD.gn b/chromium/ui/file_manager/file_manager/test/BUILD.gn
index 7c5254a8c5c..6f5cffa33e3 100644
--- a/chromium/ui/file_manager/file_manager/test/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/test/BUILD.gn
@@ -21,9 +21,11 @@ action("create_test_main") {
"//chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc",
"//ui/webui/resources/css/text_defaults.css",
"check_select.js",
- "crostini.js",
+ "crostini_mount.js",
+ "crostini_share.js",
+ "crostini_tasks.js",
"js/strings.js",
- "quick_view.js",
+ "progress_center.js",
"uma.js",
]
args = [ "--output=" + rebase_path(output, root_build_dir) ]
@@ -36,8 +38,10 @@ js_type_check("closure_compile") {
deps = [
":check_select",
":closure_compile_externs",
- ":crostini",
- ":quick_view",
+ ":crostini_mount",
+ ":crostini_share",
+ ":crostini_tasks",
+ ":progress_center",
":uma",
]
}
@@ -51,13 +55,14 @@ js_library("closure_compile_externs") {
"js/externs.js",
"$externs_path/command_line_private.js",
"$externs_path/metrics_private.js",
- "../../externs/app_window_common.js",
- "../../externs/background/file_browser_background.js",
- "../../externs/entry_location.js",
- "../../externs/volume_info.js",
- "../../externs/volume_info_list.js",
- "../../externs/volume_manager.js",
- "//third_party/analytics/externs.js",
+ "//ui/file_manager/externs/app_window_common.js",
+ "//ui/file_manager/externs/background/file_browser_background.js",
+ "//ui/file_manager/externs/background/progress_center.js",
+ "//ui/file_manager/externs/background/crostini.js",
+ "//ui/file_manager/externs/entry_location.js",
+ "//ui/file_manager/externs/volume_info.js",
+ "//ui/file_manager/externs/volume_info_list.js",
+ "//ui/file_manager/externs/volume_manager.js",
]
}
@@ -68,21 +73,35 @@ js_library("check_select") {
]
}
-js_library("crostini") {
+js_library("crostini_mount") {
deps = [
- "../foreground/js:crostini",
"js:test_util",
"//ui/webui/resources/js:webui_resource_test",
]
}
-js_library("quick_view") {
+js_library("crostini_share") {
deps = [
"js:test_util",
"//ui/webui/resources/js:webui_resource_test",
]
}
+js_library("crostini_tasks") {
+ deps = [
+ "js:test_util",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
+js_library("progress_center") {
+ deps = [
+ "js:test_util",
+ "//ui/file_manager/file_manager/common/js:progress_center_common",
+ "//ui/webui/resources/js:webui_resource_test",
+ ]
+}
+
js_library("uma") {
deps = [
"js:test_util",
diff --git a/chromium/ui/file_manager/file_manager/test/js/BUILD.gn b/chromium/ui/file_manager/file_manager/test/js/BUILD.gn
index df093277383..8d2f5b05099 100644
--- a/chromium/ui/file_manager/file_manager/test/js/BUILD.gn
+++ b/chromium/ui/file_manager/file_manager/test/js/BUILD.gn
@@ -25,7 +25,7 @@ js_library("strings") {
js_library("test_util") {
deps = [
":chrome_file_manager_private_test_impl",
- "../../background/js:test_util_base",
+ "../../background/js:runtime_loaded_test_util",
"../../foreground/js:constants",
"//ui/webui/resources/js:webui_resource_test",
]
diff --git a/chromium/ui/file_manager/gallery/js/BUILD.gn b/chromium/ui/file_manager/gallery/js/BUILD.gn
index 17e71d7f579..6f092ca3401 100644
--- a/chromium/ui/file_manager/gallery/js/BUILD.gn
+++ b/chromium/ui/file_manager/gallery/js/BUILD.gn
@@ -43,7 +43,7 @@ js_library("dimmable_ui_controller") {
]
}
-js_library("dimmable_ui_controller_unittest") {
+js_unittest("dimmable_ui_controller_unittest") {
deps = [
":dimmable_ui_controller",
"//ui/webui/resources/js:webui_resource_test",
@@ -58,12 +58,11 @@ js_library("entry_list_watcher") {
]
}
-js_library("entry_list_watcher_unittest") {
+js_unittest("entry_list_watcher_unittest") {
deps = [
":entry_list_watcher",
"../../file_manager/common/js:mock_entry",
- "../../file_manager/common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -100,18 +99,18 @@ js_library("gallery_data_model") {
]
}
-js_library("gallery_data_model_unittest") {
+js_unittest("gallery_data_model_unittest") {
deps = [
":gallery_data_model",
":mock_gallery_item",
- "../../file_manager/common/js:unittest_util",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
js_library("gallery_item") {
deps = [
+ ":gallery_metrics",
":gallery_util",
- "../../file_manager/common/js:metrics",
"../../file_manager/common/js:util",
"../../file_manager/foreground/js/metadata:metadata_model",
"../../file_manager/foreground/js/metadata:thumbnail_model",
@@ -121,12 +120,17 @@ js_library("gallery_item") {
externs_list = [ "../../externs/entry_location.js" ]
}
-js_library("gallery_item_unittest") {
+js_unittest("gallery_item_unittest") {
deps = [
":gallery_item",
":mock_gallery_item",
- "../../file_manager/common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
+ ]
+}
+
+js_library("gallery_metrics") {
+ deps = [
+ "../../file_manager/common/js:metrics_base",
]
}
@@ -134,17 +138,16 @@ js_library("gallery_util") {
deps = [
"../../file_manager/common/js:file_type",
"../../file_manager/common/js:util",
- "../../file_manager/common/js:volume_manager_common",
+ "//ui/file_manager/base/js:volume_manager_types",
"//ui/file_manager/externs:volume_manager",
]
}
-js_library("gallery_util_unittest") {
+js_unittest("gallery_util_unittest") {
deps = [
":gallery_util",
"../../file_manager/common/js:mock_entry",
- "../../file_manager/common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -171,7 +174,7 @@ js_library("ribbon") {
]
}
-js_library("ribbon_unittest") {
+js_unittest("ribbon_unittest") {
deps = [
":ribbon",
]
@@ -184,8 +187,8 @@ js_library("slide_mode") {
":gallery_constants",
":gallery_data_model",
":gallery_item",
+ ":gallery_metrics",
":ribbon",
- "../../file_manager/common/js:metrics",
"../../file_manager/common/js:util",
"../../file_manager/foreground/elements:files_toggle_ripple",
"image_editor:image_adjust",
@@ -199,11 +202,10 @@ js_library("slide_mode") {
externs_list = [ "../../externs/gallery_foreground.js" ]
}
-js_library("slide_mode_unittest") {
+js_unittest("slide_mode_unittest") {
deps = [
":slide_mode",
- "../../file_manager/common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -233,6 +235,7 @@ js_unit_tests("unit_tests") {
}
group("closure_compile") {
+ testonly = true
deps = [
":closure_compile_module",
":unit_tests_type_check",
diff --git a/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn b/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn
index e7a6675b35f..dc6be09e7c5 100644
--- a/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn
+++ b/chromium/ui/file_manager/gallery/js/image_editor/BUILD.gn
@@ -47,7 +47,7 @@ js_library("exif_encoder") {
externs_list = [ "../../../externs/exif_entry.js" ]
}
-js_library("exif_encoder_unittest") {
+js_unittest("exif_encoder_unittest") {
deps = [
":exif_encoder",
":test_util",
@@ -120,12 +120,12 @@ js_library("image_encoder") {
]
}
-js_library("image_encoder_unittest") {
+js_unittest("image_encoder_unittest") {
deps = [
":image_encoder",
":test_util",
- "../../../file_manager/common/js:unittest_util",
"../../../file_manager/foreground/js/metadata:metadata_parser",
+ "//ui/file_manager/base/js:test_error_reporting",
]
externs_list = [ "../../../externs/metadata_worker_window.js" ]
}
@@ -173,13 +173,13 @@ js_library("image_view") {
":image_util",
":viewport",
"..:gallery_item",
- "../../../file_manager/common/js:metrics",
+ "../../../file_manager/common/js:metrics_base",
"../../../file_manager/foreground/js:thumbnail_loader",
"//ui/webui/resources/js:assert",
]
}
-js_library("image_view_unittest") {
+js_unittest("image_view_unittest") {
deps = [
":image_view",
"..:mock_gallery_item",
@@ -207,6 +207,7 @@ js_unit_tests("unit_tests") {
}
group("closure_compile") {
+ testonly = true
deps = [
":closure_compile_module",
":unit_tests_type_check",
diff --git a/chromium/ui/file_manager/image_loader/BUILD.gn b/chromium/ui/file_manager/image_loader/BUILD.gn
index f88321191fc..dc89286508e 100644
--- a/chromium/ui/file_manager/image_loader/BUILD.gn
+++ b/chromium/ui/file_manager/image_loader/BUILD.gn
@@ -29,7 +29,7 @@ js_library("background") {
js_library("cache") {
}
-js_library("cache_unittest") {
+js_unittest("cache_unittest") {
deps = [
":cache",
":load_image_request",
@@ -48,7 +48,7 @@ js_library("image_loader") {
]
}
-js_library("image_loader_unittest") {
+js_unittest("image_loader_unittest") {
deps = [
":image_loader",
"//ui/webui/resources/js:webui_resource_test",
@@ -82,11 +82,10 @@ js_library("image_loader_client") {
]
}
-js_library("image_loader_client_unittest") {
+js_unittest("image_loader_client_unittest") {
deps = [
":image_loader_client",
- "../file_manager/common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -97,11 +96,10 @@ js_library("piex_loader") {
]
}
-js_library("piex_loader_unittest") {
+js_unittest("piex_loader_unittest") {
deps = [
":piex_loader",
- "../file_manager/common/js:unittest_util",
- "//ui/webui/resources/js:webui_resource_test",
+ "//ui/file_manager/base/js:test_error_reporting",
]
}
@@ -112,8 +110,6 @@ js_library("request") {
":load_image_request",
":piex_loader",
"../file_manager/common/js:file_type",
- "../file_manager/common/js:metrics",
- "../file_manager/common/js:metrics_events",
]
externs_list = [ "../externs/platform.js" ]
}
@@ -135,6 +131,7 @@ js_unit_tests("unit_tests") {
}
group("closure_compile") {
+ testonly = true
deps = [
":closure_compile_module",
":unit_tests_type_check",
diff --git a/chromium/ui/file_manager/video_player/js/BUILD.gn b/chromium/ui/file_manager/video_player/js/BUILD.gn
index e00d4b6fb28..23e98f8768f 100644
--- a/chromium/ui/file_manager/video_player/js/BUILD.gn
+++ b/chromium/ui/file_manager/video_player/js/BUILD.gn
@@ -24,7 +24,6 @@ js_library("closure_compile_externs") {
"$externs_path/metrics_private.js",
"../../externs/chrome_cast.js",
"../../externs/platform.js",
- "//third_party/analytics/externs.js",
]
}
@@ -59,7 +58,7 @@ js_library("video_player") {
"cast:cast_video_element",
"cast:media_manager",
"//ui/file_manager/base/js:filtered_volume_manager",
- "//ui/file_manager/file_manager/common/js:metrics",
+ "//ui/file_manager/file_manager/common/js:metrics_base",
"//ui/file_manager/file_manager/common/js:util",
"//ui/file_manager/image_loader:image_loader_client",
"//ui/webui/resources/js:i18n_template_no_process",
diff --git a/chromium/ui/file_manager/video_player/js/cast/BUILD.gn b/chromium/ui/file_manager/video_player/js/cast/BUILD.gn
index 6071386427a..02cddc535b2 100644
--- a/chromium/ui/file_manager/video_player/js/cast/BUILD.gn
+++ b/chromium/ui/file_manager/video_player/js/cast/BUILD.gn
@@ -19,12 +19,10 @@ js_library("closure_compile_externs") {
externs_list = [
"$externs_path/chrome_extensions.js",
"$externs_path/media_player_private.js",
- "$externs_path/metrics_private.js",
"../../../externs/app_window_common.js",
"../../../externs/background/volume_manager_factory.js",
"../../../externs/chrome_cast.js",
"../../../externs/platform.js",
- "//third_party/analytics/externs.js",
]
}
diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn
index b9e0290dba2..d0dbfa2c6d5 100644
--- a/chromium/ui/gfx/BUILD.gn
+++ b/chromium/ui/gfx/BUILD.gn
@@ -86,8 +86,6 @@ jumbo_component("gfx") {
"font_render_params_win.cc",
"gdi_util.cc",
"gdi_util.h",
- "gfx_paths.cc",
- "gfx_paths.h",
"half_float.cc",
"half_float.h",
"icon_util.cc",
@@ -120,8 +118,6 @@ jumbo_component("gfx") {
"ios/NSString+CrStringDrawing.mm",
"ios/uikit_util.h",
"ios/uikit_util.mm",
- "linux_font_delegate.cc",
- "linux_font_delegate.h",
"mac/coordinate_conversion.h",
"mac/coordinate_conversion.mm",
"mac/nswindow_frame_controls.h",
@@ -141,8 +137,6 @@ jumbo_component("gfx") {
"platform_font.h",
"platform_font_ios.h",
"platform_font_ios.mm",
- "platform_font_linux.cc",
- "platform_font_linux.h",
"platform_font_mac.h",
"platform_font_mac.mm",
"platform_font_win.cc",
@@ -223,8 +217,6 @@ jumbo_component("gfx") {
"skia_vector_animation.cc",
"skia_vector_animation.h",
"skia_vector_animation_observer.h",
- "skottie_wrapper.cc",
- "skottie_wrapper.h",
]
} else {
sources += [
@@ -271,13 +263,13 @@ jumbo_component("gfx") {
"//third_party/zlib",
]
- if (is_android) {
- set_sources_assignment_filter([])
+ if (is_linux || is_android || is_fuchsia) {
sources += [
- "platform_font_linux.cc",
- "platform_font_linux.h",
+ "platform_font_skia.cc",
+ "platform_font_skia.h",
+ "skia_font_delegate.cc",
+ "skia_font_delegate.h",
]
- set_sources_assignment_filter(sources_assignment_filter)
}
# iOS.
@@ -371,7 +363,6 @@ jumbo_component("gfx") {
sources += [
"font_fallback_fuchsia.cc",
"font_render_params_fuchsia.cc",
- "platform_font_fuchsia.cc",
]
}
}
@@ -419,6 +410,7 @@ source_set("native_widget_types") {
]
public_deps = [
+ ":gfx_export",
"//base",
]
}
@@ -493,7 +485,6 @@ jumbo_source_set("memory_buffer_sources") {
"ca_layer_params.cc",
"ca_layer_params.h",
"client_native_pixmap.h",
- "client_native_pixmap_factory.cc",
"client_native_pixmap_factory.h",
"generic_shared_memory_id.cc",
"generic_shared_memory_id.h",
@@ -539,7 +530,7 @@ jumbo_source_set("memory_buffer_sources") {
"linux/native_pixmap_dmabuf.h",
]
- deps += [ "//third_party/libdrm" ]
+ deps += [ "//build/config/linux/libdrm" ]
}
if (is_linux || is_android) {
@@ -625,7 +616,6 @@ test("gfx_unittests") {
"image/image_unittest.cc",
"ios/NSString+CrStringDrawing_unittest.mm",
"ios/uikit_util_unittest.mm",
- "platform_font_linux_unittest.cc",
"test/run_all_unittests.cc",
"text_elider_unittest.cc",
"text_utils_unittest.cc",
@@ -694,6 +684,10 @@ test("gfx_unittests") {
]
}
+ if (is_linux || is_android || is_fuchsia) {
+ sources += [ "platform_font_skia_unittest.cc" ]
+ }
+
if (!is_ios) {
sources += [ "paint_vector_icon_unittest.cc" ]
}
diff --git a/chromium/ui/gfx/OWNERS b/chromium/ui/gfx/OWNERS
index 225898fbe52..a146a9e20bb 100644
--- a/chromium/ui/gfx/OWNERS
+++ b/chromium/ui/gfx/OWNERS
@@ -28,16 +28,21 @@ per-file skia_paint_util*=danakj@chromium.org
per-file gpu_fence*=reveman@chromium.org
per-file gpu_fence*=dcastagna@chromium.org
per-file gpu_fence*=rjkroege@chromium.org
+per-file gpu_fence*=spang@chromium.org
per-file gpu_memory_buffer*=reveman@chromium.org
per-file gpu_memory_buffer*=dcastagna@chromium.org
per-file gpu_memory_buffer*=rjkroege@chromium.org
+per-file gpu_memory_buffer*=spang@chromium.org
per-file buffer_format*=reveman@chromium.org
per-file buffer_format*=dcastagna@chromium.org
per-file buffer_format*=rjkroege@chromium.org
+per-file buffer_format*=spang@chromium.org
per-file *buffer_types.*=reveman@chromium.org
per-file *buffer_types.*=dcastagna@chromium.org
per-file *buffer_types.*=rjkroege@chromium.org
-per-file *pixmap.*=rjkroege@chromium.org
+per-file *buffer_types.*=spang@chromium.org
+per-file *native_pixmap*=rjkroege@chromium.org
+per-file *native_pixmap*=spang@chromium.org
# Vector icons.
per-file *vector_icon*=estade@chromium.org
diff --git a/chromium/ui/gfx/animation/animation_mac.mm b/chromium/ui/gfx/animation/animation_mac.mm
index e3f1b1f8237..99a841c4b16 100644
--- a/chromium/ui/gfx/animation/animation_mac.mm
+++ b/chromium/ui/gfx/animation/animation_mac.mm
@@ -15,8 +15,8 @@ namespace gfx {
bool Animation::ScrollAnimationsEnabledBySystem() {
// Because of sandboxing, OS settings should only be queried from the browser
// process.
- DCHECK(base::MessageLoopForUI::IsCurrent() ||
- base::MessageLoopForIO::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet() ||
+ base::MessageLoopCurrentForIO::IsSet());
bool enabled = false;
id value = nil;
diff --git a/chromium/ui/gfx/blit_unittest.cc b/chromium/ui/gfx/blit_unittest.cc
index 98a80a36fc7..1d70915a0b4 100644
--- a/chromium/ui/gfx/blit_unittest.cc
+++ b/chromium/ui/gfx/blit_unittest.cc
@@ -4,7 +4,7 @@
#include <stdint.h>
-#include "base/memory/shared_memory.h"
+#include "base/memory/platform_shared_memory_region.h"
#include "build/build_config.h"
#include "skia/ext/platform_canvas.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -148,15 +148,17 @@ TEST(Blit, ScrollCanvas) {
TEST(Blit, WithSharedMemory) {
const int kCanvasWidth = 5;
const int kCanvasHeight = 5;
- base::SharedMemory shared_mem;
- ASSERT_TRUE(shared_mem.CreateAnonymous(kCanvasWidth * kCanvasHeight));
- base::SharedMemoryHandle section = shared_mem.handle();
+ base::subtle::PlatformSharedMemoryRegion section =
+ base::subtle::PlatformSharedMemoryRegion::CreateWritable(kCanvasWidth *
+ kCanvasHeight);
+ ASSERT_TRUE(section.IsValid());
std::unique_ptr<SkCanvas> canvas =
- skia::CreatePlatformCanvasWithSharedSection(kCanvasWidth, kCanvasHeight,
- false, section.GetHandle(),
- skia::RETURN_NULL_ON_FAILURE);
+ skia::CreatePlatformCanvasWithSharedSection(
+ kCanvasWidth, kCanvasHeight, false, section.GetPlatformHandle(),
+ skia::RETURN_NULL_ON_FAILURE);
ASSERT_TRUE(canvas);
- shared_mem.Close();
+ // Closes a HANDLE associated with |section|, |canvas| must remain valid.
+ section = base::subtle::PlatformSharedMemoryRegion();
uint8_t initial_values[kCanvasHeight][kCanvasWidth] = {
{0x00, 0x01, 0x02, 0x03, 0x04},
diff --git a/chromium/ui/gfx/canvas.cc b/chromium/ui/gfx/canvas.cc
index 21b6e1358a6..5cd71db6015 100644
--- a/chromium/ui/gfx/canvas.cc
+++ b/chromium/ui/gfx/canvas.cc
@@ -441,6 +441,12 @@ void Canvas::DrawImageInPath(const ImageSkia& image,
canvas_->drawPath(path, flags);
}
+void Canvas::DrawSkottie(scoped_refptr<cc::SkottieWrapper> skottie,
+ const Rect& dst,
+ float t) {
+ canvas_->drawSkottie(std::move(skottie), RectToSkRect(dst), t);
+}
+
void Canvas::DrawStringRect(const base::string16& text,
const FontList& font_list,
SkColor color,
diff --git a/chromium/ui/gfx/canvas.h b/chromium/ui/gfx/canvas.h
index 06de8f274ec..96e77c8b0af 100644
--- a/chromium/ui/gfx/canvas.h
+++ b/chromium/ui/gfx/canvas.h
@@ -20,6 +20,10 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/text_constants.h"
+namespace cc {
+class SkottieWrapper;
+} // namespace cc
+
namespace gfx {
class Rect;
@@ -69,7 +73,7 @@ class GFX_EXPORT Canvas {
// Specifies if words can be split by new lines.
// This only works with MULTI_LINE.
- CHARACTER_BREAK = 1 << 8,
+ CHARACTER_BREAKABLE = 1 << 8,
// Instructs DrawStringRect() to not use subpixel rendering. This is useful
// when rendering text onto a fully- or partially-transparent background
@@ -360,6 +364,13 @@ class GFX_EXPORT Canvas {
const SkPath& path,
const cc::PaintFlags& flags);
+ // Draws the frame of the |skottie| animation specified by the normalized time
+ // instant t [0->first frame .. 1->last frame] onto the region corresponded by
+ // |dst| in the canvas.
+ void DrawSkottie(scoped_refptr<cc::SkottieWrapper> skottie,
+ const Rect& dst,
+ float t);
+
// Draws text with the specified color, fonts and location. The text is
// aligned to the left, vertically centered, clipped to the region. If the
// text is too big, it is truncated and '...' is added to the end.
diff --git a/chromium/ui/gfx/canvas_skia.cc b/chromium/ui/gfx/canvas_skia.cc
index 59ad113713d..3711f05dcdf 100644
--- a/chromium/ui/gfx/canvas_skia.cc
+++ b/chromium/ui/gfx/canvas_skia.cc
@@ -108,7 +108,7 @@ void Canvas::SizeStringFloat(const base::string16& text,
if ((flags & MULTI_LINE) && *width != 0) {
WordWrapBehavior wrap_behavior = TRUNCATE_LONG_WORDS;
- if (flags & CHARACTER_BREAK)
+ if (flags & CHARACTER_BREAKABLE)
wrap_behavior = WRAP_LONG_WORDS;
else if (!(flags & NO_ELLIPSIS))
wrap_behavior = ELIDE_LONG_WORDS;
@@ -169,7 +169,7 @@ void Canvas::DrawStringRectWithFlags(const base::string16& text,
if (flags & MULTI_LINE) {
WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS;
- if (flags & CHARACTER_BREAK)
+ if (flags & CHARACTER_BREAKABLE)
wrap_behavior = WRAP_LONG_WORDS;
else if (!(flags & NO_ELLIPSIS))
wrap_behavior = ELIDE_LONG_WORDS;
diff --git a/chromium/ui/gfx/canvas_unittest_mac.mm b/chromium/ui/gfx/canvas_unittest_mac.mm
index 78d0487ceba..8cff0152ecc 100644
--- a/chromium/ui/gfx/canvas_unittest_mac.mm
+++ b/chromium/ui/gfx/canvas_unittest_mac.mm
@@ -24,9 +24,7 @@ float GetStringNativeWidth(const base::string16& text,
const FontList& font_list) {
NSFont* native_font = font_list.GetPrimaryFont().GetNativeFont();
NSString* ns_string = base::SysUTF16ToNSString(text);
- NSDictionary* attributes =
- [NSDictionary dictionaryWithObject:native_font
- forKey:NSFontAttributeName];
+ NSDictionary* attributes = @{NSFontAttributeName : native_font};
return [ns_string sizeWithAttributes:attributes].width;
}
diff --git a/chromium/ui/gfx/client_native_pixmap_factory.cc b/chromium/ui/gfx/client_native_pixmap_factory.cc
deleted file mode 100644
index 7a4354f2507..00000000000
--- a/chromium/ui/gfx/client_native_pixmap_factory.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/client_native_pixmap_factory.h"
-
-namespace gfx {
-
-ClientNativePixmapFactory::ClientNativePixmapFactory() {}
-
-ClientNativePixmapFactory::~ClientNativePixmapFactory() {}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/client_native_pixmap_factory.h b/chromium/ui/gfx/client_native_pixmap_factory.h
index fff5b4cd179..d7e3f656a54 100644
--- a/chromium/ui/gfx/client_native_pixmap_factory.h
+++ b/chromium/ui/gfx/client_native_pixmap_factory.h
@@ -23,25 +23,14 @@ class Size;
// provide a client pixmap for non-GPU processes.
class GFX_EXPORT ClientNativePixmapFactory {
public:
- virtual ~ClientNativePixmapFactory();
+ virtual ~ClientNativePixmapFactory() {}
- // Returns true if format/usage configuration is supported.
- virtual bool IsConfigurationSupported(gfx::BufferFormat format,
- gfx::BufferUsage usage) const = 0;
-
- // TODO(dshwang): implement it. crbug.com/475633
// Import the native pixmap from |handle| to be used in non-GPU processes.
// This function takes ownership of any file descriptors in |handle|.
virtual std::unique_ptr<ClientNativePixmap> ImportFromHandle(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size,
gfx::BufferUsage usage) = 0;
-
- protected:
- ClientNativePixmapFactory();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ClientNativePixmapFactory);
};
} // namespace gfx
diff --git a/chromium/ui/gfx/color_palette.h b/chromium/ui/gfx/color_palette.h
index 7b2d2358891..d17425b1e54 100644
--- a/chromium/ui/gfx/color_palette.h
+++ b/chromium/ui/gfx/color_palette.h
@@ -15,6 +15,7 @@ constexpr SkColor kPlaceholderColor = SK_ColorRED;
// The number refers to the shade of darkness. Each color in the MD
// palette ranges from 050-900.
+constexpr SkColor kGoogleBlue100 = SkColorSetRGB(0xD2, 0xE3, 0xFC);
constexpr SkColor kGoogleBlue300 = SkColorSetRGB(0x8A, 0xB4, 0xF8);
constexpr SkColor kGoogleBlue500 = SkColorSetRGB(0x42, 0x85, 0xF4);
constexpr SkColor kGoogleBlue600 = SkColorSetRGB(0x1A, 0x73, 0xE8);
diff --git a/chromium/ui/gfx/color_space.cc b/chromium/ui/gfx/color_space.cc
index 95f8665d61f..7984428cbb9 100644
--- a/chromium/ui/gfx/color_space.cc
+++ b/chromium/ui/gfx/color_space.cc
@@ -375,6 +375,7 @@ std::string ColorSpace::ToString() const {
PRINT_ENUM_CASE(MatrixID, BT2020_NCL)
PRINT_ENUM_CASE(MatrixID, BT2020_CL)
PRINT_ENUM_CASE(MatrixID, YDZDX)
+ PRINT_ENUM_CASE(MatrixID, GBR)
}
ss << ", range:";
switch (range_) {
@@ -883,6 +884,14 @@ void ColorSpace::GetTransferMatrix(SkMatrix44* matrix) const {
matrix->setRowMajorf(data);
return;
}
+ case ColorSpace::MatrixID::GBR: {
+ float data[16] = {0.0f, 1.0f, 0.0f, 0.0f, // G
+ 0.0f, 0.0f, 1.0f, 0.0f, // B
+ 1.0f, 0.0f, 0.0f, 0.0f, // R
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ matrix->setRowMajorf(data);
+ return;
+ }
}
float Kg = 1.0f - Kr - Kb;
float u_m = 0.5f / (1.0f - Kb);
@@ -909,6 +918,7 @@ void ColorSpace::GetRangeAdjustMatrix(SkMatrix44* matrix) const {
}
switch (matrix_) {
case MatrixID::RGB:
+ case MatrixID::GBR:
case MatrixID::INVALID:
case MatrixID::YCOCG:
matrix->setScale(255.0f/219.0f, 255.0f/219.0f, 255.0f/219.0f);
diff --git a/chromium/ui/gfx/color_space.h b/chromium/ui/gfx/color_space.h
index 862edfa8c15..f238b5383de 100644
--- a/chromium/ui/gfx/color_space.h
+++ b/chromium/ui/gfx/color_space.h
@@ -105,7 +105,8 @@ class COLOR_SPACE_EXPORT ColorSpace {
BT2020_NCL,
BT2020_CL,
YDZDX,
- LAST = YDZDX,
+ GBR,
+ LAST = GBR,
};
enum class RangeID : uint8_t {
diff --git a/chromium/ui/gfx/color_space_win.cc b/chromium/ui/gfx/color_space_win.cc
index a4541e08b68..9e5a0fc8e34 100644
--- a/chromium/ui/gfx/color_space_win.cc
+++ b/chromium/ui/gfx/color_space_win.cc
@@ -44,6 +44,7 @@ DXVA2_ExtendedFormat ColorSpaceWin::GetExtendedFormat(
break;
case gfx::ColorSpace::MatrixID::RGB:
+ case gfx::ColorSpace::MatrixID::GBR:
case gfx::ColorSpace::MatrixID::FCC:
case gfx::ColorSpace::MatrixID::YCOCG:
case gfx::ColorSpace::MatrixID::BT2020_NCL:
@@ -226,6 +227,7 @@ D3D11_VIDEO_PROCESSOR_COLOR_SPACE ColorSpaceWin::GetD3D11ColorSpace(
case gfx::ColorSpace::MatrixID::SMPTE240M:
case gfx::ColorSpace::MatrixID::RGB:
+ case gfx::ColorSpace::MatrixID::GBR:
case gfx::ColorSpace::MatrixID::FCC:
case gfx::ColorSpace::MatrixID::YCOCG:
case gfx::ColorSpace::MatrixID::BT2020_NCL:
diff --git a/chromium/ui/gfx/color_transform_unittest.cc b/chromium/ui/gfx/color_transform_unittest.cc
index 77c85b84902..96cab26abdf 100644
--- a/chromium/ui/gfx/color_transform_unittest.cc
+++ b/chromium/ui/gfx/color_transform_unittest.cc
@@ -458,12 +458,7 @@ TEST(SimpleColorSpace, ShaderSourceTrFnOptimizations) {
// to make reviewing shader code simpler by giving an example of the resulting
// shader source. This should be updated whenever shader generation is updated.
// This test produces slightly different results on Android.
-#if defined(OS_ANDROID)
-#define MAYBE_SampleShaderSource DISABLED_SampleShaderSource
-#else
-#define MAYBE_SampleShaderSource SampleShaderSource
-#endif
-TEST(SimpleColorSpace, MAYBE_SampleShaderSource) {
+TEST(SimpleColorSpace, SampleShaderSource) {
ColorSpace bt709 = ColorSpace::CreateREC709();
ColorSpace output(ColorSpace::PrimaryID::BT2020,
ColorSpace::TransferID::GAMMA28);
diff --git a/chromium/ui/gfx/color_utils.cc b/chromium/ui/gfx/color_utils.cc
index 6bb5a66e51e..9edd09b4180 100644
--- a/chromium/ui/gfx/color_utils.cc
+++ b/chromium/ui/gfx/color_utils.cc
@@ -443,7 +443,7 @@ void SetDarkestColor(SkColor color) {
g_color_utils_luma_midpoint = (GetLuma(color) + 255) / 2;
}
-SkColor GetDarkestColorForTesting() {
+SkColor GetDarkestColor() {
return g_color_utils_darkest;
}
diff --git a/chromium/ui/gfx/color_utils.h b/chromium/ui/gfx/color_utils.h
index 75e2e83d440..80b3504cd93 100644
--- a/chromium/ui/gfx/color_utils.h
+++ b/chromium/ui/gfx/color_utils.h
@@ -189,7 +189,7 @@ GFX_EXPORT std::string SkColorToRgbString(SkColor color);
GFX_EXPORT void SetDarkestColor(SkColor color);
// Returns the current color_utils darkest color so tests can clean up.
-GFX_EXPORT SkColor GetDarkestColorForTesting();
+GFX_EXPORT SkColor GetDarkestColor();
} // namespace color_utils
diff --git a/chromium/ui/gfx/color_utils_unittest.cc b/chromium/ui/gfx/color_utils_unittest.cc
index bb0a5426aa7..bb39cacb219 100644
--- a/chromium/ui/gfx/color_utils_unittest.cc
+++ b/chromium/ui/gfx/color_utils_unittest.cc
@@ -205,7 +205,7 @@ TEST(ColorUtils, SkColorToRgbString) {
}
TEST(ColorUtils, IsDarkDarkestColorChange) {
- SkColor old_black_color = GetDarkestColorForTesting();
+ SkColor old_black_color = GetDarkestColor();
ASSERT_FALSE(IsDark(SkColorSetARGB(255, 200, 200, 200)));
SetDarkestColor(SkColorSetARGB(255, 200, 200, 200));
@@ -236,7 +236,7 @@ TEST(ColorUtils, GetColorWithMinimumContrast_BlendLighter) {
}
TEST(ColorUtils, GetColorWithMinimumContrast_StopsAtDarkestColor) {
- SkColor old_black_color = GetDarkestColorForTesting();
+ SkColor old_black_color = GetDarkestColor();
const SkColor darkest_color = SkColorSetRGB(0x44, 0x44, 0x44);
SetDarkestColor(darkest_color);
diff --git a/chromium/ui/gfx/font_fallback_win.cc b/chromium/ui/gfx/font_fallback_win.cc
index e18fb411fc8..3da6eee3039 100644
--- a/chromium/ui/gfx/font_fallback_win.cc
+++ b/chromium/ui/gfx/font_fallback_win.cc
@@ -16,9 +16,12 @@
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/registry.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_fallback.h"
@@ -76,6 +79,7 @@ void AppendFont(const std::string& name, int size, std::vector<Font>* fonts) {
void QueryLinkedFontsFromRegistry(const Font& font,
std::map<std::string, std::string>* font_map,
std::vector<Font>* linked_fonts) {
+ std::string logging_str;
const wchar_t* kSystemLink =
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink";
@@ -90,11 +94,18 @@ void QueryLinkedFontsFromRegistry(const Font& font,
return;
}
+ base::StringAppendF(&logging_str, "Original font: %s\n",
+ font.GetFontName().c_str());
+
std::string filename;
std::string font_name;
for (size_t i = 0; i < values.size(); ++i) {
internal::ParseFontLinkEntry(
base::WideToUTF8(values[i]), &filename, &font_name);
+
+ base::StringAppendF(&logging_str, "fallback: '%s' '%s'\n",
+ font_name.c_str(), filename.c_str());
+
// If the font name is present, add that directly, otherwise add the
// font names corresponding to the filename.
if (!font_name.empty()) {
@@ -108,6 +119,13 @@ void QueryLinkedFontsFromRegistry(const Font& font,
}
key.Close();
+
+ for (const auto& resolved_font : *linked_fonts) {
+ base::StringAppendF(&logging_str, "resolved: '%s'\n",
+ resolved_font.GetFontName().c_str());
+ }
+
+ TRACE_EVENT1("ui", "QueryLinkedFontsFromRegistry", "results", logging_str);
}
// CachedFontLinkSettings is a singleton cache of the Windows font settings
@@ -145,16 +163,22 @@ CachedFontLinkSettings* CachedFontLinkSettings::GetInstance() {
const std::vector<Font>* CachedFontLinkSettings::GetLinkedFonts(
const Font& font) {
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER("FontFallback.GetLinkedFonts.Timing");
const std::string& font_name = font.GetFontName();
std::map<std::string, std::vector<Font> >::const_iterator it =
cached_linked_fonts_.find(font_name);
if (it != cached_linked_fonts_.end())
return &it->second;
- cached_linked_fonts_[font_name] = std::vector<Font>();
- std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
+ TRACE_EVENT1("ui", "CachedFontLinkSettings::GetLinkedFonts", "font_name",
+ font_name);
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER(
+ "FontFallback.GetLinkedFonts.CacheMissTiming");
+ std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
QueryLinkedFontsFromRegistry(font, &cached_system_fonts_, linked_fonts);
+ UMA_HISTOGRAM_COUNTS_100("FontFallback.GetLinkedFonts.FontCount",
+ linked_fonts->size());
return linked_fonts;
}
@@ -265,73 +289,13 @@ void ParseFontFamilyString(const std::string& family,
}
}
-LinkedFontsIterator::LinkedFontsIterator(Font font)
- : original_font_(font),
- next_font_set_(false),
- linked_fonts_(NULL),
- linked_font_index_(0) {
- SetNextFont(original_font_);
-}
-
-LinkedFontsIterator::~LinkedFontsIterator() {
-}
-
-void LinkedFontsIterator::SetNextFont(Font font) {
- next_font_ = font;
- next_font_set_ = true;
-}
-
-bool LinkedFontsIterator::NextFont(Font* font) {
- if (next_font_set_) {
- next_font_set_ = false;
- current_font_ = next_font_;
- *font = current_font_;
- return true;
- }
-
- // First time through, get the linked fonts list.
- if (linked_fonts_ == NULL)
- linked_fonts_ = GetLinkedFonts();
-
- if (linked_font_index_ == linked_fonts_->size())
- return false;
-
- current_font_ = linked_fonts_->at(linked_font_index_++);
- *font = current_font_;
- return true;
-}
-
-const std::vector<Font>* LinkedFontsIterator::GetLinkedFonts() const {
- CachedFontLinkSettings* font_link = CachedFontLinkSettings::GetInstance();
-
- // First, try to get the list for the original font.
- const std::vector<Font>* fonts = font_link->GetLinkedFonts(original_font_);
-
- // If there are no linked fonts for the original font, try querying the
- // ones for the current font. This may happen if the first font is a custom
- // font that has no linked fonts in the registry.
- //
- // Note: One possibility would be to always merge both lists of fonts,
- // but it is not clear whether there are any real world scenarios
- // where this would actually help.
- if (fonts->empty())
- fonts = font_link->GetLinkedFonts(current_font_);
-
- return fonts;
-}
-
} // namespace internal
std::vector<Font> GetFallbackFonts(const Font& font) {
std::string font_family = font.GetFontName();
-
- // LinkedFontsIterator doesn't care about the font size, so we always pass 10.
- internal::LinkedFontsIterator linked_fonts(Font(font_family, 10));
- std::vector<Font> fallback_fonts;
- Font current;
- while (linked_fonts.NextFont(&current))
- fallback_fonts.push_back(current);
- return fallback_fonts;
+ CachedFontLinkSettings* font_link = CachedFontLinkSettings::GetInstance();
+ // GetLinkedFonts doesn't care about the font size, so we always pass 10.
+ return *font_link->GetLinkedFonts(Font(font_family, 10));
}
bool GetFallbackFont(const Font& font,
@@ -342,7 +306,7 @@ bool GetFallbackFont(const Font& font,
// browser process because we can use the shared system fallback, but in the
// renderer this can cause hangs. Code that needs font fallback in the
// renderer should instead use the font proxy.
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
// Check that we have at least as much text as was claimed. If we have less
// text than expected then DirectWrite will become confused and crash. This
diff --git a/chromium/ui/gfx/font_fallback_win.h b/chromium/ui/gfx/font_fallback_win.h
index b9d8339e214..083eb10aa4e 100644
--- a/chromium/ui/gfx/font_fallback_win.h
+++ b/chromium/ui/gfx/font_fallback_win.h
@@ -33,52 +33,6 @@ void GFX_EXPORT ParseFontLinkEntry(const std::string& entry,
void GFX_EXPORT ParseFontFamilyString(const std::string& family,
std::vector<std::string>* font_names);
-// Iterator over linked fallback fonts for a given font. The linked font chain
-// comes from the Windows registry, but gets cached between uses.
-class GFX_EXPORT LinkedFontsIterator {
- public:
- // Instantiates the iterator over the linked font chain for |font|. The first
- // item will be |font| itself.
- explicit LinkedFontsIterator(Font font);
- virtual ~LinkedFontsIterator();
-
- // Sets the font that would be returned by the next call to |NextFont()|,
- // useful for inserting one-time entries into the iterator chain.
- void SetNextFont(Font font);
-
- // Gets the next font in the link chain, if available, and increments the
- // iterator. Returns |true| on success or |false| if the iterator is past
- // last item (in that case, the value of |font| should not be used). If
- // |SetNextFont()| was called, returns the font set that way and clears it.
- bool NextFont(Font* font);
-
- protected:
- // Retrieves the list of linked fonts. Protected and virtual so that it may
- // be overridden by tests.
- virtual const std::vector<Font>* GetLinkedFonts() const;
-
- private:
- // Original font whose linked fonts are being iterated over.
- Font original_font_;
-
- // Font that was set via |SetNextFont()|.
- Font next_font_;
-
- // Indicates whether |SetNextFont()| was called.
- bool next_font_set_;
-
- // The font most recently returned by |NextFont()|.
- Font current_font_;
-
- // List of linked fonts; weak pointer.
- const std::vector<Font>* linked_fonts_;
-
- // Index of the current entry in the |linked_fonts_| list.
- size_t linked_font_index_;
-
- DISALLOW_COPY_AND_ASSIGN(LinkedFontsIterator);
-};
-
} // namespace internal
} // namespace gfx
diff --git a/chromium/ui/gfx/font_fallback_win_unittest.cc b/chromium/ui/gfx/font_fallback_win_unittest.cc
index 8629f6f2942..e4faf0c2b55 100644
--- a/chromium/ui/gfx/font_fallback_win_unittest.cc
+++ b/chromium/ui/gfx/font_fallback_win_unittest.cc
@@ -10,34 +10,6 @@
namespace gfx {
-namespace {
-
-// Subclass of LinkedFontsIterator for testing that allows mocking the linked
-// fonts vector.
-class TestLinkedFontsIterator : public internal::LinkedFontsIterator {
- public:
- explicit TestLinkedFontsIterator(Font font) : LinkedFontsIterator(font) {
- }
-
- ~TestLinkedFontsIterator() override {}
-
- // Add a linked font to the mocked vector of linked fonts.
- void AddLinkedFontForTesting(Font font) {
- test_linked_fonts.push_back(font);
- }
-
- const std::vector<Font>* GetLinkedFonts() const override {
- return &test_linked_fonts;
- }
-
- private:
- std::vector<Font> test_linked_fonts;
-
- DISALLOW_COPY_AND_ASSIGN(TestLinkedFontsIterator);
-};
-
-} // namespace
-
TEST(FontFallbackWinTest, ParseFontLinkEntry) {
std::string file;
std::string font;
@@ -84,38 +56,6 @@ TEST(FontFallbackWinTest, ParseFontFamilyString) {
EXPECT_EQ("Meiryo UI Italic", font_names[3]);
}
-TEST(FontFallbackWinTest, LinkedFontsIterator) {
- TestLinkedFontsIterator iterator(Font("Arial", 16));
- iterator.AddLinkedFontForTesting(Font("Times New Roman", 16));
-
- Font font;
- EXPECT_TRUE(iterator.NextFont(&font));
- ASSERT_EQ("Arial", font.GetFontName());
-
- EXPECT_TRUE(iterator.NextFont(&font));
- ASSERT_EQ("Times New Roman", font.GetFontName());
-
- EXPECT_FALSE(iterator.NextFont(&font));
-}
-
-TEST(FontFallbackWinTest, LinkedFontsIteratorSetNextFont) {
- TestLinkedFontsIterator iterator(Font("Arial", 16));
- iterator.AddLinkedFontForTesting(Font("Times New Roman", 16));
-
- Font font;
- EXPECT_TRUE(iterator.NextFont(&font));
- ASSERT_EQ("Arial", font.GetFontName());
-
- iterator.SetNextFont(Font("Tahoma", 16));
- EXPECT_TRUE(iterator.NextFont(&font));
- ASSERT_EQ("Tahoma", font.GetFontName());
-
- EXPECT_TRUE(iterator.NextFont(&font));
- ASSERT_EQ("Times New Roman", font.GetFontName());
-
- EXPECT_FALSE(iterator.NextFont(&font));
-}
-
TEST(FontFallbackWinTest, FontFallback) {
// Needed to bypass DCHECK in GetFallbackFont.
base::MessageLoopForUI message_loop;
diff --git a/chromium/ui/gfx/font_list_unittest.cc b/chromium/ui/gfx/font_list_unittest.cc
index f8025dc6ca0..14abab4629a 100644
--- a/chromium/ui/gfx/font_list_unittest.cc
+++ b/chromium/ui/gfx/font_list_unittest.cc
@@ -232,13 +232,7 @@ TEST(FontListTest, Fonts_DeriveWithSizeDelta) {
EXPECT_EQ("Courier New|13|italic|normal", FontToString(derived_fonts[1]));
}
-// TODO(865540): Enable this on android.
-#if defined(OS_ANDROID)
-#define MAYBE_Fonts_GetHeight_GetBaseline DISABLED_Fonts_GetHeight_GetBaseline
-#else
-#define MAYBE_Fonts_GetHeight_GetBaseline Fonts_GetHeight_GetBaseline
-#endif
-TEST(FontListTest, MAYBE_Fonts_GetHeight_GetBaseline) {
+TEST(FontListTest, Fonts_GetHeight_GetBaseline) {
// If a font list has only one font, the height and baseline must be the same.
Font font1(kTestFontName, 16);
ASSERT_EQ(base::ToLowerASCII(kTestFontName),
@@ -249,12 +243,11 @@ TEST(FontListTest, MAYBE_Fonts_GetHeight_GetBaseline) {
// If there are two different fonts, the font list returns the max value
// for the baseline (ascent) and height.
+ // NOTE: On most platforms, kCJKFontName has different metrics than
+ // kTestFontName, but on Android it does not.
Font font2(kCJKFontName, 16);
ASSERT_EQ(base::ToLowerASCII(kCJKFontName),
base::ToLowerASCII(font2.GetActualFontNameForTesting()));
- EXPECT_NE(font1.GetBaseline(), font2.GetBaseline());
- // TODO(ananta): Find a size and font pair with reliably distinct descents.
- EXPECT_NE(font1.GetHeight(), font2.GetHeight());
std::vector<Font> fonts;
fonts.push_back(font1);
fonts.push_back(font2);
diff --git a/chromium/ui/gfx/font_names_testing.cc b/chromium/ui/gfx/font_names_testing.cc
index 6c696650b82..0815bcb6df8 100644
--- a/chromium/ui/gfx/font_names_testing.cc
+++ b/chromium/ui/gfx/font_names_testing.cc
@@ -34,6 +34,8 @@ const char kTestFontName[] = "Arial";
const char kSymbolFontName[] = "DejaVu Sans";
#elif defined(OS_ANDROID)
const char kSymbolFontName[] = "monospace";
+#elif defined(OS_WIN)
+const char kSymbolFontName[] = "Segoe UI Symbol";
#else
const char kSymbolFontName[] = "Symbol";
#endif
diff --git a/chromium/ui/gfx/font_render_params.h b/chromium/ui/gfx/font_render_params.h
index 93be3531d97..9c7491ea834 100644
--- a/chromium/ui/gfx/font_render_params.h
+++ b/chromium/ui/gfx/font_render_params.h
@@ -117,7 +117,7 @@ GFX_EXPORT FontRenderParams GetFontRenderParams(
GFX_EXPORT void ClearFontRenderParamsCacheForTest();
#endif
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
// Gets the device scale factor to query the FontRenderParams.
GFX_EXPORT float GetFontRenderParamsDeviceScaleFactor();
diff --git a/chromium/ui/gfx/font_render_params_fuchsia.cc b/chromium/ui/gfx/font_render_params_fuchsia.cc
index 6229bcc9db6..cc44366a79a 100644
--- a/chromium/ui/gfx/font_render_params_fuchsia.cc
+++ b/chromium/ui/gfx/font_render_params_fuchsia.cc
@@ -36,4 +36,8 @@ FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
return *params;
}
+float GetFontRenderParamsDeviceScaleFactor() {
+ return 1.0;
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/font_render_params_linux.cc b/chromium/ui/gfx/font_render_params_linux.cc
index 1277d923a7f..e99959ea316 100644
--- a/chromium/ui/gfx/font_render_params_linux.cc
+++ b/chromium/ui/gfx/font_render_params_linux.cc
@@ -21,7 +21,7 @@
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "ui/gfx/font.h"
-#include "ui/gfx/linux_font_delegate.h"
+#include "ui/gfx/skia_font_delegate.h"
#include "ui/gfx/switches.h"
namespace gfx {
@@ -266,7 +266,7 @@ FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
// Start with the delegate's settings, but let Fontconfig have the final say.
FontRenderParams params;
- const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
+ const SkiaFontDelegate* delegate = SkiaFontDelegate::instance();
if (delegate)
params = delegate->GetDefaultFontRenderParams();
QueryFontconfig(actual_query, &params, family_out);
diff --git a/chromium/ui/gfx/font_render_params_linux_unittest.cc b/chromium/ui/gfx/font_render_params_linux_unittest.cc
index e654120dae5..28db6bc1b5d 100644
--- a/chromium/ui/gfx/font_render_params_linux_unittest.cc
+++ b/chromium/ui/gfx/font_render_params_linux_unittest.cc
@@ -15,7 +15,7 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
-#include "ui/gfx/linux_font_delegate.h"
+#include "ui/gfx/skia_font_delegate.h"
namespace gfx {
@@ -33,9 +33,9 @@ const char kFontconfigMatchFontHeader[] = " <match target=\"font\">\n";
const char kFontconfigMatchPatternHeader[] = " <match target=\"pattern\">\n";
const char kFontconfigMatchFooter[] = " </match>\n";
-// Implementation of LinuxFontDelegate that returns a canned FontRenderParams
+// Implementation of SkiaFontDelegate that returns a canned FontRenderParams
// struct. This is used to isolate tests from the system's local configuration.
-class TestFontDelegate : public LinuxFontDelegate {
+class TestFontDelegate : public SkiaFontDelegate {
public:
TestFontDelegate() {}
~TestFontDelegate() override {}
@@ -130,14 +130,14 @@ class FontRenderParamsTest : public testing::Test {
public:
FontRenderParamsTest() {
CHECK(temp_dir_.CreateUniqueTempDir());
- original_font_delegate_ = LinuxFontDelegate::instance();
- LinuxFontDelegate::SetInstance(&test_font_delegate_);
+ original_font_delegate_ = SkiaFontDelegate::instance();
+ SkiaFontDelegate::SetInstance(&test_font_delegate_);
ClearFontRenderParamsCacheForTest();
}
~FontRenderParamsTest() override {
- LinuxFontDelegate::SetInstance(
- const_cast<LinuxFontDelegate*>(original_font_delegate_));
+ SkiaFontDelegate::SetInstance(
+ const_cast<SkiaFontDelegate*>(original_font_delegate_));
}
void SetUp() override {
@@ -153,7 +153,7 @@ class FontRenderParamsTest : public testing::Test {
protected:
base::ScopedTempDir temp_dir_;
- const LinuxFontDelegate* original_font_delegate_;
+ const SkiaFontDelegate* original_font_delegate_;
TestFontDelegate test_font_delegate_;
private:
@@ -394,7 +394,7 @@ TEST_F(FontRenderParamsTest, ForceSubpixelPositioning) {
}
TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) {
- // Configure the LinuxFontDelegate (which queries GtkSettings on desktop
+ // Configure the SkiaFontDelegate (which queries GtkSettings on desktop
// Linux) to request subpixel rendering.
FontRenderParams system_params;
system_params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
diff --git a/chromium/ui/gfx/font_unittest.cc b/chromium/ui/gfx/font_unittest.cc
index e9e810640ec..2626ddcd916 100644
--- a/chromium/ui/gfx/font_unittest.cc
+++ b/chromium/ui/gfx/font_unittest.cc
@@ -73,18 +73,10 @@ TEST_F(FontTest, AvgWidths) {
EXPECT_GT(cf.GetExpectedTextWidth(3), cf.GetExpectedTextWidth(2));
}
-#if defined(OS_WIN)
-#define MAYBE_GetActualFontNameForTesting DISABLED_GetActualFontNameForTesting
-#else
-#define MAYBE_GetActualFontNameForTesting GetActualFontNameForTesting
-#endif
-// On Windows, Font::GetActualFontNameForTesting() doesn't work well for now.
-// http://crbug.com/327287
-//
// Check that fonts used for testing are installed and enabled. On Mac
// fonts may be installed but still need enabling in Font Book.app.
// http://crbug.com/347429
-TEST_F(FontTest, MAYBE_GetActualFontNameForTesting) {
+TEST_F(FontTest, GetActualFontNameForTesting) {
Font arial(kTestFontName, 16);
EXPECT_EQ(base::ToLowerASCII(kTestFontName),
base::ToLowerASCII(arial.GetActualFontNameForTesting()))
diff --git a/chromium/ui/gfx/geometry/insets.h b/chromium/ui/gfx/geometry/insets.h
index 10516583b82..d2b752b9f59 100644
--- a/chromium/ui/gfx/geometry/insets.h
+++ b/chromium/ui/gfx/geometry/insets.h
@@ -50,6 +50,11 @@ class GEOMETRY_EXPORT Insets {
// Returns true if the insets are empty.
bool IsEmpty() const { return width() == 0 && height() == 0; }
+ void set_top(int top) { top_ = top; }
+ void set_left(int left) { left_ = left; }
+ void set_bottom(int bottom) { bottom_ = bottom; }
+ void set_right(int right) { right_ = right; }
+
void Set(int top, int left, int bottom, int right) {
top_ = top;
left_ = left;
diff --git a/chromium/ui/gfx/geometry/insets_unittest.cc b/chromium/ui/gfx/geometry/insets_unittest.cc
index 6f607d9173e..e08d79e911f 100644
--- a/chromium/ui/gfx/geometry/insets_unittest.cc
+++ b/chromium/ui/gfx/geometry/insets_unittest.cc
@@ -31,6 +31,30 @@ TEST(InsetsTest, Insets) {
EXPECT_FALSE(insets.IsEmpty());
}
+TEST(InsetsTest, SetTop) {
+ gfx::Insets insets(1);
+ insets.set_top(2);
+ EXPECT_EQ(gfx::Insets(2, 1, 1, 1), insets);
+}
+
+TEST(InsetsTest, SetBottom) {
+ gfx::Insets insets(1);
+ insets.set_bottom(2);
+ EXPECT_EQ(gfx::Insets(1, 1, 2, 1), insets);
+}
+
+TEST(InsetsTest, SetLeft) {
+ gfx::Insets insets(1);
+ insets.set_left(2);
+ EXPECT_EQ(gfx::Insets(1, 2, 1, 1), insets);
+}
+
+TEST(InsetsTest, SetRight) {
+ gfx::Insets insets(1);
+ insets.set_right(2);
+ EXPECT_EQ(gfx::Insets(1, 1, 1, 2), insets);
+}
+
TEST(InsetsTest, Set) {
gfx::Insets insets;
insets.Set(1, 2, 3, 4);
diff --git a/chromium/ui/gfx/gfx_paths.cc b/chromium/ui/gfx/gfx_paths.cc
deleted file mode 100644
index ba387ad4eb5..00000000000
--- a/chromium/ui/gfx/gfx_paths.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/gfx_paths.h"
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-
-namespace gfx {
-
-bool PathProvider(int key, base::FilePath* result) {
- base::FilePath cur;
- switch (key) {
- // The following are only valid in the development environment, and
- // will fail if executed from an installed executable (because the
- // generated path won't exist).
- case DIR_TEST_DATA:
- if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &cur))
- return false;
- cur = cur.Append(FILE_PATH_LITERAL("ui"));
- cur = cur.Append(FILE_PATH_LITERAL("gfx"));
- cur = cur.Append(FILE_PATH_LITERAL("test"));
- cur = cur.Append(FILE_PATH_LITERAL("data"));
- if (!base::PathExists(cur)) // we don't want to create this
- return false;
- break;
- default:
- return false;
- }
-
- *result = cur;
- return true;
-}
-
-// This cannot be done as a static initializer sadly since Visual Studio will
-// eliminate this object file if there is no direct entry point into it.
-void RegisterPathProvider() {
- base::PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/gfx_paths.h b/chromium/ui/gfx/gfx_paths.h
deleted file mode 100644
index 7a779edbc92..00000000000
--- a/chromium/ui/gfx/gfx_paths.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GFX_PATHS_H_
-#define UI_GFX_GFX_PATHS_H_
-
-#include "ui/gfx/gfx_export.h"
-
-// This file declares path keys for the app module. These can be used with
-// the PathService to access various special directories and files.
-
-namespace gfx {
-
-enum {
- PATH_START = 2000,
-
- // Valid only in development environment; TODO(darin): move these
- DIR_TEST_DATA, // Directory where unit test data resides.
-
- PATH_END
-};
-
-// Call once to register the provider for the path keys defined above.
-GFX_EXPORT void RegisterPathProvider();
-
-} // namespace gfx
-
-#endif // UI_GFX_GFX_PATHS_H_
diff --git a/chromium/ui/gfx/gpu_memory_buffer.h b/chromium/ui/gfx/gpu_memory_buffer.h
index 9e77c0881ba..9870ae3dfc8 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.h
+++ b/chromium/ui/gfx/gpu_memory_buffer.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include "base/memory/shared_memory.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "build/build_config.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/generic_shared_memory_id.h"
@@ -61,8 +62,7 @@ struct GFX_EXPORT GpuMemoryBufferHandle {
bool is_null() const { return type == EMPTY_BUFFER; }
GpuMemoryBufferType type;
GpuMemoryBufferId id;
- // TODO(crbug.com/863011): convert this to a scoped handle.
- base::SharedMemoryHandle handle;
+ base::UnsafeSharedMemoryRegion region;
uint32_t offset;
int32_t stride;
#if defined(OS_LINUX)
diff --git a/chromium/ui/gfx/harfbuzz_font_skia.cc b/chromium/ui/gfx/harfbuzz_font_skia.cc
index fe88148b97c..a06771b8b35 100644
--- a/chromium/ui/gfx/harfbuzz_font_skia.cc
+++ b/chromium/ui/gfx/harfbuzz_font_skia.cc
@@ -19,13 +19,6 @@
#include "ui/gfx/render_text.h"
#include "ui/gfx/skia_util.h"
-#if defined(OS_MACOSX)
-#include <hb-coretext.h>
-
-#include "base/mac/scoped_cftyperef.h"
-#include "third_party/skia/include/ports/SkTypeface_mac.h"
-#endif
-
namespace gfx {
namespace {
@@ -65,16 +58,15 @@ void GetGlyphWidthAndExtents(cc::PaintFlags* flags,
hb_codepoint_t codepoint,
hb_position_t* width,
hb_glyph_extents_t* extents) {
- SkPaint paint = flags->ToSkPaint();
+ SkFont font = flags->ToSkFont();
DCHECK_LE(codepoint, std::numeric_limits<uint16_t>::max());
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
SkScalar sk_width;
SkRect sk_bounds;
uint16_t glyph = static_cast<uint16_t>(codepoint);
- paint.getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds);
+ font.getWidths(&glyph, 1, &sk_width, &sk_bounds);
if (width)
*width = SkiaScalarToHarfBuzzUnits(sk_width);
if (extents) {
@@ -100,14 +92,21 @@ hb_bool_t GetGlyph(hb_font_t* font,
bool exists = cache->count(unicode) != 0;
if (!exists) {
- font_data->flags_.setTextEncoding(cc::PaintFlags::kUTF32_TextEncoding);
- SkPaint paint = font_data->flags_.ToSkPaint();
- paint.textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]);
+ (*cache)[unicode] =
+ font_data->flags_.getTypeface()->unicharToGlyph(unicode);
}
*glyph = (*cache)[unicode];
return !!*glyph;
}
+hb_bool_t GetNominalGlyph(hb_font_t* font,
+ void* data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t* glyph,
+ void* user_data) {
+ return GetGlyph(font, data, unicode, 0, glyph, user_data);
+}
+
// Returns the horizontal advance value of the |glyph|.
hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font,
void* data,
@@ -153,11 +152,6 @@ hb_position_t GetGlyphHorizontalKerning(hb_font_t* font,
hb_codepoint_t right_glyph,
void* user_data) {
FontData* font_data = reinterpret_cast<FontData*>(data);
- if (font_data->flags_.isVerticalText()) {
- // We don't support cross-stream kerning.
- return 0;
- }
-
return GetGlyphKerning(font_data, left_glyph, right_glyph);
}
@@ -167,11 +161,6 @@ hb_position_t GetGlyphVerticalKerning(hb_font_t* font,
hb_codepoint_t bottom_glyph,
void* user_data) {
FontData* font_data = reinterpret_cast<FontData*>(data);
- if (!font_data->flags_.isVerticalText()) {
- // We don't support cross-stream kerning.
- return 0;
- }
-
return GetGlyphKerning(font_data, top_glyph, bottom_glyph);
}
@@ -190,7 +179,8 @@ hb_bool_t GetGlyphExtents(hb_font_t* font,
class FontFuncs {
public:
FontFuncs() : font_funcs_(hb_font_funcs_create()) {
- hb_font_funcs_set_glyph_func(font_funcs_, GetGlyph, 0, 0);
+ hb_font_funcs_set_variation_glyph_func(font_funcs_, GetGlyph, 0, 0);
+ hb_font_funcs_set_nominal_glyph_func(font_funcs_, GetNominalGlyph, 0, 0);
hb_font_funcs_set_glyph_h_advance_func(
font_funcs_, GetGlyphHorizontalAdvance, 0, 0);
hb_font_funcs_set_glyph_h_kerning_func(
@@ -254,18 +244,6 @@ class HarfBuzzFace {
}
void Init(SkTypeface* skia_face) {
-#if defined(OS_MACOSX)
- // On Mac, hb_face_t needs to be instantiated using the CoreText constructor
- // when there is an underlying CTFont. Otherwise the wrong shaping engine is
- // chosen. See also HarfBuzzFace.cpp in Blink.
- if (CTFontRef ct_font = SkTypeface_GetCTFontRef(skia_face)) {
- base::ScopedCFTypeRef<CGFontRef> cg_font(
- CTFontCopyGraphicsFont(ct_font, nullptr));
- face_ = hb_coretext_face_create(cg_font);
- DCHECK(face_);
- return;
- }
-#endif
SkSafeRef(skia_face);
face_ = hb_face_create_for_tables(GetFontTable, skia_face, UnrefSkTypeface);
DCHECK(face_);
@@ -295,13 +273,6 @@ hb_font_t* CreateHarfBuzzFont(sk_sp<SkTypeface> skia_face,
face_cache->first.Init(skia_face.get());
hb_font_t* harfbuzz_font = nullptr;
-#if defined(OS_MACOSX)
- // Since we have a CTFontRef available at the right size, associate it with
- // the hb_font_t. This avoids Harfbuzz doing its own lookup by typeface name,
- // which requires talking to the font server again.
- if (CTFontRef ct_font = SkTypeface_GetCTFontRef(skia_face.get()))
- harfbuzz_font = hb_coretext_font_create(ct_font);
-#endif
if (!harfbuzz_font)
harfbuzz_font = hb_font_create(face_cache->first.get());
diff --git a/chromium/ui/gfx/icon_util_unittest.cc b/chromium/ui/gfx/icon_util_unittest.cc
index d25771307b7..a9c73c4fe65 100644
--- a/chromium/ui/gfx/icon_util_unittest.cc
+++ b/chromium/ui/gfx/icon_util_unittest.cc
@@ -15,15 +15,14 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/gfx_paths.h"
#include "ui/gfx/icon_util_unittests_resource.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_family.h"
namespace {
-static const char kSmallIconName[] = "icon_util/16_X_16_icon.ico";
-static const char kLargeIconName[] = "icon_util/128_X_128_icon.ico";
+static const char kSmallIconName[] = "16_X_16_icon.ico";
+static const char kLargeIconName[] = "128_X_128_icon.ico";
static const char kTempIconFilename[] = "temp_test_icon.ico";
} // namespace
@@ -33,9 +32,14 @@ class IconUtilTest : public testing::Test {
using ScopedHICON = base::win::ScopedHICON;
void SetUp() override {
- gfx::RegisterPathProvider();
- ASSERT_TRUE(
- base::PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_));
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
+ test_data_dir_ = test_data_dir_.Append(FILE_PATH_LITERAL("ui"))
+ .Append(FILE_PATH_LITERAL("gfx"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .Append(FILE_PATH_LITERAL("icon_util"));
+ ASSERT_TRUE(base::PathExists(test_data_dir_));
+
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
}
@@ -74,7 +78,7 @@ class IconUtilTest : public testing::Test {
protected:
// The root directory for test files. This should be treated as read-only.
- base::FilePath test_data_directory_;
+ base::FilePath test_data_dir_;
// Directory for creating files by this test.
base::ScopedTempDir temp_directory_;
@@ -145,8 +149,7 @@ void IconUtilTest::CheckAllIconSizes(const base::FilePath& icon_filename,
// The following test case makes sure IconUtil::SkBitmapFromHICON fails
// gracefully when called with invalid input parameters.
TEST_F(IconUtilTest, TestIconToBitmapInvalidParameters) {
- base::FilePath icon_filename =
- test_data_directory_.AppendASCII(kSmallIconName);
+ base::FilePath icon_filename = test_data_dir_.AppendASCII(kSmallIconName);
gfx::Size icon_size(kSmallIconWidth, kSmallIconHeight);
ScopedHICON icon(
LoadIconFromFile(icon_filename, icon_size.width(), icon_size.height()));
@@ -270,8 +273,8 @@ TEST_F(IconUtilTest, TestCreateIconFileEmptyImageFamily) {
// This test case makes sure that when we load an icon from disk and convert
// the HICON into a bitmap, the bitmap has the expected format and dimensions.
TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
- base::FilePath small_icon_filename = test_data_directory_.AppendASCII(
- kSmallIconName);
+ base::FilePath small_icon_filename =
+ test_data_dir_.AppendASCII(kSmallIconName);
gfx::Size small_icon_size(kSmallIconWidth, kSmallIconHeight);
ScopedHICON small_icon(LoadIconFromFile(
small_icon_filename, small_icon_size.width(), small_icon_size.height()));
@@ -283,8 +286,8 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
EXPECT_EQ(bitmap.height(), small_icon_size.height());
EXPECT_EQ(bitmap.colorType(), kN32_SkColorType);
- base::FilePath large_icon_filename = test_data_directory_.AppendASCII(
- kLargeIconName);
+ base::FilePath large_icon_filename =
+ test_data_dir_.AppendASCII(kLargeIconName);
gfx::Size large_icon_size(kLargeIconWidth, kLargeIconHeight);
ScopedHICON large_icon(LoadIconFromFile(
large_icon_filename, large_icon_size.width(), large_icon_size.height()));
diff --git a/chromium/ui/gfx/image/image.cc b/chromium/ui/gfx/image/image.cc
index a81091e8975..3fe6a6f5e50 100644
--- a/chromium/ui/gfx/image/image.cc
+++ b/chromium/ui/gfx/image/image.cc
@@ -177,7 +177,8 @@ class ImageRepCocoaTouch : public ImageRep {
explicit ImageRepCocoaTouch(UIImage* image)
: ImageRep(Image::kImageRepCocoaTouch),
image_(image) {
- CHECK(image);
+ CHECK(image_);
+ base::mac::NSObjectRetain(image_);
}
~ImageRepCocoaTouch() override {
@@ -204,7 +205,8 @@ class ImageRepCocoa : public ImageRep {
explicit ImageRepCocoa(NSImage* image)
: ImageRep(Image::kImageRepCocoa),
image_(image) {
- CHECK(image);
+ CHECK(image_);
+ base::mac::NSObjectRetain(image_);
}
~ImageRepCocoa() override {
@@ -351,7 +353,6 @@ Image::Image(const ImageSkia& image) {
#if defined(OS_IOS)
Image::Image(UIImage* image) {
if (image) {
- base::mac::NSObjectRetain(image);
storage_ = new internal::ImageStorage(Image::kImageRepCocoaTouch);
AddRepresentation(std::make_unique<internal::ImageRepCocoaTouch>(image));
}
@@ -456,14 +457,13 @@ UIImage* Image::ToUIImage() const {
const internal::ImageRepPNG* png_rep =
GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
scoped_rep.reset(new internal::ImageRepCocoaTouch(
- internal::CreateUIImageFromPNG(png_rep->image_reps())));
+ internal::UIImageFromPNG(png_rep->image_reps())));
break;
}
case kImageRepSkia: {
const internal::ImageRepSkia* skia_rep =
GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
UIImage* image = UIImageFromImageSkia(*skia_rep->image());
- base::mac::NSObjectRetain(image);
scoped_rep.reset(new internal::ImageRepCocoaTouch(image));
break;
}
@@ -496,7 +496,6 @@ NSImage* Image::ToNSImage() const {
GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
default_representation_color_space);
- base::mac::NSObjectRetain(image);
scoped_rep.reset(new internal::ImageRepCocoa(image));
break;
}
@@ -581,39 +580,12 @@ ImageSkia Image::AsImageSkia() const {
return IsEmpty() ? ImageSkia() : *ToImageSkia();
}
-#if defined(OS_IOS)
-UIImage* Image::AsUIImage() const {
- return IsEmpty() ? nil : ToUIImage();
-}
-#elif defined(OS_MACOSX)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
NSImage* Image::AsNSImage() const {
return IsEmpty() ? nil : ToNSImage();
}
#endif
-scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const {
- scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes();
- scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes());
- copy->data().assign(original->front(), original->front() + original->size());
- return copy;
-}
-
-ImageSkia* Image::CopyImageSkia() const {
- return new ImageSkia(*ToImageSkia());
-}
-
-SkBitmap* Image::CopySkBitmap() const {
- return new SkBitmap(*ToSkBitmap());
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-NSImage* Image::CopyNSImage() const {
- NSImage* image = ToNSImage();
- base::mac::NSObjectRetain(image);
- return image;
-}
-#endif
-
bool Image::HasRepresentation(RepresentationType type) const {
return storage() && storage()->HasRepresentation(type);
}
diff --git a/chromium/ui/gfx/image/image.h b/chromium/ui/gfx/image/image.h
index 43ec2c15203..e33e5359692 100644
--- a/chromium/ui/gfx/image/image.h
+++ b/chromium/ui/gfx/image/image.h
@@ -71,9 +71,7 @@ class GFX_EXPORT Image {
// Retains |image|.
explicit Image(UIImage* image);
#elif defined(OS_MACOSX)
- // Does not retain |image|; expects to take ownership.
- // A single NSImage object can contain multiple bitmaps so there's no reason
- // to pass a vector of these.
+ // Retains |image|.
explicit Image(NSImage* image);
#endif
@@ -136,24 +134,9 @@ class GFX_EXPORT Image {
// image is empty.
ImageSkia AsImageSkia() const;
- // Same as ToSkBitmap(), but returns nil if this image is empty.
-#if defined(OS_IOS)
- UIImage* AsUIImage() const;
-#elif defined(OS_MACOSX)
- NSImage* AsNSImage() const;
-#endif
-
- // Performs a conversion, like above, but returns a copy of the result rather
- // than a weak pointer. The caller is responsible for deleting the result.
- // Note that the result is only a copy in terms of memory management; the
- // backing pixels are shared amongst all copies (a fact of each of the
- // converted representations, rather than a limitation imposed by Image) and
- // so the result should be considered immutable.
- scoped_refptr<base::RefCountedMemory> Copy1xPNGBytes() const;
- ImageSkia* CopyImageSkia() const;
- SkBitmap* CopySkBitmap() const;
+ // Same as ToNSImage(), but returns nil if this image is empty.
#if defined(OS_MACOSX) && !defined(OS_IOS)
- NSImage* CopyNSImage() const;
+ NSImage* AsNSImage() const;
#endif
// Inspects the representations map to see if the given type exists.
diff --git a/chromium/ui/gfx/image/image_family.cc b/chromium/ui/gfx/image/image_family.cc
index adc1482c398..b3b1c5a08b1 100644
--- a/chromium/ui/gfx/image/image_family.cc
+++ b/chromium/ui/gfx/image/image_family.cc
@@ -129,7 +129,8 @@ gfx::Image ImageFamily::CreateExact(int width, int height) const {
// is not racy to |image|. Since this function can run on a different thread
// than the thread |image| created on, we should not touch the
// non-thread-safe ref count in gfx::Image here.
- std::unique_ptr<gfx::ImageSkia> image_skia(image->CopyImageSkia());
+ std::unique_ptr<gfx::ImageSkia> image_skia(
+ new gfx::ImageSkia(*image->ToImageSkia()));
return gfx::Image(*image_skia);
}
diff --git a/chromium/ui/gfx/image/image_generic.cc b/chromium/ui/gfx/image/image_generic.cc
index acca9d0bd36..ad77df1f86e 100644
--- a/chromium/ui/gfx/image/image_generic.cc
+++ b/chromium/ui/gfx/image/image_generic.cc
@@ -76,7 +76,7 @@ class PNGImageSource : public ImageSkiaSource {
private:
struct Compare {
- bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) {
+ bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) const {
return rep1.scale() < rep2.scale();
}
};
diff --git a/chromium/ui/gfx/image/image_ios.mm b/chromium/ui/gfx/image/image_ios.mm
index e1c644d1b5f..4b1c67c8c2a 100644
--- a/chromium/ui/gfx/image/image_ios.mm
+++ b/chromium/ui/gfx/image/image_ios.mm
@@ -72,8 +72,7 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
return png_bytes;
}
-UIImage* CreateUIImageFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
+UIImage* UIImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps) {
float ideal_scale = ImageSkia::GetMaxSupportedScale();
if (image_png_reps.empty())
@@ -91,7 +90,8 @@ UIImage* CreateUIImageFromPNG(
}
}
- return CreateUIImageFromImagePNGRep(image_png_reps[closest_index]);
+ return
+ [CreateUIImageFromImagePNGRep(image_png_reps[closest_index]) autorelease];
}
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
diff --git a/chromium/ui/gfx/image/image_mac.mm b/chromium/ui/gfx/image/image_mac.mm
index bce798620b3..62385f99729 100644
--- a/chromium/ui/gfx/image/image_mac.mm
+++ b/chromium/ui/gfx/image/image_mac.mm
@@ -97,7 +97,7 @@ NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
[image addRepresentation:ns_image_rep];
}
- return image.release();
+ return image.autorelease();
}
gfx::Size NSImageSize(NSImage* image) {
diff --git a/chromium/ui/gfx/image/image_mac_unittest.mm b/chromium/ui/gfx/image/image_mac_unittest.mm
index dc26e924e91..4b782f032ef 100644
--- a/chromium/ui/gfx/image/image_mac_unittest.mm
+++ b/chromium/ui/gfx/image/image_mac_unittest.mm
@@ -40,7 +40,7 @@ bool NSImageStructureMatches(
float scale = scales[i];
bool found_match = false;
for (size_t j = 0; j < [ns_image representations].count; ++j) {
- NSImageRep* ns_image_rep = [[ns_image representations] objectAtIndex:j];
+ NSImageRep* ns_image_rep = [ns_image representations][j];
if (ns_image_rep &&
[ns_image_rep pixelsWide] == width * scale &&
[ns_image_rep pixelsHigh] == height * scale) {
@@ -101,7 +101,7 @@ TEST_F(ImageMacTest, MultiResolutionNSImageToImageSkia) {
[ns_image addRepresentation:ns_image_rep1];
[ns_image addRepresentation:ns_image_rep2];
- gfx::Image image(ns_image.release());
+ gfx::Image image(ns_image);
EXPECT_EQ(1u, image.RepresentationCount());
@@ -132,7 +132,7 @@ TEST_F(ImageMacTest, UnalignedMultiResolutionNSImageToImageSkia) {
[[NSImage alloc] initWithSize:NSMakeSize(kWidth1x, kHeight1x)]);
[ns_image addRepresentation:ns_image_rep4];
- gfx::Image image(ns_image.release());
+ gfx::Image image(ns_image);
EXPECT_EQ(1u, image.RepresentationCount());
diff --git a/chromium/ui/gfx/image/image_platform.h b/chromium/ui/gfx/image/image_platform.h
index ca49cbebb13..117d2624e95 100644
--- a/chromium/ui/gfx/image/image_platform.h
+++ b/chromium/ui/gfx/image/image_platform.h
@@ -35,13 +35,11 @@ namespace internal {
#if defined(OS_IOS)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
UIImage* uiimage);
-// Caller takes ownership of the returned UIImage.
-UIImage* CreateUIImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps);
+UIImage* UIImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps);
gfx::Size UIImageSize(UIImage* image);
#elif defined(OS_MACOSX)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
NSImage* nsimage);
-// Caller takes ownership of the returned NSImage.
NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
CGColorSpaceRef color_space);
gfx::Size NSImageSize(NSImage* image);
diff --git a/chromium/ui/gfx/image/image_unittest.cc b/chromium/ui/gfx/image/image_unittest.cc
index faa55c299a0..c25b09ac990 100644
--- a/chromium/ui/gfx/image/image_unittest.cc
+++ b/chromium/ui/gfx/image/image_unittest.cc
@@ -249,15 +249,7 @@ TEST_F(ImageTest, MultiResolutionPNGToImageSkia) {
#endif
}
-// TODO(crbug.com/153782): disable this test as it fails on iOS retina devices.
-#if defined(OS_IOS)
-#define MAYBE_MultiResolutionPNGToPlatform \
- DISABLED_MultiResolutionPNGToPlatform
-#else
-#define MAYBE_MultiResolutionPNGToPlatform \
- MultiResolutionPNGToPlatform
-#endif
-TEST_F(ImageTest, MAYBE_MultiResolutionPNGToPlatform) {
+TEST_F(ImageTest, MultiResolutionPNGToPlatform) {
const int kSize1x = 25;
const int kSize2x = 50;
@@ -307,15 +299,7 @@ TEST_F(ImageTest, PlatformToPNGEncodeAndDecode) {
// The platform types use the platform provided encoding/decoding of PNGs. Make
// sure these work with the Skia Encode/Decode.
-// TODO(crbug.com/153782): disable this test as it fails on iOS retina devices.
-#if defined(OS_IOS)
-#define MAYBE_PNGEncodeFromSkiaDecodeToPlatform \
- DISABLED_PNGEncodeFromSkiaDecodeToPlatform
-#else
-#define MAYBE_PNGEncodeFromSkiaDecodeToPlatform \
- PNGEncodeFromSkiaDecodeToPlatform
-#endif
-TEST_F(ImageTest, MAYBE_PNGEncodeFromSkiaDecodeToPlatform) {
+TEST_F(ImageTest, PNGEncodeFromSkiaDecodeToPlatform) {
// Force the conversion sequence skia to png to platform_type.
gfx::Image from_bitmap = gfx::Image::CreateFrom1xBitmap(
gt::CreateBitmap(25, 25));
@@ -435,41 +419,6 @@ TEST_F(ImageTest, PlatformToPlatform) {
EXPECT_EQ(25, image.Height());
}
-TEST_F(ImageTest, PlatformToSkiaToCopy) {
- const gfx::ImageSkia* image_skia = NULL;
- {
- gfx::Image image(gt::CreatePlatformImage());
- image_skia = image.CopyImageSkia();
- }
- EXPECT_TRUE(image_skia);
- EXPECT_FALSE(image_skia->isNull());
- delete image_skia;
-
- const SkBitmap* bitmap = NULL;
- {
- gfx::Image image(gt::CreatePlatformImage());
- bitmap = image.CopySkBitmap();
- }
-
- EXPECT_TRUE(bitmap);
- EXPECT_FALSE(bitmap->isNull());
- delete bitmap;
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-TEST_F(ImageTest, SkiaToCocoaCopy) {
- NSImage* ns_image;
-
- {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- ns_image = image.CopyNSImage();
- }
-
- EXPECT_TRUE(ns_image);
- base::mac::NSObjectRelease(ns_image);
-}
-#endif
-
TEST_F(ImageTest, CheckSkiaColor) {
gfx::Image image(gt::CreatePlatformImage());
diff --git a/chromium/ui/gfx/image/image_unittest_util.cc b/chromium/ui/gfx/image/image_unittest_util.cc
index 95cfd57f866..56ca50f0694 100644
--- a/chromium/ui/gfx/image/image_unittest_util.cc
+++ b/chromium/ui/gfx/image/image_unittest_util.cc
@@ -19,11 +19,9 @@
#include "ui/gfx/image/image_skia.h"
#if defined(OS_IOS)
-#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "skia/ext/skia_utils_ios.h"
#elif defined(OS_MACOSX)
-#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "skia/ext/skia_utils_mac.h"
#endif
@@ -222,12 +220,10 @@ PlatformImage CreatePlatformImage() {
CGColorSpaceCreateDeviceRGB());
UIImage* image =
skia::SkBitmapToUIImageWithColorSpace(bitmap, scale, color_space);
- base::mac::NSObjectRetain(image);
return image;
#elif defined(OS_MACOSX)
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
bitmap, base::mac::GetGenericRGBColorSpace());
- base::mac::NSObjectRetain(image);
return image;
#else
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
@@ -258,7 +254,7 @@ gfx::Image CopyViaPlatformType(const gfx::Image& image) {
#if defined(OS_IOS)
return gfx::Image(image.ToUIImage());
#elif defined(OS_MACOSX)
- return gfx::Image(image.CopyNSImage());
+ return gfx::Image(image.ToNSImage());
#else
return gfx::Image(image.AsImageSkia());
#endif
diff --git a/chromium/ui/gfx/ipc/gfx_param_traits_macros.h b/chromium/ui/gfx/ipc/gfx_param_traits_macros.h
index 870c09122dd..e5965bb7b08 100644
--- a/chromium/ui/gfx/ipc/gfx_param_traits_macros.h
+++ b/chromium/ui/gfx/ipc/gfx_param_traits_macros.h
@@ -48,7 +48,7 @@ IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
IPC_STRUCT_TRAITS_MEMBER(id)
IPC_STRUCT_TRAITS_MEMBER(type)
- IPC_STRUCT_TRAITS_MEMBER(handle)
+ IPC_STRUCT_TRAITS_MEMBER(region)
IPC_STRUCT_TRAITS_MEMBER(offset)
IPC_STRUCT_TRAITS_MEMBER(stride)
#if defined(OS_LINUX)
diff --git a/chromium/ui/gfx/linux/OWNERS b/chromium/ui/gfx/linux/OWNERS
index 2d13a903030..7543e31d7e3 100644
--- a/chromium/ui/gfx/linux/OWNERS
+++ b/chromium/ui/gfx/linux/OWNERS
@@ -3,3 +3,4 @@ dongseong.hwang@chromium.org
dnicoara@chromium.org
reveman@chromium.org
rjkroege@chromium.org
+spang@chromium.org
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
index 6611dcfef83..0a8ecf0f74e 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.cc
@@ -16,6 +16,7 @@
#include "base/process/memory.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include <linux/dma-buf.h>
@@ -59,6 +60,68 @@ void PrimeSyncEnd(int dmabuf_fd) {
} // namespace
// static
+bool ClientNativePixmapDmaBuf::IsConfigurationSupported(
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage) {
+ switch (usage) {
+ case gfx::BufferUsage::GPU_READ:
+ return format == gfx::BufferFormat::BGR_565 ||
+ format == gfx::BufferFormat::RGBA_8888 ||
+ format == gfx::BufferFormat::RGBX_8888 ||
+ format == gfx::BufferFormat::BGRA_8888 ||
+ format == gfx::BufferFormat::BGRX_8888 ||
+ format == gfx::BufferFormat::YVU_420;
+ case gfx::BufferUsage::SCANOUT:
+ return format == gfx::BufferFormat::BGRX_8888 ||
+ format == gfx::BufferFormat::RGBX_8888 ||
+ format == gfx::BufferFormat::RGBA_8888 ||
+ format == gfx::BufferFormat::BGRA_8888;
+ case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
+ return
+#if defined(ARCH_CPU_X86_FAMILY)
+ // Currently only Intel driver (i.e. minigbm and Mesa) supports R_8
+ // RG_88, NV12 and XB30. https://crbug.com/356871
+ format == gfx::BufferFormat::R_8 ||
+ format == gfx::BufferFormat::RG_88 ||
+ format == gfx::BufferFormat::YUV_420_BIPLANAR ||
+ format == gfx::BufferFormat::RGBX_1010102 ||
+#endif
+
+ format == gfx::BufferFormat::BGRX_8888 ||
+ format == gfx::BufferFormat::BGRA_8888 ||
+ format == gfx::BufferFormat::RGBX_8888 ||
+ format == gfx::BufferFormat::RGBA_8888;
+ case gfx::BufferUsage::SCANOUT_VDA_WRITE:
+ return false;
+
+ case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
+ case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
+ return
+#if defined(ARCH_CPU_X86_FAMILY)
+ // Currently only Intel driver (i.e. minigbm and
+ // Mesa) supports R_8 RG_88 and NV12.
+ // https://crbug.com/356871
+ format == gfx::BufferFormat::R_8 ||
+ format == gfx::BufferFormat::RG_88 ||
+ format == gfx::BufferFormat::YUV_420_BIPLANAR ||
+#endif
+ format == gfx::BufferFormat::BGRA_8888;
+ case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
+ // Each platform only supports one camera buffer type. We list the
+ // supported buffer formats on all platforms here. When allocating a
+ // camera buffer the caller is responsible for making sure a buffer is
+ // successfully allocated. For example, allocating YUV420_BIPLANAR
+ // for SCANOUT_CAMERA_READ_WRITE may only work on Intel boards.
+ return format == gfx::BufferFormat::YUV_420_BIPLANAR;
+ case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
+ // R_8 is used as the underlying pixel format for BLOB buffers.
+ return format == gfx::BufferFormat::R_8;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
std::unique_ptr<gfx::ClientNativePixmap>
ClientNativePixmapDmaBuf::ImportFromDmabuf(
const gfx::NativePixmapHandle& handle,
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h
index b8f5630e51e..f5da2b3a083 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h
+++ b/chromium/ui/gfx/linux/client_native_pixmap_dmabuf.h
@@ -11,14 +11,19 @@
#include "base/files/scoped_file.h"
#include "base/macros.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gfx_export.h"
#include "ui/gfx/native_pixmap_handle.h"
namespace gfx {
class ClientNativePixmapDmaBuf : public gfx::ClientNativePixmap {
public:
+ static GFX_EXPORT bool IsConfigurationSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage);
+
static std::unique_ptr<gfx::ClientNativePixmap> ImportFromDmabuf(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size);
diff --git a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
index 0fdb9cb3f87..6b0aaa84e86 100644
--- a/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
+++ b/chromium/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
@@ -12,12 +12,10 @@
#include "build/build_config.h"
#include "ui/gfx/native_pixmap_handle.h"
-#if defined(OS_CHROMEOS)
-// This can be enabled on all linux but it is not a requirement to support
-// glCreateImageChromium+Dmabuf since it uses gfx::BufferUsage::SCANOUT and
-// the pixmap does not need to be mappable on the client side.
+// Although, it's compiled for all linux platforms, it does not mean dmabuf
+// will work there. Check the comment below in the
+// ClientNativePixmapFactoryDmabuf for more details.
#include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
-#endif
namespace gfx {
@@ -47,82 +45,9 @@ class ClientNativePixmapOpaque : public ClientNativePixmap {
class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
public:
- ClientNativePixmapFactoryDmabuf() {}
+ explicit ClientNativePixmapFactoryDmabuf() {}
~ClientNativePixmapFactoryDmabuf() override {}
- // ClientNativePixmapFactory:
- bool IsConfigurationSupported(gfx::BufferFormat format,
- gfx::BufferUsage usage) const override {
- switch (usage) {
- case gfx::BufferUsage::GPU_READ:
- return format == gfx::BufferFormat::BGR_565 ||
- format == gfx::BufferFormat::RGBA_8888 ||
- format == gfx::BufferFormat::RGBX_8888 ||
- format == gfx::BufferFormat::BGRA_8888 ||
- format == gfx::BufferFormat::BGRX_8888 ||
- format == gfx::BufferFormat::YVU_420;
- case gfx::BufferUsage::SCANOUT:
- return format == gfx::BufferFormat::BGRX_8888 ||
- format == gfx::BufferFormat::RGBX_8888 ||
- format == gfx::BufferFormat::RGBA_8888 ||
- format == gfx::BufferFormat::BGRA_8888;
- case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
- return
-#if defined(ARCH_CPU_X86_FAMILY)
- // Currently only Intel driver (i.e. minigbm and Mesa) supports R_8
- // RG_88, NV12 and XB30. https://crbug.com/356871
- format == gfx::BufferFormat::R_8 ||
- format == gfx::BufferFormat::RG_88 ||
- format == gfx::BufferFormat::YUV_420_BIPLANAR ||
- format == gfx::BufferFormat::RGBX_1010102 ||
-#endif
-
- format == gfx::BufferFormat::BGRX_8888 ||
- format == gfx::BufferFormat::BGRA_8888 ||
- format == gfx::BufferFormat::RGBX_8888 ||
- format == gfx::BufferFormat::RGBA_8888;
- case gfx::BufferUsage::SCANOUT_VDA_WRITE:
- return false;
- case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
- case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: {
-#if defined(OS_CHROMEOS)
- return
-#if defined(ARCH_CPU_X86_FAMILY)
- // Currently only Intel driver (i.e. minigbm and Mesa) supports R_8
- // RG_88 and NV12. https://crbug.com/356871
- format == gfx::BufferFormat::R_8 ||
- format == gfx::BufferFormat::RG_88 ||
- format == gfx::BufferFormat::YUV_420_BIPLANAR ||
-#endif
- format == gfx::BufferFormat::BGRA_8888;
-#else
- return false;
-#endif
- }
- case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE: {
-#if defined(OS_CHROMEOS)
- // Each platform only supports one camera buffer type. We list the
- // supported buffer formats on all platforms here. When allocating a
- // camera buffer the caller is responsible for making sure a buffer is
- // successfully allocated. For example, allocating YUV420_BIPLANAR
- // for SCANOUT_CAMERA_READ_WRITE may only work on Intel boards.
- return format == gfx::BufferFormat::YUV_420_BIPLANAR;
-#else
- return false;
-#endif
- }
- case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE: {
-#if defined(OS_CHROMEOS)
- // R_8 is used as the underlying pixel format for BLOB buffers.
- return format == gfx::BufferFormat::R_8;
-#else
- return false;
-#endif
- }
- }
- NOTREACHED();
- return false;
- }
std::unique_ptr<ClientNativePixmap> ImportFromHandle(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size,
@@ -134,12 +59,7 @@ class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
-#if defined(OS_CHROMEOS)
return ClientNativePixmapDmaBuf::ImportFromDmabuf(handle, size);
-#else
- NOTREACHED();
- return nullptr;
-#endif
case gfx::BufferUsage::GPU_READ:
case gfx::BufferUsage::SCANOUT:
case gfx::BufferUsage::SCANOUT_VDA_WRITE:
@@ -152,6 +72,7 @@ class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
return nullptr;
}
+ private:
DISALLOW_COPY_AND_ASSIGN(ClientNativePixmapFactoryDmabuf);
};
diff --git a/chromium/ui/gfx/linux_font_delegate.cc b/chromium/ui/gfx/linux_font_delegate.cc
deleted file mode 100644
index 3dfdf942ece..00000000000
--- a/chromium/ui/gfx/linux_font_delegate.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/linux_font_delegate.h"
-
-namespace {
-
-gfx::LinuxFontDelegate* g_linux_font_delegate = 0;
-
-} // namespace
-
-namespace gfx {
-
-void LinuxFontDelegate::SetInstance(LinuxFontDelegate* instance) {
- g_linux_font_delegate = instance;
-}
-
-const LinuxFontDelegate* LinuxFontDelegate::instance() {
- return g_linux_font_delegate;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/mojo/BUILD.gn b/chromium/ui/gfx/mojo/BUILD.gn
index fb02266e148..5a839155076 100644
--- a/chromium/ui/gfx/mojo/BUILD.gn
+++ b/chromium/ui/gfx/mojo/BUILD.gn
@@ -23,6 +23,10 @@ mojom("mojo") {
"//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo",
]
+
+ if (is_linux || is_chromeos) {
+ enabled_features = [ "supports_native_pixmap" ]
+ }
}
mojom("test_interfaces") {
diff --git a/chromium/ui/gfx/mojo/OWNERS b/chromium/ui/gfx/mojo/OWNERS
index 34d76d93b61..89b0ae4cd2b 100644
--- a/chromium/ui/gfx/mojo/OWNERS
+++ b/chromium/ui/gfx/mojo/OWNERS
@@ -3,6 +3,8 @@ file://ipc/SECURITY_OWNERS
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *_struct_traits*.*=set noparent
per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
diff --git a/chromium/ui/gfx/mojo/accelerated_widget_struct_traits.h b/chromium/ui/gfx/mojo/accelerated_widget_struct_traits.h
index 5fc9569a1b3..62508fd41a1 100644
--- a/chromium/ui/gfx/mojo/accelerated_widget_struct_traits.h
+++ b/chromium/ui/gfx/mojo/accelerated_widget_struct_traits.h
@@ -15,7 +15,7 @@ template <>
struct StructTraits<gfx::mojom::AcceleratedWidgetDataView,
gfx::AcceleratedWidget> {
static uint64_t widget(gfx::AcceleratedWidget widget) {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_IOS)
return reinterpret_cast<uint64_t>(widget);
#elif defined(USE_OZONE) || defined(USE_X11) || defined(OS_MACOSX)
return static_cast<uint64_t>(widget);
@@ -27,7 +27,7 @@ struct StructTraits<gfx::mojom::AcceleratedWidgetDataView,
static bool Read(gfx::mojom::AcceleratedWidgetDataView data,
gfx::AcceleratedWidget* out) {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_IOS)
*out = reinterpret_cast<gfx::AcceleratedWidget>(data.widget());
return true;
#elif defined(USE_OZONE) || defined(USE_X11) || defined(OS_MACOSX)
diff --git a/chromium/ui/gfx/mojo/buffer_types.mojom b/chromium/ui/gfx/mojo/buffer_types.mojom
index 170f1eb60e3..260b0e02d23 100644
--- a/chromium/ui/gfx/mojo/buffer_types.mojom
+++ b/chromium/ui/gfx/mojo/buffer_types.mojom
@@ -4,6 +4,8 @@
module gfx.mojom;
+import "mojo/public/mojom/base/shared_memory.mojom";
+
// gfx::BufferFormat
enum BufferFormat {
R_8,
@@ -44,22 +46,13 @@ struct BufferUsageAndFormat {
BufferFormat format;
};
-// gfx::GpuMemoryBufferType
-enum GpuMemoryBufferType {
- EMPTY_BUFFER,
- SHARED_MEMORY_BUFFER,
- IO_SURFACE_BUFFER,
- NATIVE_PIXMAP,
- DXGI_SHARED_HANDLE,
- ANDROID_HARDWARE_BUFFER,
-};
-
// gfx::GpuMemoryBufferId
struct GpuMemoryBufferId {
int32 id;
};
// gfx::NativePixmapPlane
+[EnableIf=supports_native_pixmap]
struct NativePixmapPlane {
uint32 stride;
int32 offset;
@@ -68,6 +61,7 @@ struct NativePixmapPlane {
};
// gfx::NativePixmapHandle
+[EnableIf=supports_native_pixmap]
struct NativePixmapHandle {
// A file descriptor for the underlying memory object (usually dmabuf).
array<handle> fds;
@@ -89,21 +83,26 @@ struct AHardwareBufferHandle {
handle<message_pipe> tracking_pipe;
};
+union GpuMemoryBufferPlatformHandle {
+ mojo_base.mojom.UnsafeSharedMemoryRegion shared_memory_handle;
+
+ [EnableIf=supports_native_pixmap]
+ NativePixmapHandle native_pixmap_handle;
+
+ [EnableIf=is_mac]
+ handle mach_port;
+
+ [EnableIf=is_win]
+ handle dxgi_handle;
+
+ [EnableIf=is_android]
+ AHardwareBufferHandle android_hardware_buffer_handle;
+};
+
// gfx::GpuMemoryBufferHandle
struct GpuMemoryBufferHandle {
- // TODO(676224): Use preprocessor to restrict platform-specific members to
- // desired platform.
- GpuMemoryBufferType type;
GpuMemoryBufferId id;
- handle<shared_buffer>? shared_memory_handle;
uint32 offset;
uint32 stride;
- NativePixmapHandle? native_pixmap_handle;
- handle? mach_port;
-
- [EnableIf=is_win]
- handle? dxgi_handle;
-
- [EnableIf=is_android]
- AHardwareBufferHandle? android_hardware_buffer_handle;
+ GpuMemoryBufferPlatformHandle? platform_handle;
};
diff --git a/chromium/ui/gfx/mojo/buffer_types_struct_traits.cc b/chromium/ui/gfx/mojo/buffer_types_struct_traits.cc
index bfe71c55134..0536672dadd 100644
--- a/chromium/ui/gfx/mojo/buffer_types_struct_traits.cc
+++ b/chromium/ui/gfx/mojo/buffer_types_struct_traits.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/mojo/buffer_types_struct_traits.h"
#include "build/build_config.h"
+#include "mojo/public/cpp/base/shared_memory_mojom_traits.h"
#include "mojo/public/cpp/system/platform_handle.h"
#if defined(OS_ANDROID)
@@ -27,14 +28,13 @@ bool StructTraits<gfx::mojom::BufferUsageAndFormatDataView,
return data.ReadUsage(&out->usage) && data.ReadFormat(&out->format);
}
+#if defined(OS_LINUX)
std::vector<mojo::ScopedHandle>
StructTraits<gfx::mojom::NativePixmapHandleDataView, gfx::NativePixmapHandle>::
fds(const gfx::NativePixmapHandle& pixmap_handle) {
std::vector<mojo::ScopedHandle> handles;
-#if defined(OS_LINUX)
for (const base::FileDescriptor& fd : pixmap_handle.fds)
handles.emplace_back(mojo::WrapPlatformFile(fd.fd));
-#endif // defined(OS_LINUX)
return handles;
}
@@ -42,7 +42,6 @@ bool StructTraits<
gfx::mojom::NativePixmapHandleDataView,
gfx::NativePixmapHandle>::Read(gfx::mojom::NativePixmapHandleDataView data,
gfx::NativePixmapHandle* out) {
-#if defined(OS_LINUX)
mojo::ArrayDataView<mojo::ScopedHandle> handles_data_view;
data.GetFdsDataView(&handles_data_view);
for (size_t i = 0; i < handles_data_view.size(); ++i) {
@@ -55,151 +54,148 @@ bool StructTraits<
out->fds.push_back(base::FileDescriptor(platform_file, auto_close));
}
return data.ReadPlanes(&out->planes);
-#else
- return false;
-#endif
-}
-
-mojo::ScopedSharedBufferHandle
-StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
- gfx::GpuMemoryBufferHandle>::
- shared_memory_handle(const gfx::GpuMemoryBufferHandle& handle) {
- if (handle.type != gfx::SHARED_MEMORY_BUFFER)
- return mojo::ScopedSharedBufferHandle();
- return mojo::WrapSharedMemoryHandle(
- handle.handle, handle.handle.GetSize(),
- mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
}
+#endif // defined(OS_LINUX)
-const gfx::NativePixmapHandle&
-StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
- gfx::GpuMemoryBufferHandle>::
- native_pixmap_handle(const gfx::GpuMemoryBufferHandle& handle) {
+gfx::mojom::GpuMemoryBufferPlatformHandlePtr StructTraits<
+ gfx::mojom::GpuMemoryBufferHandleDataView,
+ gfx::GpuMemoryBufferHandle>::platform_handle(gfx::GpuMemoryBufferHandle&
+ handle) {
+ switch (handle.type) {
+ case gfx::EMPTY_BUFFER:
+ break;
+ case gfx::SHARED_MEMORY_BUFFER:
+ return gfx::mojom::GpuMemoryBufferPlatformHandle::NewSharedMemoryHandle(
+ std::move(handle.region));
+ case gfx::NATIVE_PIXMAP:
#if defined(OS_LINUX)
- return handle.native_pixmap_handle;
+ return gfx::mojom::GpuMemoryBufferPlatformHandle::NewNativePixmapHandle(
+ handle.native_pixmap_handle);
#else
- static base::NoDestructor<gfx::NativePixmapHandle> pixmap_handle;
- return *pixmap_handle;
+ break;
#endif
-}
-
-mojo::ScopedHandle StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
- gfx::GpuMemoryBufferHandle>::
- mach_port(const gfx::GpuMemoryBufferHandle& handle) {
+ case gfx::IO_SURFACE_BUFFER:
#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (handle.type != gfx::IO_SURFACE_BUFFER)
- return mojo::ScopedHandle();
- return mojo::WrapMachPort(handle.mach_port.get());
+ return gfx::mojom::GpuMemoryBufferPlatformHandle::NewMachPort(
+ mojo::WrapMachPort(handle.mach_port.get()));
#else
- return mojo::ScopedHandle();
+ break;
#endif
-}
-
+ case gfx::DXGI_SHARED_HANDLE:
#if defined(OS_WIN)
-// static
-mojo::ScopedHandle StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
- gfx::GpuMemoryBufferHandle>::
- dxgi_handle(const gfx::GpuMemoryBufferHandle& handle) {
- if (handle.type != gfx::DXGI_SHARED_HANDLE)
- return mojo::ScopedHandle();
- DCHECK(handle.dxgi_handle.IsValid());
- return mojo::WrapPlatformFile(handle.dxgi_handle.GetHandle());
-}
+ DCHECK(handle.dxgi_handle.IsValid());
+ return gfx::mojom::GpuMemoryBufferPlatformHandle::NewDxgiHandle(
+ mojo::WrapPlatformFile(handle.dxgi_handle.GetHandle()));
+#else
+ break;
#endif
-
+ case gfx::ANDROID_HARDWARE_BUFFER: {
#if defined(OS_ANDROID)
-// static
-gfx::mojom::AHardwareBufferHandlePtr
-StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
- gfx::GpuMemoryBufferHandle>::
- android_hardware_buffer_handle(gfx::GpuMemoryBufferHandle& handle) {
- if (handle.type != gfx::ANDROID_HARDWARE_BUFFER)
- return nullptr;
-
- // We must keep a ref to the AHardwareBuffer alive until the receiver has
- // acquired its own reference. We do this by sending a message pipe handle
- // along with the buffer. When the receiver deserializes (or even if they
- // die without ever reading the message) their end of the pipe will be
- // closed. We will eventually detect this and release the AHB reference.
- mojo::MessagePipe tracking_pipe;
- auto wrapped_handle = gfx::mojom::AHardwareBufferHandle::New(
- mojo::WrapPlatformFile(
- handle.android_hardware_buffer.SerializeAsFileDescriptor().release()),
- std::move(tracking_pipe.handle0));
-
- // Pass ownership of the input handle to our tracking pipe to keep the AHB
- // alive until it's deserialized.
- mojo::ScopeToMessagePipe(std::move(handle.android_hardware_buffer),
- std::move(tracking_pipe.handle1));
- return wrapped_handle;
-}
+ // We must keep a ref to the AHardwareBuffer alive until the receiver has
+ // acquired its own reference. We do this by sending a message pipe handle
+ // along with the buffer. When the receiver deserializes (or even if they
+ // die without ever reading the message) their end of the pipe will be
+ // closed. We will eventually detect this and release the AHB reference.
+ mojo::MessagePipe tracking_pipe;
+ auto wrapped_handle = gfx::mojom::AHardwareBufferHandle::New(
+ mojo::WrapPlatformFile(
+ handle.android_hardware_buffer.SerializeAsFileDescriptor()
+ .release()),
+ std::move(tracking_pipe.handle0));
+
+ // Pass ownership of the input handle to our tracking pipe to keep the AHB
+ // alive until it's deserialized.
+ mojo::ScopeToMessagePipe(std::move(handle.android_hardware_buffer),
+ std::move(tracking_pipe.handle1));
+ return gfx::mojom::GpuMemoryBufferPlatformHandle::
+ NewAndroidHardwareBufferHandle(std::move(wrapped_handle));
+#else
+ break;
#endif
+ }
+ }
+
+ return nullptr;
+}
bool StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle>::
Read(gfx::mojom::GpuMemoryBufferHandleDataView data,
gfx::GpuMemoryBufferHandle* out) {
- if (!data.ReadType(&out->type) || !data.ReadId(&out->id))
+ if (!data.ReadId(&out->id))
return false;
- if (out->type == gfx::SHARED_MEMORY_BUFFER) {
- mojo::ScopedSharedBufferHandle handle = data.TakeSharedMemoryHandle();
- if (handle.is_valid()) {
- MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle(
- std::move(handle), &out->handle, nullptr, nullptr);
+ out->offset = data.offset();
+ out->stride = data.stride();
+
+ gfx::mojom::GpuMemoryBufferPlatformHandlePtr platform_handle;
+ if (!data.ReadPlatformHandle(&platform_handle)) {
+ return false;
+ }
+
+ if (!platform_handle) {
+ out->type = gfx::EMPTY_BUFFER;
+ return true;
+ }
+
+ switch (platform_handle->which()) {
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
+ SHARED_MEMORY_HANDLE:
+ out->type = gfx::SHARED_MEMORY_BUFFER;
+ out->region = std::move(platform_handle->get_shared_memory_handle());
+ return true;
+#if defined(OS_LINUX)
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
+ NATIVE_PIXMAP_HANDLE:
+ out->type = gfx::NATIVE_PIXMAP;
+ out->native_pixmap_handle = platform_handle->get_native_pixmap_handle();
+ return true;
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::MACH_PORT: {
+ out->type = gfx::IO_SURFACE_BUFFER;
+ mach_port_t mach_port;
+ MojoResult unwrap_result = mojo::UnwrapMachPort(
+ std::move(platform_handle->get_mach_port()), &mach_port);
+ if (unwrap_result != MOJO_RESULT_OK)
+ return false;
+ out->mach_port.reset(mach_port);
+ return true;
+ }
+#elif defined(OS_WIN)
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::DXGI_HANDLE: {
+ out->type = gfx::DXGI_SHARED_HANDLE;
+ HANDLE handle;
+ MojoResult unwrap_result = mojo::UnwrapPlatformFile(
+ std::move(platform_handle->get_dxgi_handle()), &handle);
if (unwrap_result != MOJO_RESULT_OK)
return false;
+ out->dxgi_handle = IPC::PlatformFileForTransit(handle);
+ return true;
}
+#elif defined(OS_ANDROID)
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
+ ANDROID_HARDWARE_BUFFER_HANDLE: {
+ out->type = gfx::ANDROID_HARDWARE_BUFFER;
+ gfx::mojom::AHardwareBufferHandlePtr buffer_handle =
+ std::move(platform_handle->get_android_hardware_buffer_handle());
+ if (!buffer_handle)
+ return false;
- out->offset = data.offset();
- out->stride = data.stride();
- }
-#if defined(OS_LINUX)
- if (out->type == gfx::NATIVE_PIXMAP &&
- !data.ReadNativePixmapHandle(&out->native_pixmap_handle))
- return false;
-#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (out->type == gfx::IO_SURFACE_BUFFER) {
- mach_port_t mach_port;
- MojoResult unwrap_result =
- mojo::UnwrapMachPort(data.TakeMachPort(), &mach_port);
- if (unwrap_result != MOJO_RESULT_OK)
- return false;
- out->mach_port.reset(mach_port);
- }
+ base::PlatformFile fd;
+ MojoResult unwrap_result = mojo::UnwrapPlatformFile(
+ std::move(buffer_handle->buffer_handle), &fd);
+ base::ScopedFD scoped_fd(fd);
+ if (unwrap_result != MOJO_RESULT_OK || !scoped_fd.is_valid())
+ return false;
+
+ out->android_hardware_buffer = base::android::ScopedHardwareBufferHandle::
+ DeserializeFromFileDescriptor(std::move(scoped_fd));
+ return out->android_hardware_buffer.is_valid();
+ }
#endif
-#if defined(OS_WIN)
- if (out->type == gfx::DXGI_SHARED_HANDLE) {
- HANDLE handle;
- MojoResult unwrap_result =
- mojo::UnwrapPlatformFile(data.TakeDxgiHandle(), &handle);
- if (unwrap_result != MOJO_RESULT_OK)
- return false;
- out->dxgi_handle = IPC::PlatformFileForTransit(handle);
- out->offset = data.offset();
- out->stride = data.stride();
}
-#endif
-#if defined(OS_ANDROID)
- if (out->type == gfx::ANDROID_HARDWARE_BUFFER) {
- gfx::mojom::AHardwareBufferHandlePtr buffer_handle;
- if (!data.ReadAndroidHardwareBufferHandle(&buffer_handle) || !buffer_handle)
- return false;
- base::PlatformFile fd;
- MojoResult unwrap_result =
- mojo::UnwrapPlatformFile(std::move(buffer_handle->buffer_handle), &fd);
- base::ScopedFD scoped_fd(fd);
- if (unwrap_result != MOJO_RESULT_OK || !scoped_fd.is_valid())
- return false;
- out->android_hardware_buffer = base::android::ScopedHardwareBufferHandle::
- DeserializeFromFileDescriptor(std::move(scoped_fd));
- out->offset = data.offset();
- out->stride = data.stride();
- }
-#endif
- return true;
+ return false;
}
} // namespace mojo
diff --git a/chromium/ui/gfx/mojo/buffer_types_struct_traits.h b/chromium/ui/gfx/mojo/buffer_types_struct_traits.h
index 8c8c1fc9d5e..98866074a3a 100644
--- a/chromium/ui/gfx/mojo/buffer_types_struct_traits.h
+++ b/chromium/ui/gfx/mojo/buffer_types_struct_traits.h
@@ -177,54 +177,6 @@ struct StructTraits<gfx::mojom::BufferUsageAndFormatDataView,
};
template <>
-struct EnumTraits<gfx::mojom::GpuMemoryBufferType, gfx::GpuMemoryBufferType> {
- static gfx::mojom::GpuMemoryBufferType ToMojom(
- gfx::GpuMemoryBufferType type) {
- switch (type) {
- case gfx::GpuMemoryBufferType::EMPTY_BUFFER:
- return gfx::mojom::GpuMemoryBufferType::EMPTY_BUFFER;
- case gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER:
- return gfx::mojom::GpuMemoryBufferType::SHARED_MEMORY_BUFFER;
- case gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER:
- return gfx::mojom::GpuMemoryBufferType::IO_SURFACE_BUFFER;
- case gfx::GpuMemoryBufferType::NATIVE_PIXMAP:
- return gfx::mojom::GpuMemoryBufferType::NATIVE_PIXMAP;
- case gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE:
- return gfx::mojom::GpuMemoryBufferType::DXGI_SHARED_HANDLE;
- case gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER:
- return gfx::mojom::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER;
- }
- NOTREACHED();
- return gfx::mojom::GpuMemoryBufferType::EMPTY_BUFFER;
- }
-
- static bool FromMojom(gfx::mojom::GpuMemoryBufferType input,
- gfx::GpuMemoryBufferType* out) {
- switch (input) {
- case gfx::mojom::GpuMemoryBufferType::EMPTY_BUFFER:
- *out = gfx::GpuMemoryBufferType::EMPTY_BUFFER;
- return true;
- case gfx::mojom::GpuMemoryBufferType::SHARED_MEMORY_BUFFER:
- *out = gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER;
- return true;
- case gfx::mojom::GpuMemoryBufferType::IO_SURFACE_BUFFER:
- *out = gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER;
- return true;
- case gfx::mojom::GpuMemoryBufferType::NATIVE_PIXMAP:
- *out = gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
- return true;
- case gfx::mojom::GpuMemoryBufferType::DXGI_SHARED_HANDLE:
- *out = gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE;
- return true;
- case gfx::mojom::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER:
- *out = gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER;
- return true;
- }
- return false;
- }
-};
-
-template <>
struct StructTraits<gfx::mojom::GpuMemoryBufferIdDataView,
gfx::GpuMemoryBufferId> {
static int32_t id(const gfx::GpuMemoryBufferId& buffer_id) {
@@ -237,6 +189,7 @@ struct StructTraits<gfx::mojom::GpuMemoryBufferIdDataView,
}
};
+#if defined(OS_LINUX)
template <>
struct StructTraits<gfx::mojom::NativePixmapPlaneDataView,
gfx::NativePixmapPlane> {
@@ -265,14 +218,6 @@ struct StructTraits<gfx::mojom::NativePixmapPlaneDataView,
template <>
struct StructTraits<gfx::mojom::NativePixmapHandleDataView,
gfx::NativePixmapHandle> {
- static bool IsNull(const gfx::NativePixmapHandle& handle) {
-#if defined(OS_LINUX)
- return false;
-#else
- // NativePixmapHandle are not used on non-linux platforms.
- return true;
-#endif
- }
static std::vector<mojo::ScopedHandle> fds(
const gfx::NativePixmapHandle& pixmap_handle);
@@ -284,38 +229,22 @@ struct StructTraits<gfx::mojom::NativePixmapHandleDataView,
static bool Read(gfx::mojom::NativePixmapHandleDataView data,
gfx::NativePixmapHandle* out);
};
+#endif // defined(OS_LINUX)
template <>
struct StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
gfx::GpuMemoryBufferHandle> {
- static gfx::GpuMemoryBufferType type(
- const gfx::GpuMemoryBufferHandle& handle) {
- return handle.type;
- }
static gfx::GpuMemoryBufferId id(const gfx::GpuMemoryBufferHandle& handle) {
return handle.id;
}
- static mojo::ScopedSharedBufferHandle shared_memory_handle(
- const gfx::GpuMemoryBufferHandle& handle);
static uint32_t offset(const gfx::GpuMemoryBufferHandle& handle) {
return handle.offset;
}
static uint32_t stride(const gfx::GpuMemoryBufferHandle& handle) {
return handle.stride;
}
- static const gfx::NativePixmapHandle& native_pixmap_handle(
- const gfx::GpuMemoryBufferHandle& handle);
- static mojo::ScopedHandle mach_port(const gfx::GpuMemoryBufferHandle& handle);
-
-#if defined(OS_WIN)
- static mojo::ScopedHandle dxgi_handle(
- const gfx::GpuMemoryBufferHandle& handle);
-#endif
-
-#if defined(OS_ANDROID)
- static gfx::mojom::AHardwareBufferHandlePtr android_hardware_buffer_handle(
+ static gfx::mojom::GpuMemoryBufferPlatformHandlePtr platform_handle(
gfx::GpuMemoryBufferHandle& handle);
-#endif
static bool Read(gfx::mojom::GpuMemoryBufferHandleDataView data,
gfx::GpuMemoryBufferHandle* handle);
diff --git a/chromium/ui/gfx/mojo/struct_traits_unittest.cc b/chromium/ui/gfx/mojo/struct_traits_unittest.cc
index 56cef9be17e..b726fa2eb3a 100644
--- a/chromium/ui/gfx/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/gfx/mojo/struct_traits_unittest.cc
@@ -129,15 +129,7 @@ TEST_F(StructTraitsTest, Transform) {
EXPECT_EQ(col4row4, output.matrix().get(3, 3));
}
-// AcceleratedWidgets can only be sent between processes on some platforms.
-#if defined(OS_WIN) || defined(USE_OZONE) || defined(USE_X11) || \
- defined(OS_MACOSX)
-#define MAYBE_AcceleratedWidget AcceleratedWidget
-#else
-#define MAYBE_AcceleratedWidget DISABLED_AcceleratedWidget
-#endif
-
-TEST_F(StructTraitsTest, MAYBE_AcceleratedWidget) {
+TEST_F(StructTraitsTest, AcceleratedWidget) {
gfx::AcceleratedWidget input(CastToAcceleratedWidget(1001));
gfx::AcceleratedWidget output;
mojo::test::SerializeAndDeserialize<gfx::mojom::AcceleratedWidget>(&input,
@@ -149,14 +141,15 @@ TEST_F(StructTraitsTest, GpuMemoryBufferHandle) {
const gfx::GpuMemoryBufferId kId(99);
const uint32_t kOffset = 126;
const int32_t kStride = 256;
- base::SharedMemory shared_memory;
- ASSERT_TRUE(shared_memory.CreateAnonymous(1024));
- ASSERT_TRUE(shared_memory.Map(1024));
+ base::UnsafeSharedMemoryRegion shared_memory_region =
+ base::UnsafeSharedMemoryRegion::Create(1024);
+ ASSERT_TRUE(shared_memory_region.IsValid());
+ ASSERT_TRUE(shared_memory_region.Map().IsValid());
gfx::GpuMemoryBufferHandle handle;
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.id = kId;
- handle.handle = base::SharedMemory::DuplicateHandle(shared_memory.handle());
+ handle.region = shared_memory_region.Duplicate();
handle.offset = kOffset;
handle.stride = kStride;
@@ -168,8 +161,8 @@ TEST_F(StructTraitsTest, GpuMemoryBufferHandle) {
EXPECT_EQ(kOffset, output.offset);
EXPECT_EQ(kStride, output.stride);
- base::SharedMemory output_memory(output.handle, true);
- EXPECT_TRUE(output_memory.Map(1024));
+ base::UnsafeSharedMemoryRegion output_memory = std::move(output.region);
+ EXPECT_TRUE(output_memory.Map().IsValid());
#if defined(OS_LINUX)
gfx::GpuMemoryBufferHandle handle2;
diff --git a/chromium/ui/gfx/mojo/swap_result.typemap b/chromium/ui/gfx/mojo/swap_result.typemap
index 76d24a5085c..ee4deac51ef 100644
--- a/chromium/ui/gfx/mojo/swap_result.typemap
+++ b/chromium/ui/gfx/mojo/swap_result.typemap
@@ -4,5 +4,5 @@
mojom = "//ui/gfx/mojo/swap_result.mojom"
public_headers = [ "//ui/gfx/swap_result.h" ]
-traits_headers = [ "//ui/gfx/mojo/swap_result_enum_traits.h" ]
+traits_headers = [ "//ui/gfx/mojo/swap_result_mojom_traits.h" ]
type_mappings = [ "gfx.mojom.SwapResult=gfx::SwapResult" ]
diff --git a/chromium/ui/gfx/mojo/swap_result_enum_traits.h b/chromium/ui/gfx/mojo/swap_result_mojom_traits.h
index c32ca59b055..3c37116ef11 100644
--- a/chromium/ui/gfx/mojo/swap_result_enum_traits.h
+++ b/chromium/ui/gfx/mojo/swap_result_mojom_traits.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_MOJO_SWAP_RESULT_ENUM_TRAITS_H_
-#define UI_GFX_MOJO_SWAP_RESULT_ENUM_TRAITS_H_
+#ifndef UI_GFX_MOJO_SWAP_RESULT_MOJOM_TRAITS_H_
+#define UI_GFX_MOJO_SWAP_RESULT_MOJOM_TRAITS_H_
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "ui/gfx/mojo/swap_result.mojom-shared.h"
@@ -45,4 +45,4 @@ struct EnumTraits<gfx::mojom::SwapResult, gfx::SwapResult> {
} // namespace mojo
-#endif // UI_GFX_MOJO_SWAP_RESULT_ENUM_TRAITS_H_
+#endif // UI_GFX_MOJO_SWAP_RESULT_MOJOM_TRAITS_H_
diff --git a/chromium/ui/gfx/native_widget_types.h b/chromium/ui/gfx/native_widget_types.h
index 7ceeee14e7f..2b0b362c662 100644
--- a/chromium/ui/gfx/native_widget_types.h
+++ b/chromium/ui/gfx/native_widget_types.h
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "build/build_config.h"
+#include "ui/gfx/gfx_export.h"
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
@@ -35,9 +36,6 @@
// unless you're in the IPC layer, which will be translating between
// NativeViewIds from the renderer and NativeViews.
//
-// NativeImage: The platform-specific image type used for drawing UI elements
-// in the browser.
-//
// The name 'View' here meshes with OS X where the UI elements are called
// 'views' and with our Chrome UI code where the elements are also called
// 'views'.
@@ -117,21 +115,80 @@ typedef ui::Cursor NativeCursor;
typedef aura::Window* NativeView;
typedef aura::Window* NativeWindow;
typedef ui::Event* NativeEvent;
+constexpr NativeView kNullNativeView = nullptr;
+constexpr NativeWindow kNullNativeWindow = nullptr;
#elif defined(OS_IOS)
typedef void* NativeCursor;
typedef UIView* NativeView;
typedef UIWindow* NativeWindow;
typedef UIEvent* NativeEvent;
+constexpr NativeView kNullNativeView = nullptr;
+constexpr NativeWindow kNullNativeWindow = nullptr;
#elif defined(OS_MACOSX)
typedef NSCursor* NativeCursor;
-typedef NSView* NativeView;
-typedef NSWindow* NativeWindow;
typedef NSEvent* NativeEvent;
+// NativeViews and NativeWindows on macOS are not necessarily in the same
+// process as the NSViews and NSWindows that they represent. Require an
+// explicit function call (GetNativeNSView or GetNativeNSWindow) to retrieve
+// the underlying NSView or NSWindow.
+// https://crbug.com/893719
+class GFX_EXPORT NativeView {
+ public:
+ constexpr NativeView() {}
+ // TODO(ccameron): Make this constructor explicit.
+ constexpr NativeView(NSView* ns_view) : ns_view_(ns_view) {}
+
+ // This function name is verbose (that is, not just GetNSView) so that it
+ // is easily grep-able.
+ NSView* GetNativeNSView() const { return ns_view_; }
+
+ operator bool() const { return ns_view_ != 0; }
+ bool operator==(const NativeView& other) const {
+ return ns_view_ == other.ns_view_;
+ }
+ bool operator!=(const NativeView& other) const {
+ return ns_view_ != other.ns_view_;
+ }
+ bool operator<(const NativeView& other) const {
+ return ns_view_ < other.ns_view_;
+ }
+
+ private:
+ NSView* ns_view_ = nullptr;
+};
+class GFX_EXPORT NativeWindow {
+ public:
+ constexpr NativeWindow() {}
+ // TODO(ccameron): Make this constructor explicit.
+ constexpr NativeWindow(NSWindow* ns_window) : ns_window_(ns_window) {}
+
+ // This function name is verbose (that is, not just GetNSWindow) so that it
+ // is easily grep-able.
+ NSWindow* GetNativeNSWindow() const { return ns_window_; }
+
+ operator bool() const { return ns_window_ != 0; }
+ bool operator==(const NativeWindow& other) const {
+ return ns_window_ == other.ns_window_;
+ }
+ bool operator!=(const NativeWindow& other) const {
+ return ns_window_ != other.ns_window_;
+ }
+ bool operator<(const NativeWindow& other) const {
+ return ns_window_ < other.ns_window_;
+ }
+
+ private:
+ NSWindow* ns_window_ = nullptr;
+};
+constexpr NativeView kNullNativeView = NativeView(nullptr);
+constexpr NativeWindow kNullNativeWindow = NativeWindow(nullptr);
#elif defined(OS_ANDROID)
typedef void* NativeCursor;
typedef ui::ViewAndroid* NativeView;
typedef ui::WindowAndroid* NativeWindow;
typedef base::android::ScopedJavaGlobalRef<jobject> NativeEvent;
+constexpr NativeView kNullNativeView = nullptr;
+constexpr NativeWindow kNullNativeWindow = nullptr;
#else
#error Unknown build environment.
#endif
@@ -161,15 +218,6 @@ const ui::CursorType kNullCursor = static_cast<ui::CursorType>(0);
const gfx::NativeCursor kNullCursor = static_cast<gfx::NativeCursor>(NULL);
#endif
-#if defined(OS_IOS)
-typedef UIImage NativeImageType;
-#elif defined(OS_MACOSX)
-typedef NSImage NativeImageType;
-#else
-typedef SkBitmap NativeImageType;
-#endif
-typedef NativeImageType* NativeImage;
-
// Note: for test_shell we're packing a pointer into the NativeViewId. So, if
// you make it a type which is smaller than a pointer, you have to fix
// test_shell.
diff --git a/chromium/ui/gfx/paint_throbber.cc b/chromium/ui/gfx/paint_throbber.cc
index f3486a6d974..17b2f13a9a2 100644
--- a/chromium/ui/gfx/paint_throbber.cc
+++ b/chromium/ui/gfx/paint_throbber.cc
@@ -182,4 +182,52 @@ void PaintThrobberSpinningAfterWaiting(Canvas* canvas,
effective_elapsed_time, start_angle);
}
+GFX_EXPORT void PaintNewThrobberWaiting(Canvas* canvas,
+ const RectF& throbber_container_bounds,
+ SkColor color,
+ const base::TimeDelta& elapsed_time) {
+ // The throbber bounces back and forth. We map the elapsed time to 0->2. Time
+ // 0->1 represents when the throbber moves left to right, time 1->2 represents
+ // right to left.
+ float time =
+ 2.0f *
+ (elapsed_time.InMilliseconds() % kNewThrobberWaitingAnimationCycleMs) /
+ kNewThrobberWaitingAnimationCycleMs;
+ // 1 -> 2 values mirror back to 1 -> 0 values to represent right-to-left.
+ const bool going_back = time > 1.0f;
+ if (going_back)
+ time = 2.0f - time;
+ // This animation should be fast in the middle and slow at the edges.
+ time = Tween::CalculateValue(Tween::EASE_IN_OUT, time);
+ const float min_width = throbber_container_bounds.height();
+ // The throbber animation stretches longer when moving in (left to right) than
+ // when going back.
+ const float throbber_width =
+ (going_back ? 0.75f : 1.0f) * throbber_container_bounds.width();
+
+ // These bounds keep at least |min_width| of the throbber visible (inside the
+ // throbber bounds).
+ const float min_x =
+ throbber_container_bounds.x() - throbber_width + min_width;
+ const float max_x = throbber_container_bounds.right() - min_width;
+
+ RectF bounds = throbber_container_bounds;
+ // Linear interpolation between |min_x| and |max_x|.
+ bounds.set_x(time * (max_x - min_x) + min_x);
+ bounds.set_width(throbber_width);
+ // The throbber is designed to go out of bounds, but it should not be rendered
+ // outside |throbber_container_bounds|. This clips the throbber to the edges,
+ // which gives a smooth bouncing effect.
+ bounds.Intersect(throbber_container_bounds);
+
+ cc::PaintFlags flags;
+ flags.setColor(color);
+ flags.setStyle(cc::PaintFlags::kFill_Style);
+ // Disable anti-aliasing to effectively "pixel align" the rectangle.
+ flags.setAntiAlias(false);
+
+ // Draw with circular end caps.
+ canvas->DrawRect(bounds, flags);
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/paint_throbber.h b/chromium/ui/gfx/paint_throbber.h
index be767865898..a373d20a176 100644
--- a/chromium/ui/gfx/paint_throbber.h
+++ b/chromium/ui/gfx/paint_throbber.h
@@ -15,6 +15,7 @@ namespace gfx {
class Canvas;
class Rect;
+class RectF;
// This struct describes the "waiting" mode of a throb animation. It's useful
// for building a "spinning" state animation on top of a previous "waiting"
@@ -50,15 +51,16 @@ GFX_EXPORT void PaintThrobberSpinningAfterWaiting(
const base::TimeDelta& elapsed_time,
ThrobberWaitingState* waiting_state);
-// Paint a throbber in the "spinning" state, smoothly transitioning from a
-// previous "waiting" state described by |final_waiting_frame|.
-GFX_EXPORT void PaintThrobberSpinningForFrameAfterWaiting(
- Canvas* canvas,
- const Rect& bounds,
- SkColor color,
- uint32_t frame,
- SkColor waiting_color,
- uint32_t final_waiting_frame);
+// Paints a throbber in the "waiting" state (bouncing back and forth). Used when
+// waiting on a network response, for example.
+GFX_EXPORT void PaintNewThrobberWaiting(Canvas* canvas,
+ const RectF& throbber_container_bounds,
+ SkColor color,
+ const base::TimeDelta& elapsed_time);
+
+// Cycle time for the throbber above. Used to be able to smoothly transition
+// between the throbber and the determinite progress-bar animation.
+constexpr int kNewThrobberWaitingAnimationCycleMs = 1000;
} // namespace gfx
diff --git a/chromium/ui/gfx/path.cc b/chromium/ui/gfx/path.cc
index 70ed739ab8d..16d73946daa 100644
--- a/chromium/ui/gfx/path.cc
+++ b/chromium/ui/gfx/path.cc
@@ -4,28 +4,12 @@
#include "ui/gfx/path.h"
-#include "base/logging.h"
-
namespace gfx {
Path::Path()
: SkPath() {
}
-Path::Path(const Point* points, size_t count) {
- DCHECK(count > 1);
- moveTo(SkIntToScalar(points[0].x), SkIntToScalar(points[0].y));
- for (size_t i = 1; i < count; ++i)
- lineTo(SkIntToScalar(points[i].x), SkIntToScalar(points[i].y));
-}
-
-Path::Path(const PointF* points, size_t count) {
- DCHECK(count > 1);
- moveTo(SkFloatToScalar(points[0].x), SkFloatToScalar(points[0].y));
- for (size_t i = 1; i < count; ++i)
- lineTo(SkFloatToScalar(points[i].x), SkFloatToScalar(points[i].y));
-}
-
Path::~Path() {
}
diff --git a/chromium/ui/gfx/path.h b/chromium/ui/gfx/path.h
index e1cbfa9b93b..259053a48b3 100644
--- a/chromium/ui/gfx/path.h
+++ b/chromium/ui/gfx/path.h
@@ -14,24 +14,11 @@
namespace gfx {
+// DEPRECATED, use SkPath directly.
+// TODO(collinbaker): remove this class and replace all references with SkPath.
class GFX_EXPORT Path : public SkPath {
public:
- // Used by Path(Point,size_t) constructor.
- struct Point {
- int x;
- int y;
- };
- struct PointF {
- float x;
- float y;
- };
-
Path();
-
- // Creates a path populated with the specified points.
- Path(const Point* points, size_t count);
- Path(const PointF* points, size_t count);
-
~Path();
};
diff --git a/chromium/ui/gfx/platform_font_fuchsia.cc b/chromium/ui/gfx/platform_font_fuchsia.cc
deleted file mode 100644
index d1500668323..00000000000
--- a/chromium/ui/gfx/platform_font_fuchsia.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2017 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/gfx/platform_font.h"
-
-#include "base/logging.h"
-
-namespace gfx {
-
-// static
-PlatformFont* PlatformFont::CreateDefault() {
- // TODO(fuchsia): Stubbed during headless bringup, https://crbug.com/743296.
- NOTIMPLEMENTED();
- return NULL;
-}
-
-// static
-PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
- int font_size) {
- // TODO(fuchsia): Stubbed during headless bringup, https://crbug.com/743296.
- NOTIMPLEMENTED();
- return NULL;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/platform_font_linux.cc b/chromium/ui/gfx/platform_font_skia.cc
index 0f45d859fac..81a77adcee7 100644
--- a/chromium/ui/gfx/platform_font_linux.cc
+++ b/chromium/ui/gfx/platform_font_skia.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/platform_font_linux.h"
+#include "ui/gfx/platform_font_skia.h"
#include <algorithm>
#include <string>
@@ -19,7 +19,8 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
-#include "ui/gfx/linux_font_delegate.h"
+#include "ui/gfx/font_render_params.h"
+#include "ui/gfx/skia_font_delegate.h"
#include "ui/gfx/text_utils.h"
namespace gfx {
@@ -35,7 +36,7 @@ const char* kFallbackFontFamilyName = "sans";
#endif
// The default font, used for the default constructor.
-base::LazyInstance<scoped_refptr<PlatformFontLinux>>::Leaky g_default_font =
+base::LazyInstance<scoped_refptr<PlatformFontSkia>>::Leaky g_default_font =
LAZY_INSTANCE_INITIALIZER;
// Creates a SkTypeface for the passed-in Font::FontStyle and family. If a
@@ -58,8 +59,8 @@ sk_sp<SkTypeface> CreateSkTypeface(bool italic,
if (!typeface) {
// A non-scalable font such as .pcf is specified. Fall back to a default
// scalable font.
- typeface = sk_sp<SkTypeface>(SkTypeface::MakeFromName(
- kFallbackFontFamilyName, sk_style));
+ typeface = sk_sp<SkTypeface>(
+ SkTypeface::MakeFromName(kFallbackFontFamilyName, sk_style));
if (!typeface) {
*out_success = false;
return nullptr;
@@ -72,20 +73,18 @@ sk_sp<SkTypeface> CreateSkTypeface(bool italic,
} // namespace
-#if defined(OS_CHROMEOS)
-std::string* PlatformFontLinux::default_font_description_ = NULL;
-#endif
+std::string* PlatformFontSkia::default_font_description_ = NULL;
////////////////////////////////////////////////////////////////////////////////
-// PlatformFontLinux, public:
+// PlatformFontSkia, public:
-PlatformFontLinux::PlatformFontLinux() {
+PlatformFontSkia::PlatformFontSkia() {
CHECK(InitDefaultFont()) << "Could not find the default font";
InitFromPlatformFont(g_default_font.Get().get());
}
-PlatformFontLinux::PlatformFontLinux(const std::string& font_name,
- int font_size_pixels) {
+PlatformFontSkia::PlatformFontSkia(const std::string& font_name,
+ int font_size_pixels) {
FontRenderParamsQuery query;
query.families.push_back(font_name);
query.pixel_size = font_size_pixels;
@@ -95,10 +94,10 @@ PlatformFontLinux::PlatformFontLinux(const std::string& font_name,
}
////////////////////////////////////////////////////////////////////////////////
-// PlatformFontLinux, PlatformFont implementation:
+// PlatformFontSkia, PlatformFont implementation:
// static
-bool PlatformFontLinux::InitDefaultFont() {
+bool PlatformFontSkia::InitDefaultFont() {
if (g_default_font.Get())
return true;
@@ -109,10 +108,16 @@ bool PlatformFontLinux::InitDefaultFont() {
Font::Weight weight = Font::Weight::NORMAL;
FontRenderParams params;
+ // On Linux, SkiaFontDelegate is used to query the native toolkit (e.g.
+ // GTK+) for the default UI font.
+ const SkiaFontDelegate* delegate = SkiaFontDelegate::instance();
+ if (delegate) {
+ delegate->GetDefaultFontDescription(&family, &size_pixels, &style, &weight,
+ &params);
+ } else if (default_font_description_) {
#if defined(OS_CHROMEOS)
- // On Chrome OS, a FontList font description string is stored as a
- // translatable resource and passed in via SetDefaultFontDescription().
- if (default_font_description_) {
+ // On ChromeOS, a FontList font description string is stored as a
+ // translatable resource and passed in via SetDefaultFontDescription().
FontRenderParamsQuery query;
CHECK(FontList::ParseDescription(*default_font_description_,
&query.families, &query.style,
@@ -122,45 +127,36 @@ bool PlatformFontLinux::InitDefaultFont() {
size_pixels = query.pixel_size;
style = query.style;
weight = query.weight;
- }
#else
- // On Linux, LinuxFontDelegate is used to query the native toolkit (e.g.
- // GTK+) for the default UI font.
- const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
- if (delegate) {
- delegate->GetDefaultFontDescription(&family, &size_pixels, &style, &weight,
- &params);
- }
+ NOTREACHED();
#endif
+ }
sk_sp<SkTypeface> typeface =
CreateSkTypeface(style & Font::ITALIC, weight, &family, &success);
if (!success)
return false;
- g_default_font.Get() = new PlatformFontLinux(
+ g_default_font.Get() = new PlatformFontSkia(
std::move(typeface), family, size_pixels, style, weight, params);
return true;
}
// static
-void PlatformFontLinux::ReloadDefaultFont() {
+void PlatformFontSkia::ReloadDefaultFont() {
// Reset the scoped_refptr.
g_default_font.Get() = nullptr;
}
-#if defined(OS_CHROMEOS)
// static
-void PlatformFontLinux::SetDefaultFontDescription(
+void PlatformFontSkia::SetDefaultFontDescription(
const std::string& font_description) {
delete default_font_description_;
default_font_description_ = new std::string(font_description);
}
-#endif
-
-Font PlatformFontLinux::DeriveFont(int size_delta,
- int style,
- Font::Weight weight) const {
+Font PlatformFontSkia::DeriveFont(int size_delta,
+ int style,
+ Font::Weight weight) const {
const int new_size = font_size_pixels_ + size_delta;
DCHECK_GT(new_size, 0);
@@ -174,7 +170,7 @@ Font PlatformFontLinux::DeriveFont(int size_delta,
if (!success) {
LOG(ERROR) << "Could not find any font: " << new_family << ", "
<< kFallbackFontFamilyName << ". Falling back to the default";
- return Font(new PlatformFontLinux);
+ return Font(new PlatformFontSkia);
}
FontRenderParamsQuery query;
@@ -182,53 +178,54 @@ Font PlatformFontLinux::DeriveFont(int size_delta,
query.pixel_size = new_size;
query.style = style;
- return Font(new PlatformFontLinux(std::move(typeface), new_family, new_size,
- style, weight, gfx::GetFontRenderParams(query, NULL)));
+ return Font(new PlatformFontSkia(std::move(typeface), new_family, new_size,
+ style, weight,
+ gfx::GetFontRenderParams(query, NULL)));
}
-int PlatformFontLinux::GetHeight() {
+int PlatformFontSkia::GetHeight() {
ComputeMetricsIfNecessary();
return height_pixels_;
}
-Font::Weight PlatformFontLinux::GetWeight() const {
+Font::Weight PlatformFontSkia::GetWeight() const {
return weight_;
}
-int PlatformFontLinux::GetBaseline() {
+int PlatformFontSkia::GetBaseline() {
ComputeMetricsIfNecessary();
return ascent_pixels_;
}
-int PlatformFontLinux::GetCapHeight() {
+int PlatformFontSkia::GetCapHeight() {
ComputeMetricsIfNecessary();
return cap_height_pixels_;
}
-int PlatformFontLinux::GetExpectedTextWidth(int length) {
+int PlatformFontSkia::GetExpectedTextWidth(int length) {
ComputeMetricsIfNecessary();
return round(static_cast<float>(length) * average_width_pixels_);
}
-int PlatformFontLinux::GetStyle() const {
+int PlatformFontSkia::GetStyle() const {
return style_;
}
-const std::string& PlatformFontLinux::GetFontName() const {
+const std::string& PlatformFontSkia::GetFontName() const {
return font_family_;
}
-std::string PlatformFontLinux::GetActualFontNameForTesting() const {
+std::string PlatformFontSkia::GetActualFontNameForTesting() const {
SkString family_name;
typeface_->getFamilyName(&family_name);
return family_name.c_str();
}
-int PlatformFontLinux::GetFontSize() const {
+int PlatformFontSkia::GetFontSize() const {
return font_size_pixels_;
}
-const FontRenderParams& PlatformFontLinux::GetFontRenderParams() {
+const FontRenderParams& PlatformFontSkia::GetFontRenderParams() {
float current_scale_factor = GetFontRenderParamsDeviceScaleFactor();
if (current_scale_factor != device_scale_factor_) {
FontRenderParamsQuery query;
@@ -244,27 +241,26 @@ const FontRenderParams& PlatformFontLinux::GetFontRenderParams() {
}
////////////////////////////////////////////////////////////////////////////////
-// PlatformFontLinux, private:
-
-PlatformFontLinux::PlatformFontLinux(sk_sp<SkTypeface> typeface,
- const std::string& family,
- int size_pixels,
- int style,
- Font::Weight weight,
- const FontRenderParams& render_params) {
+// PlatformFontSkia, private:
+
+PlatformFontSkia::PlatformFontSkia(sk_sp<SkTypeface> typeface,
+ const std::string& family,
+ int size_pixels,
+ int style,
+ Font::Weight weight,
+ const FontRenderParams& render_params) {
InitFromDetails(std::move(typeface), family, size_pixels, style, weight,
- render_params);
+ render_params);
}
-PlatformFontLinux::~PlatformFontLinux() {}
+PlatformFontSkia::~PlatformFontSkia() {}
-void PlatformFontLinux::InitFromDetails(
- sk_sp<SkTypeface> typeface,
- const std::string& font_family,
- int font_size_pixels,
- int style,
- Font::Weight weight,
- const FontRenderParams& render_params) {
+void PlatformFontSkia::InitFromDetails(sk_sp<SkTypeface> typeface,
+ const std::string& font_family,
+ int font_size_pixels,
+ int style,
+ Font::Weight weight,
+ const FontRenderParams& render_params) {
DCHECK_GT(font_size_pixels, 0);
font_family_ = font_family;
@@ -288,7 +284,7 @@ void PlatformFontLinux::InitFromDetails(
font_render_params_ = render_params;
}
-void PlatformFontLinux::InitFromPlatformFont(const PlatformFontLinux* other) {
+void PlatformFontSkia::InitFromPlatformFont(const PlatformFontSkia* other) {
typeface_ = other->typeface_;
font_family_ = other->font_family_;
font_size_pixels_ = other->font_size_pixels_;
@@ -306,7 +302,7 @@ void PlatformFontLinux::InitFromPlatformFont(const PlatformFontLinux* other) {
}
}
-void PlatformFontLinux::ComputeMetricsIfNecessary() {
+void PlatformFontSkia::ComputeMetricsIfNecessary() {
if (metrics_need_computation_) {
metrics_need_computation_ = false;
@@ -317,9 +313,10 @@ void PlatformFontLinux::ComputeMetricsIfNecessary() {
paint.setTypeface(typeface_);
paint.setFakeBoldText(weight_ >= Font::Weight::BOLD &&
!typeface_->isBold());
- paint.setTextSkewX((Font::ITALIC & style_) && !typeface_->isItalic() ?
- -SK_Scalar1/4 : 0);
- SkPaint::FontMetrics metrics;
+ paint.setTextSkewX((Font::ITALIC & style_) && !typeface_->isItalic()
+ ? -SK_Scalar1 / 4
+ : 0);
+ SkFontMetrics metrics;
paint.getFontMetrics(&metrics);
ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
@@ -333,13 +330,13 @@ void PlatformFontLinux::ComputeMetricsIfNecessary() {
// static
PlatformFont* PlatformFont::CreateDefault() {
- return new PlatformFontLinux;
+ return new PlatformFontSkia;
}
// static
PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
int font_size) {
- return new PlatformFontLinux(font_name, font_size);
+ return new PlatformFontSkia(font_name, font_size);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/platform_font_linux.h b/chromium/ui/gfx/platform_font_skia.h
index 3dfd76c18bb..9822bf7f2c8 100644
--- a/chromium/ui/gfx/platform_font_linux.h
+++ b/chromium/ui/gfx/platform_font_skia.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_PLATFORM_FONT_LINUX_H_
-#define UI_GFX_PLATFORM_FONT_LINUX_H_
+#ifndef UI_GFX_PLATFORM_FONT_SKIA_H_
+#define UI_GFX_PLATFORM_FONT_SKIA_H_
#include <memory>
#include <string>
@@ -17,13 +17,13 @@
namespace gfx {
-class GFX_EXPORT PlatformFontLinux : public PlatformFont {
+class GFX_EXPORT PlatformFontSkia : public PlatformFont {
public:
// TODO(derat): Get rid of the default constructor in favor of using
// FontList (which also has the concept of a default font but may contain
// multiple font families) everywhere. See http://crbug.com/398885#c16.
- PlatformFontLinux();
- PlatformFontLinux(const std::string& font_name, int font_size_pixels);
+ PlatformFontSkia();
+ PlatformFontSkia(const std::string& font_name, int font_size_pixels);
// Initials the default PlatformFont. Returns true if this is successful, or
// false if fonts resources are not available. If this returns false, the
@@ -35,11 +35,12 @@ class GFX_EXPORT PlatformFontLinux : public PlatformFont {
// the locale has changed.
static void ReloadDefaultFont();
-#if defined(OS_CHROMEOS)
// Sets the default font. |font_description| is a FontList font description;
// only the first family will be used.
+ // TODO(sergeyu): Remove this function. Currently it is used only on ChromeOS
+ // to set the default font to the one loaded from resources.
+ //
static void SetDefaultFontDescription(const std::string& font_description);
-#endif
// Overridden from PlatformFont:
Font DeriveFont(int size_delta,
@@ -61,26 +62,25 @@ class GFX_EXPORT PlatformFontLinux : public PlatformFont {
private:
// Create a new instance of this object with the specified properties. Called
// from DeriveFont.
- PlatformFontLinux(sk_sp<SkTypeface> typeface,
- const std::string& family,
- int size_pixels,
- int style,
- Font::Weight weight,
- const FontRenderParams& params);
- ~PlatformFontLinux() override;
+ PlatformFontSkia(sk_sp<SkTypeface> typeface,
+ const std::string& family,
+ int size_pixels,
+ int style,
+ Font::Weight weight,
+ const FontRenderParams& params);
+ ~PlatformFontSkia() override;
// Initializes this object based on the passed-in details. If |typeface| is
// empty, a new typeface will be loaded.
- void InitFromDetails(
- sk_sp<SkTypeface> typeface,
- const std::string& font_family,
- int font_size_pixels,
- int style,
- Font::Weight weight,
- const FontRenderParams& params);
+ void InitFromDetails(sk_sp<SkTypeface> typeface,
+ const std::string& font_family,
+ int font_size_pixels,
+ int style,
+ Font::Weight weight,
+ const FontRenderParams& params);
- // Initializes this object as a copy of another PlatformFontLinux.
- void InitFromPlatformFont(const PlatformFontLinux* other);
+ // Initializes this object as a copy of another PlatformFontSkia.
+ void InitFromPlatformFont(const PlatformFontSkia* other);
// Computes the metrics if they have not yet been computed.
void ComputeMetricsIfNecessary();
@@ -105,14 +105,12 @@ class GFX_EXPORT PlatformFontLinux : public PlatformFont {
double average_width_pixels_;
Font::Weight weight_;
-#if defined(OS_CHROMEOS)
// A font description string of the format used by FontList.
static std::string* default_font_description_;
-#endif
- DISALLOW_COPY_AND_ASSIGN(PlatformFontLinux);
+ DISALLOW_COPY_AND_ASSIGN(PlatformFontSkia);
};
} // namespace gfx
-#endif // UI_GFX_PLATFORM_FONT_LINUX_H_
+#endif // UI_GFX_PLATFORM_FONT_SKIA_H_
diff --git a/chromium/ui/gfx/platform_font_linux_unittest.cc b/chromium/ui/gfx/platform_font_skia_unittest.cc
index 4d73bee9bf6..d2c6b99a083 100644
--- a/chromium/ui/gfx/platform_font_linux_unittest.cc
+++ b/chromium/ui/gfx/platform_font_skia_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/platform_font_linux.h"
+#include "ui/gfx/platform_font_skia.h"
#include <string>
@@ -11,18 +11,18 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
+#include "ui/gfx/font_names_testing.h"
#include "ui/gfx/font_render_params.h"
-#include "ui/gfx/linux_font_delegate.h"
+#include "ui/gfx/skia_font_delegate.h"
namespace gfx {
-// Implementation of LinuxFontDelegate used to control the default font
-// description on Linux.
-class TestFontDelegate : public LinuxFontDelegate {
+// Implementation of SkiaFontDelegate used to control the default font
+// description.
+class TestFontDelegate : public SkiaFontDelegate {
public:
- TestFontDelegate()
- : size_pixels_(0), style_(Font::NORMAL), weight_(Font::Weight::NORMAL) {}
- ~TestFontDelegate() override {}
+ TestFontDelegate() = default;
+ ~TestFontDelegate() override = default;
void set_family(const std::string& family) { family_ = family; }
void set_size_pixels(int size_pixels) { size_pixels_ = size_pixels; }
@@ -50,25 +50,25 @@ class TestFontDelegate : public LinuxFontDelegate {
private:
// Default values to be returned.
std::string family_;
- int size_pixels_;
- int style_;
- gfx::Font::Weight weight_;
+ int size_pixels_ = 0;
+ int style_ = Font::NORMAL;
+ gfx::Font::Weight weight_ = Font::Weight::NORMAL;
FontRenderParams params_;
DISALLOW_COPY_AND_ASSIGN(TestFontDelegate);
};
-class PlatformFontLinuxTest : public testing::Test {
+class PlatformFontSkiaTest : public testing::Test {
public:
- PlatformFontLinuxTest() {
- original_font_delegate_ = LinuxFontDelegate::instance();
- LinuxFontDelegate::SetInstance(&test_font_delegate_);
+ PlatformFontSkiaTest() {
+ original_font_delegate_ = SkiaFontDelegate::instance();
+ SkiaFontDelegate::SetInstance(&test_font_delegate_);
}
- ~PlatformFontLinuxTest() override {
- LinuxFontDelegate::SetInstance(
- const_cast<LinuxFontDelegate*>(original_font_delegate_));
- PlatformFontLinux::ReloadDefaultFont();
+ ~PlatformFontSkiaTest() override {
+ SkiaFontDelegate::SetInstance(
+ const_cast<SkiaFontDelegate*>(original_font_delegate_));
+ PlatformFontSkia::ReloadDefaultFont();
}
protected:
@@ -76,48 +76,37 @@ class PlatformFontLinuxTest : public testing::Test {
private:
// Originally-registered delegate.
- const LinuxFontDelegate* original_font_delegate_;
+ const SkiaFontDelegate* original_font_delegate_;
- DISALLOW_COPY_AND_ASSIGN(PlatformFontLinuxTest);
+ DISALLOW_COPY_AND_ASSIGN(PlatformFontSkiaTest);
};
-// Test that PlatformFontLinux's default constructor initializes the instance
+// Test that PlatformFontSkia's default constructor initializes the instance
// with the correct parameters.
-TEST_F(PlatformFontLinuxTest, DefaultFont) {
-#if defined(OS_CHROMEOS)
- PlatformFontLinux::SetDefaultFontDescription("Arimo,Tinos,13px");
-#else
- test_font_delegate_.set_family("Arimo");
+TEST_F(PlatformFontSkiaTest, DefaultFont) {
+ test_font_delegate_.set_family(kTestFontName);
test_font_delegate_.set_size_pixels(13);
test_font_delegate_.set_style(Font::NORMAL);
FontRenderParams params;
params.antialiasing = false;
params.hinting = FontRenderParams::HINTING_FULL;
test_font_delegate_.set_params(params);
-#endif
- scoped_refptr<gfx::PlatformFontLinux> font(new gfx::PlatformFontLinux());
- EXPECT_EQ("Arimo", font->GetFontName());
+ scoped_refptr<gfx::PlatformFontSkia> font(new gfx::PlatformFontSkia());
+ EXPECT_EQ(kTestFontName, font->GetFontName());
EXPECT_EQ(13, font->GetFontSize());
EXPECT_EQ(gfx::Font::NORMAL, font->GetStyle());
-#if !defined(OS_CHROMEOS)
- // On Linux, the FontRenderParams returned by the the delegate should be used.
+
EXPECT_EQ(params.antialiasing, font->GetFontRenderParams().antialiasing);
EXPECT_EQ(params.hinting, font->GetFontRenderParams().hinting);
-#endif
// Drop the old default font and check that new settings are loaded.
-#if defined(OS_CHROMEOS)
- PlatformFontLinux::SetDefaultFontDescription(
- "Tinos,Arimo,Bold Italic 15px");
-#else
- test_font_delegate_.set_family("Tinos");
+ test_font_delegate_.set_family(kSymbolFontName);
test_font_delegate_.set_size_pixels(15);
test_font_delegate_.set_style(gfx::Font::ITALIC);
test_font_delegate_.set_weight(gfx::Font::Weight::BOLD);
-#endif
- PlatformFontLinux::ReloadDefaultFont();
- scoped_refptr<gfx::PlatformFontLinux> font2(new gfx::PlatformFontLinux());
- EXPECT_EQ("Tinos", font2->GetFontName());
+ PlatformFontSkia::ReloadDefaultFont();
+ scoped_refptr<gfx::PlatformFontSkia> font2(new gfx::PlatformFontSkia());
+ EXPECT_EQ(kSymbolFontName, font2->GetFontName());
EXPECT_EQ(15, font2->GetFontSize());
EXPECT_NE(font2->GetStyle() & Font::ITALIC, 0);
EXPECT_EQ(gfx::Font::Weight::BOLD, font2->GetWeight());
diff --git a/chromium/ui/gfx/platform_font_win.cc b/chromium/ui/gfx/platform_font_win.cc
index 7a43e1309b2..e7c628c75aa 100644
--- a/chromium/ui/gfx/platform_font_win.cc
+++ b/chromium/ui/gfx/platform_font_win.cc
@@ -677,7 +677,7 @@ PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRefFromSkia(
paint.setAntiAlias(font_params.antialiasing);
paint.setTypeface(std::move(skia_face));
paint.setTextSize(-font_info.lfHeight);
- SkPaint::FontMetrics skia_metrics;
+ SkFontMetrics skia_metrics;
paint.getFontMetrics(&skia_metrics);
// The calculations below are similar to those in the CreateHFontRef
diff --git a/chromium/ui/gfx/platform_font_win.h b/chromium/ui/gfx/platform_font_win.h
index 96003b89fa4..e08ec38cc41 100644
--- a/chromium/ui/gfx/platform_font_win.h
+++ b/chromium/ui/gfx/platform_font_win.h
@@ -104,7 +104,7 @@ class GFX_EXPORT PlatformFontWin : public PlatformFont {
private:
friend class internal::SystemFonts;
- FRIEND_TEST_ALL_PREFIXES(RenderTextHarfBuzzTest, HarfBuzz_UniscribeFallback);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UniscribeFallback);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, Metrics_SkiaVersusGDI);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, DirectWriteFontSubstitution);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, AdjustFontSize);
@@ -164,8 +164,7 @@ class GFX_EXPORT PlatformFontWin : public PlatformFont {
private:
friend class base::RefCounted<HFontRef>;
- FRIEND_TEST_ALL_PREFIXES(RenderTextHarfBuzzTest,
- HarfBuzz_UniscribeFallback);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UniscribeFallback);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, Metrics_SkiaVersusGDI);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, DirectWriteFontSubstitution);
diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc
index deada9af341..46dd6934bda 100644
--- a/chromium/ui/gfx/render_text.cc
+++ b/chromium/ui/gfx/render_text.cc
@@ -21,7 +21,6 @@
#include "build/build_config.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_shader.h"
-#include "cc/paint/paint_text_blob.h"
#include "third_party/icu/source/common/unicode/rbbi.h"
#include "third_party/icu/source/common/unicode/utf16.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
@@ -232,7 +231,7 @@ void SkiaTextRenderer::DrawPosText(const SkPoint* pos,
const uint16_t* glyphs,
size_t glyph_count) {
SkTextBlobBuilder builder;
- const auto& run_buffer = builder.allocRunPos(flags_.ToSkPaint(), glyph_count);
+ const auto& run_buffer = builder.allocRunPos(flags_.ToSkFont(), glyph_count);
static_assert(sizeof(*glyphs) == sizeof(*run_buffer.glyphs), "");
memcpy(run_buffer.glyphs, glyphs, glyph_count * sizeof(*glyphs));
@@ -240,10 +239,7 @@ void SkiaTextRenderer::DrawPosText(const SkPoint* pos,
static_assert(sizeof(*pos) == 2 * sizeof(*run_buffer.pos), "");
memcpy(run_buffer.pos, pos, glyph_count * sizeof(*pos));
- canvas_skia_->drawTextBlob(
- base::MakeRefCounted<cc::PaintTextBlob>(builder.make(),
- std::vector<sk_sp<SkTypeface>>{}),
- 0, 0, flags_);
+ canvas_skia_->drawTextBlob(builder.make(), 0, 0, flags_);
}
void SkiaTextRenderer::DrawUnderline(int x,
diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc
index c8a9af201d3..849a1a88743 100644
--- a/chromium/ui/gfx/render_text_harfbuzz.cc
+++ b/chromium/ui/gfx/render_text_harfbuzz.cc
@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop_current.h"
+#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -493,7 +494,7 @@ class HarfBuzzLineBreaker {
paint.setTypeface(run.font_params.skia_face);
paint.setTextSize(SkIntToScalar(run.font_params.font_size));
paint.setAntiAlias(run.font_params.render_params.antialiasing);
- SkPaint::FontMetrics metrics;
+ SkFontMetrics metrics;
paint.getFontMetrics(&metrics);
// max_descent_ is y-down, fDescent is y-down, baseline_offset is y-down
@@ -1305,6 +1306,53 @@ std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() {
return spans;
}
+std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) {
+ EnsureLayout();
+ DCHECK(!update_display_run_list_);
+ DCHECK(Range(0, text().length()).Contains(range));
+ const size_t start =
+ IsValidCursorIndex(range.GetMin())
+ ? range.GetMin()
+ : IndexOfAdjacentGrapheme(range.GetMin(), CURSOR_BACKWARD);
+ const size_t end =
+ IsValidCursorIndex(range.GetMax())
+ ? range.GetMax()
+ : IndexOfAdjacentGrapheme(range.GetMax(), CURSOR_FORWARD);
+ const Range display_range(TextIndexToDisplayIndex(start),
+ TextIndexToDisplayIndex(end));
+ DCHECK(Range(0, GetDisplayText().length()).Contains(display_range));
+
+ std::vector<Rect> rects;
+ if (display_range.is_empty())
+ return rects;
+
+ internal::TextRunList* run_list = GetRunList();
+ for (size_t line_index = 0; line_index < lines().size(); ++line_index) {
+ const internal::Line& line = lines()[line_index];
+ // Only the last line can be empty.
+ DCHECK(!line.segments.empty() || (line_index == lines().size() - 1));
+ const float line_start_x =
+ line.segments.empty()
+ ? 0
+ : run_list->runs()[line.segments[0].run]->preceding_run_widths;
+
+ for (const internal::LineSegment& segment : line.segments) {
+ const Range intersection = segment.char_range.Intersect(display_range);
+ DCHECK(!intersection.is_reversed());
+ if (!intersection.is_empty()) {
+ const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run];
+ RangeF selected_span =
+ run.GetGraphemeSpanForCharRange(this, intersection);
+ int start_x = std::ceil(selected_span.start() - line_start_x);
+ int end_x = std::ceil(selected_span.end() - line_start_x);
+ Rect rect(start_x, 0, end_x - start_x, std::ceil(line.size.height()));
+ rects.push_back(rect + GetLineOffset(line_index));
+ }
+ }
+ }
+ return rects;
+}
+
Range RenderTextHarfBuzz::GetCursorSpan(const Range& text_range) {
DCHECK(!text_range.is_reversed());
EnsureLayout();
@@ -1422,7 +1470,8 @@ SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel(
size_t cursor = current.caret_pos();
#if defined(OS_WIN)
// Windows generally advances to the start of a word in either direction.
- // TODO: Break on the end of a word when the neighboring text is puctuation.
+ // TODO: Break on the end of a word when the neighboring text is
+ // punctuation.
if (iter.IsStartOfWord(cursor))
break;
#else
@@ -1435,53 +1484,6 @@ SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel(
return current;
}
-std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) {
- EnsureLayout();
- DCHECK(!update_display_run_list_);
- DCHECK(Range(0, text().length()).Contains(range));
- const size_t start =
- IsValidCursorIndex(range.GetMin())
- ? range.GetMin()
- : IndexOfAdjacentGrapheme(range.GetMin(), CURSOR_BACKWARD);
- const size_t end =
- IsValidCursorIndex(range.GetMax())
- ? range.GetMax()
- : IndexOfAdjacentGrapheme(range.GetMax(), CURSOR_FORWARD);
- const Range display_range(TextIndexToDisplayIndex(start),
- TextIndexToDisplayIndex(end));
- DCHECK(Range(0, GetDisplayText().length()).Contains(display_range));
-
- std::vector<Rect> rects;
- if (display_range.is_empty())
- return rects;
-
- internal::TextRunList* run_list = GetRunList();
- for (size_t line_index = 0; line_index < lines().size(); ++line_index) {
- const internal::Line& line = lines()[line_index];
- // Only the last line can be empty.
- DCHECK(!line.segments.empty() || (line_index == lines().size() - 1));
- const float line_start_x =
- line.segments.empty()
- ? 0
- : run_list->runs()[line.segments[0].run]->preceding_run_widths;
-
- for (const internal::LineSegment& segment : line.segments) {
- const Range intersection = segment.char_range.Intersect(display_range);
- DCHECK(!intersection.is_reversed());
- if (!intersection.is_empty()) {
- const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run];
- RangeF selected_span =
- run.GetGraphemeSpanForCharRange(this, intersection);
- int start_x = std::ceil(selected_span.start() - line_start_x);
- int end_x = std::ceil(selected_span.end() - line_start_x);
- Rect rect(start_x, 0, end_x - start_x, std::ceil(line.size.height()));
- rects.push_back(rect + GetLineOffset(line_index));
- }
- }
- }
- return rects;
-}
-
size_t RenderTextHarfBuzz::TextIndexToDisplayIndex(size_t index) {
return TextIndexToGivenTextIndex(GetDisplayText(), index);
}
@@ -1786,7 +1788,6 @@ void RenderTextHarfBuzz::ShapeRuns(
TRACE_EVENT1("ui", "RenderTextHarfBuzz::ShapeRuns", "run_count", runs.size());
const Font& primary_font = font_list().GetPrimaryFont();
- Font best_font(primary_font);
for (const Font& font : font_list().GetFonts()) {
internal::TextRunHarfBuzz::FontParams test_font_params = font_params;
@@ -1816,33 +1817,43 @@ void RenderTextHarfBuzz::ShapeRuns(
}
#endif
- std::vector<Font> fallback_font_list = GetFallbackFonts(primary_font);
+ std::vector<Font> fallback_font_list;
+ {
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER("RenderTextHarfBuzz.GetFallbackFontsTime");
+ TRACE_EVENT0("ui", "RenderTextHarfBuzz::GetFallbackFonts");
+ fallback_font_list = GetFallbackFonts(primary_font);
#if defined(OS_WIN)
- // Append fonts in the fallback list of the preferred fallback font.
- // TODO(tapted): Investigate whether there's a case that benefits from this on
- // Mac.
- if (!preferred_fallback_family.empty()) {
- std::vector<Font> fallback_fonts = GetFallbackFonts(fallback_font);
- fallback_font_list.insert(fallback_font_list.end(), fallback_fonts.begin(),
- fallback_fonts.end());
- }
+ // Append fonts in the fallback list of the preferred fallback font.
+ // TODO(tapted): Investigate whether there's a case that benefits from this
+ // on Mac.
+ if (!preferred_fallback_family.empty()) {
+ std::vector<Font> fallback_fonts = GetFallbackFonts(fallback_font);
+ fallback_font_list.insert(fallback_font_list.end(),
+ fallback_fonts.begin(), fallback_fonts.end());
+ }
- // Add Segoe UI and its associated linked fonts to the fallback font list to
- // ensure that the fallback list covers the basic cases.
- // http://crbug.com/467459. On some Windows configurations the default font
- // could be a raster font like System, which would not give us a reasonable
- // fallback font list.
- if (!base::LowerCaseEqualsASCII(primary_font.GetFontName(), "segoe ui") &&
- !base::LowerCaseEqualsASCII(preferred_fallback_family, "segoe ui")) {
- std::vector<Font> default_fallback_families =
- GetFallbackFonts(Font("Segoe UI", 13));
- fallback_font_list.insert(fallback_font_list.end(),
- default_fallback_families.begin(), default_fallback_families.end());
- }
+ // Add Segoe UI and its associated linked fonts to the fallback font list to
+ // ensure that the fallback list covers the basic cases.
+ // http://crbug.com/467459. On some Windows configurations the default font
+ // could be a raster font like System, which would not give us a reasonable
+ // fallback font list.
+ if (!base::LowerCaseEqualsASCII(primary_font.GetFontName(), "segoe ui") &&
+ !base::LowerCaseEqualsASCII(preferred_fallback_family, "segoe ui")) {
+ std::vector<Font> default_fallback_families =
+ GetFallbackFonts(Font("Segoe UI", 13));
+ fallback_font_list.insert(fallback_font_list.end(),
+ default_fallback_families.begin(),
+ default_fallback_families.end());
+ }
#endif
+ }
// Use a set to track the fallback fonts and avoid duplicate entries.
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER(
+ "RenderTextHarfBuzz.ShapeRunsWithFallbackFontsTime");
+ TRACE_EVENT1("ui", "RenderTextHarfBuzz::ShapeRunsWithFallbackFonts",
+ "fonts_count", fallback_font_list.size());
std::set<Font, CaseInsensitiveCompare> fallback_fonts;
// Try shaping with the fallback fonts.
@@ -1865,8 +1876,12 @@ void RenderTextHarfBuzz::ShapeRuns(
if (test_font_params.SetFontAndRenderParams(font, fallback_render_params)) {
ShapeRunsWithFont(text, test_font_params, &runs);
}
- if (runs.empty())
+ if (runs.empty()) {
+ TRACE_EVENT_INSTANT1("ui", "RenderTextHarfBuzz::FallbackFont",
+ TRACE_EVENT_SCOPE_THREAD, "font_name",
+ TRACE_STR_COPY(font_name.c_str()));
return;
+ }
}
for (internal::TextRunHarfBuzz*& run : runs) {
diff --git a/chromium/ui/gfx/render_text_harfbuzz.h b/chromium/ui/gfx/render_text_harfbuzz.h
index 46ff10e5b4f..38a99132b27 100644
--- a/chromium/ui/gfx/render_text_harfbuzz.h
+++ b/chromium/ui/gfx/render_text_harfbuzz.h
@@ -214,6 +214,7 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
SelectionModel FindCursorPosition(const Point& point) override;
bool IsSelectionSupported() const override;
std::vector<FontSpan> GetFontSpansForTesting() override;
+ std::vector<Rect> GetSubstringBounds(const Range& range) override;
Range GetCursorSpan(const Range& text_range) override;
// ICU grapheme iterator for the layout text. Can be null in case of an error.
@@ -228,7 +229,6 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
SelectionModel AdjacentWordSelectionModel(
const SelectionModel& selection,
VisualCursorDirection direction) override;
- std::vector<Rect> GetSubstringBounds(const Range& range) override;
size_t TextIndexToDisplayIndex(size_t index) override;
size_t DisplayIndexToTextIndex(size_t index) override;
bool IsValidCursorIndex(size_t index) override;
@@ -239,7 +239,7 @@ class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
private:
friend class test::RenderTextTestApi;
- friend class RenderTextHarfBuzzTest;
+ friend class RenderTextTest;
// Return the run index that contains the argument; or the length of the
// |runs_| vector if argument exceeds the text length or width.
diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc
index 6b63ba258a6..2ae6bf4375d 100644
--- a/chromium/ui/gfx/render_text_unittest.cc
+++ b/chromium/ui/gfx/render_text_unittest.cc
@@ -48,10 +48,7 @@
#endif
#if defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-
#include "base/mac/mac_util.h"
-#include "ui/gfx/render_text_mac.h"
#endif
using base::UTF8ToUTF16;
@@ -61,27 +58,6 @@ namespace gfx {
namespace {
-// An enum specifying the different RenderText implementations to be tested.
-enum RenderTextBackend {
- RENDER_TEXT_HARFBUZZ,
- RENDER_TEXT_MAC,
-};
-
-// Parameterised test name generator for tests depending on RenderTextBackend.
-struct PrintRenderTextBackend {
- template <class ParamType>
- std::string operator()(const testing::TestParamInfo<ParamType>& info) const {
- switch (info.param) {
- case RENDER_TEXT_HARFBUZZ:
- return "HarfBuzz";
- case RENDER_TEXT_MAC:
- return "Mac";
- }
- NOTREACHED();
- return std::string();
- }
-};
-
// Various weak, LTR, RTL, and Bidi string cases with three characters each.
const char kWeak[] = " . ";
const char kLtr[] = "abc";
@@ -347,41 +323,16 @@ class TestRectangleBuffer {
// Test fixture class used to run parameterized tests for all RenderText
// implementations.
-class RenderTextTest : public testing::Test,
- public ::testing::WithParamInterface<RenderTextBackend> {
+class RenderTextTest : public testing::Test {
public:
RenderTextTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI),
- render_text_(CreateRenderTextInstance()),
+ render_text_(std::make_unique<RenderTextHarfBuzz>()),
test_api_(new test::RenderTextTestApi(render_text_.get())),
renderer_(canvas()) {}
protected:
- bool IsWin8Plus() const {
-#if defined(OS_WIN)
- return base::win::GetVersion() >= base::win::VERSION_WIN8;
-#else
- return false;
-#endif
- }
-
- std::unique_ptr<RenderText> CreateRenderTextInstance() const {
- switch (GetParam()) {
- case RENDER_TEXT_HARFBUZZ:
- return std::make_unique<RenderTextHarfBuzz>();
-
- case RENDER_TEXT_MAC:
-#if defined(OS_MACOSX)
- return std::make_unique<RenderTextMac>();
-#else
- break;
-#endif
- }
- NOTREACHED();
- return nullptr;
- }
-
cc::PaintFlags& GetRendererPaint() {
return test::RenderTextTestApi::GetRendererPaint(renderer());
}
@@ -389,7 +340,6 @@ class RenderTextTest : public testing::Test,
void DrawVisualText() { test_api_->DrawVisualText(renderer()); }
const internal::TextRunList* GetHarfBuzzRunList() const {
- DCHECK_EQ(RENDER_TEXT_HARFBUZZ, GetParam());
return test_api_->GetHarfBuzzRunList();
}
@@ -443,23 +393,11 @@ class RenderTextTest : public testing::Test,
}
void ResetRenderTextInstance() {
- render_text_ = CreateRenderTextInstance();
+ render_text_ = std::make_unique<RenderTextHarfBuzz>();
test_api_.reset(new test::RenderTextTestApi(GetRenderText()));
}
- RenderText* GetRenderText() { return render_text_.get(); };
-
- RenderTextHarfBuzz* GetRenderTextHarfBuzz() {
- DCHECK_EQ(RENDER_TEXT_HARFBUZZ, GetParam());
- return static_cast<RenderTextHarfBuzz*>(GetRenderText());
- }
-
-#if defined(OS_MACOSX)
- RenderTextMac* GetRenderTextMac() {
- DCHECK_EQ(RENDER_TEXT_MAC, GetParam());
- return static_cast<RenderTextMac*>(GetRenderText());
- }
-#endif
+ RenderTextHarfBuzz* GetRenderText() { return render_text_.get(); };
Rect GetSubstringBoundsUnion(const Range& range) {
const std::vector<Rect> bounds = render_text_->GetSubstringBounds(range);
@@ -516,35 +454,6 @@ class RenderTextTest : public testing::Test,
}
}
- Canvas* canvas() { return &canvas_; }
- TestSkiaTextRenderer* renderer() { return &renderer_; }
- test::RenderTextTestApi* test_api() { return test_api_.get(); };
-
- private:
- // Needed to bypass DCHECK in GetFallbackFont.
- base::test::ScopedTaskEnvironment scoped_task_environment_;
-
- std::unique_ptr<RenderText> render_text_;
- std::unique_ptr<test::RenderTextTestApi> test_api_;
- Canvas canvas_;
- TestSkiaTextRenderer renderer_;
-
- DISALLOW_COPY_AND_ASSIGN(RenderTextTest);
-};
-
-// Test fixture class. Use for tests which are only to be run for
-// RenderTextHarfBuzz.
-class RenderTextHarfBuzzTest : public RenderTextTest {
- public:
- RenderTextHarfBuzzTest() {}
-
- // Overridden from testing::Test:
- void SetUp() override {
- RenderTextTest::SetUp();
- DCHECK_EQ(RENDER_TEXT_HARFBUZZ, GetParam());
- }
-
- protected:
void SetGlyphWidth(float test_width) {
test_api()->SetGlyphWidth(test_width);
}
@@ -558,7 +467,7 @@ class RenderTextHarfBuzzTest : public RenderTextTest {
font_params.SetFontAndRenderParams(font, render_params);
run->shape.missing_glyph_count = static_cast<size_t>(-1);
std::vector<internal::TextRunHarfBuzz*> runs = {run};
- GetRenderTextHarfBuzz()->ShapeRunsWithFont(text, font_params, &runs);
+ GetRenderText()->ShapeRunsWithFont(text, font_params, &runs);
return runs.empty();
}
@@ -568,35 +477,25 @@ class RenderTextHarfBuzzTest : public RenderTextTest {
// Do not use this function to ensure layout. This is only used to run a
// subset of the EnsureLayout functionality and check intermediate state.
- void EnsureLayoutRunList() { GetRenderTextHarfBuzz()->EnsureLayoutRunList(); }
+ void EnsureLayoutRunList() { GetRenderText()->EnsureLayoutRunList(); }
- private:
- DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzzTest);
-};
-
-#if defined(OS_MACOSX)
-// Test fixture class. Use for tests which are only to be run for RenderTextMac.
-class RenderTextMacTest : public RenderTextTest {
- public:
- RenderTextMacTest() {}
+ Canvas* canvas() { return &canvas_; }
+ TestSkiaTextRenderer* renderer() { return &renderer_; }
+ test::RenderTextTestApi* test_api() { return test_api_.get(); };
- // Overridden from testing::Test:
- void SetUp() override {
- RenderTextTest::SetUp();
- DCHECK_EQ(RENDER_TEXT_MAC, GetParam());
- }
+ private:
+ // Needed to bypass DCHECK in GetFallbackFont.
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
- protected:
- base::ScopedCFTypeRef<CTLineRef> GetCoreTextLine() {
- return GetRenderTextMac()->line_;
- }
+ std::unique_ptr<RenderTextHarfBuzz> render_text_;
+ std::unique_ptr<test::RenderTextTestApi> test_api_;
+ Canvas canvas_;
+ TestSkiaTextRenderer renderer_;
- private:
- DISALLOW_COPY_AND_ASSIGN(RenderTextMacTest);
+ DISALLOW_COPY_AND_ASSIGN(RenderTextTest);
};
-#endif
-TEST_P(RenderTextTest, DefaultStyles) {
+TEST_F(RenderTextTest, DefaultStyles) {
// Check the default styles applied to new instances and adjusted text.
RenderText* render_text = GetRenderText();
EXPECT_TRUE(render_text->text().empty());
@@ -611,7 +510,7 @@ TEST_P(RenderTextTest, DefaultStyles) {
}
}
-TEST_P(RenderTextTest, SetStyles) {
+TEST_F(RenderTextTest, SetStyles) {
// Ensure custom default styles persist across setting and clearing text.
RenderText* render_text = GetRenderText();
const SkColor color = SK_ColorRED;
@@ -636,7 +535,7 @@ TEST_P(RenderTextTest, SetStyles) {
}
}
-TEST_P(RenderTextTest, ApplyStyles) {
+TEST_F(RenderTextTest, ApplyStyles) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("012345678"));
@@ -706,18 +605,14 @@ TEST_P(RenderTextTest, ApplyStyles) {
render_text->SetText(UTF8ToUTF16("012345678"));
EXPECT_TRUE(test_api()->styles()[ITALIC].EqualsForTesting(expected_italic));
- // TODO(tmoniuszko): Enable when RenderTextMac::IsValidCursorIndex is
- // implemented. See http://crbug.com/131618.
- if (GetParam() != RENDER_TEXT_MAC) {
- // Styles shouldn't be changed mid-grapheme.
- render_text->SetText(UTF8ToUTF16("0\u0915\u093f1\u0915\u093f2"));
- render_text->ApplyStyle(UNDERLINE, true, Range(2, 5));
- EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(
- {{0, false}, {1, true}, {6, false}}));
- }
+ // Styles shouldn't be changed mid-grapheme.
+ render_text->SetText(UTF8ToUTF16("0\u0915\u093f1\u0915\u093f2"));
+ render_text->ApplyStyle(UNDERLINE, true, Range(2, 5));
+ EXPECT_TRUE(test_api()->styles()[UNDERLINE].EqualsForTesting(
+ {{0, false}, {1, true}, {6, false}}));
}
-TEST_P(RenderTextTest, AppendTextKeepsStyles) {
+TEST_F(RenderTextTest, AppendTextKeepsStyles) {
RenderText* render_text = GetRenderText();
// Setup basic functionality.
render_text->SetText(UTF8ToUTF16("abcd"));
@@ -780,8 +675,7 @@ void TestVisualCursorMotionInObscuredField(
EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, ObscuredText) {
+TEST_F(RenderTextTest, ObscuredText) {
const base::string16 seuss = UTF8ToUTF16("hop on pop");
const base::string16 no_seuss = GetObscuredString(seuss.length());
RenderText* render_text = GetRenderText();
@@ -849,7 +743,7 @@ TEST_P(RenderTextHarfBuzzTest, ObscuredText) {
}
}
-TEST_P(RenderTextTest, RevealObscuredText) {
+TEST_F(RenderTextTest, RevealObscuredText) {
const base::string16 seuss = UTF8ToUTF16("hop on pop");
const base::string16 no_seuss = GetObscuredString(seuss.length());
RenderText* render_text = GetRenderText();
@@ -937,7 +831,7 @@ TEST_P(RenderTextTest, RevealObscuredText) {
EXPECT_EQ(valid_expect_5_and_6, render_text->GetDisplayText());
}
-TEST_P(RenderTextTest, ObscuredEmoji) {
+TEST_F(RenderTextTest, ObscuredEmoji) {
// Ensures text itemization doesn't crash on obscured multi-char glyphs.
RenderText* render_text = GetRenderText();
render_text->SetObscured(true);
@@ -951,7 +845,7 @@ TEST_P(RenderTextTest, ObscuredEmoji) {
render_text->Draw(canvas());
}
-TEST_P(RenderTextTest, ElidedText) {
+TEST_F(RenderTextTest, ElidedText) {
// TODO(skanuj) : Add more test cases for following
// - RenderText styles.
// - Cross interaction of truncate, elide and obscure.
@@ -1002,7 +896,7 @@ TEST_P(RenderTextTest, ElidedText) {
{L"012\U0001D11E", L"012\u2026", true},
};
- std::unique_ptr<RenderText> expected_render_text(CreateRenderTextInstance());
+ auto expected_render_text = std::make_unique<RenderTextHarfBuzz>();
expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
@@ -1032,8 +926,8 @@ TEST_P(RenderTextTest, ElidedText) {
}
}
-TEST_P(RenderTextTest, ElidedObscuredText) {
- std::unique_ptr<RenderText> expected_render_text(CreateRenderTextInstance());
+TEST_F(RenderTextTest, ElidedObscuredText) {
+ auto expected_render_text = std::make_unique<RenderTextHarfBuzz>();
expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
const base::char16 elided_obscured_text[] = {
@@ -1052,8 +946,7 @@ TEST_P(RenderTextTest, ElidedObscuredText) {
EXPECT_EQ(elided_obscured_text, render_text->GetDisplayText());
}
-// TODO(PORT): Fails for RenderTextMac.
-TEST_P(RenderTextHarfBuzzTest, MultilineElide) {
+TEST_F(RenderTextTest, MultilineElide) {
RenderText* render_text = GetRenderText();
base::string16 input_text;
// Aim for 3 lines of text.
@@ -1105,7 +998,7 @@ TEST_P(RenderTextHarfBuzzTest, MultilineElide) {
base::string16(kEllipsisUTF16));
}
-TEST_P(RenderTextHarfBuzzTest, MultilineElideWrap) {
+TEST_F(RenderTextTest, MultilineElideWrap) {
RenderText* render_text = GetRenderText();
base::string16 input_text;
for (int i = 0; i < 20; ++i)
@@ -1138,7 +1031,7 @@ TEST_P(RenderTextHarfBuzzTest, MultilineElideWrap) {
}
}
-TEST_P(RenderTextHarfBuzzTest, MultilineElideWrapStress) {
+TEST_F(RenderTextTest, MultilineElideWrapStress) {
RenderText* render_text = GetRenderText();
base::string16 input_text;
for (int i = 0; i < 20; ++i)
@@ -1178,7 +1071,7 @@ TEST_P(RenderTextHarfBuzzTest, MultilineElideWrapStress) {
}
}
-TEST_P(RenderTextTest, ElidedEmail) {
+TEST_F(RenderTextTest, ElidedEmail) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("test@example.com"));
const Size size = render_text->GetStringSize();
@@ -1192,7 +1085,7 @@ TEST_P(RenderTextTest, ElidedEmail) {
EXPECT_GT(long_email.size(), render_text->GetDisplayText().size());
}
-TEST_P(RenderTextTest, TruncatedText) {
+TEST_F(RenderTextTest, TruncatedText) {
struct {
const wchar_t* text;
const wchar_t* display_text;
@@ -1237,7 +1130,7 @@ TEST_P(RenderTextTest, TruncatedText) {
}
}
-TEST_P(RenderTextTest, TruncatedObscuredText) {
+TEST_F(RenderTextTest, TruncatedObscuredText) {
RenderText* render_text = GetRenderText();
render_text->set_truncate_length(3);
render_text->SetObscured(true);
@@ -1246,8 +1139,7 @@ TEST_P(RenderTextTest, TruncatedObscuredText) {
EXPECT_EQ(GetObscuredString(3, 2, 0x2026), render_text->GetDisplayText());
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, TruncatedCursorMovementLTR) {
+TEST_F(RenderTextTest, TruncatedCursorMovementLTR) {
RenderText* render_text = GetRenderText();
render_text->set_truncate_length(2);
render_text->SetText(UTF8ToUTF16("abcd"));
@@ -1275,8 +1167,7 @@ TEST_P(RenderTextHarfBuzzTest, TruncatedCursorMovementLTR) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_LEFT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, TruncatedCursorMovementRTL) {
+TEST_F(RenderTextTest, TruncatedCursorMovementRTL) {
RenderText* render_text = GetRenderText();
render_text->set_truncate_length(2);
render_text->SetText(UTF8ToUTF16("\u05d0\u05d1\u05d2\u05d3"));
@@ -1304,8 +1195,7 @@ TEST_P(RenderTextHarfBuzzTest, TruncatedCursorMovementRTL) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_RIGHT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursor_Character) {
+TEST_F(RenderTextTest, MoveCursor_Character) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("123 456 789"));
std::vector<Range> expected;
@@ -1368,8 +1258,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursor_Character) {
render_text, CHARACTER_BREAK, CURSOR_LEFT, SELECTION_EXTEND, &expected);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word) {
+TEST_F(RenderTextTest, MoveCursor_Word) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("123 456 789"));
std::vector<Range> expected;
@@ -1464,8 +1353,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word) {
SELECTION_EXTEND, &expected);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word_RTL) {
+TEST_F(RenderTextTest, MoveCursor_Word_RTL) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("אבג דהו זחט"));
std::vector<Range> expected;
@@ -1560,7 +1448,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursor_Word_RTL) {
SELECTION_EXTEND, &expected);
}
-TEST_P(RenderTextTest, MoveCursor_Line) {
+TEST_F(RenderTextTest, MoveCursor_Line) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("123 456 789"));
std::vector<Range> expected;
@@ -1638,7 +1526,7 @@ TEST_P(RenderTextTest, MoveCursor_Line) {
SELECTION_EXTEND, &expected);
}
-TEST_P(RenderTextTest, GetDisplayTextDirection) {
+TEST_F(RenderTextTest, GetDisplayTextDirection) {
struct {
const char* text;
const base::i18n::TextDirection text_direction;
@@ -1694,8 +1582,7 @@ TEST_P(RenderTextTest, GetDisplayTextDirection) {
EXPECT_EQ(render_text->GetDisplayTextDirection(), base::i18n::RIGHT_TO_LEFT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtr) {
+TEST_F(RenderTextTest, MoveCursorLeftRightInLtr) {
RenderText* render_text = GetRenderText();
// Pure LTR.
render_text->SetText(UTF8ToUTF16("abc"));
@@ -1718,8 +1605,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtr) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_LEFT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtrRtl) {
+TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtl) {
RenderText* render_text = GetRenderText();
// LTR-RTL
render_text->SetText(UTF8ToUTF16("abc\u05d0\u05d1\u05d2"));
@@ -1747,8 +1633,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtrRtl) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_LEFT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtrRtlLtr) {
+TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtlLtr) {
RenderText* render_text = GetRenderText();
// LTR-RTL-LTR.
render_text->SetText(UTF8ToUTF16("a\u05d1b"));
@@ -1769,8 +1654,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInLtrRtlLtr) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_LEFT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtl) {
+TEST_F(RenderTextTest, MoveCursorLeftRightInRtl) {
RenderText* render_text = GetRenderText();
// Pure RTL.
render_text->SetText(UTF8ToUTF16("\u05d0\u05d1\u05d2"));
@@ -1794,8 +1678,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtl) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_RIGHT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtlLtr) {
+TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtr) {
RenderText* render_text = GetRenderText();
// RTL-LTR
render_text->SetText(UTF8ToUTF16("\u05d0\u05d1\u05d2abc"));
@@ -1823,8 +1706,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtlLtr) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_RIGHT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtlLtrRtl) {
+TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtrRtl) {
RenderText* render_text = GetRenderText();
// RTL-LTR-RTL.
render_text->SetText(UTF8ToUTF16("\u05d0a\u05d1"));
@@ -1846,8 +1728,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightInRtlLtrRtl) {
RunMoveCursorLeftRightTest(render_text, expected, CURSOR_RIGHT);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_ComplexScript) {
+TEST_F(RenderTextTest, MoveCursorLeftRight_ComplexScript) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("\u0915\u093f\u0915\u094d\u0915"));
EXPECT_EQ(0U, render_text->cursor_position());
@@ -1870,7 +1751,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_ComplexScript) {
EXPECT_EQ(0U, render_text->cursor_position());
}
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_MeiryoUILigatures) {
+TEST_F(RenderTextTest, MoveCursorLeftRight_MeiryoUILigatures) {
RenderText* render_text = GetRenderText();
// Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
// (code point) has unique bounds, so mid-glyph cursoring should be possible.
@@ -1895,7 +1776,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRight_MeiryoUILigatures) {
EXPECT_EQ(6U, render_text->cursor_position());
}
-TEST_P(RenderTextHarfBuzzTest, GraphemePositions) {
+TEST_F(RenderTextTest, GraphemePositions) {
// LTR कि (DEVANAGARI KA with VOWEL I) (2-char grapheme), LTR abc, and LTR कि.
const base::string16 kText1 = WideToUTF16(L"\u0915\u093fabc\u0915\u093f");
@@ -1962,8 +1843,7 @@ TEST_P(RenderTextHarfBuzzTest, GraphemePositions) {
}
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MidGraphemeSelectionBounds) {
+TEST_F(RenderTextTest, MidGraphemeSelectionBounds) {
// Test that selection bounds may be set amid multi-character graphemes.
const base::string16 kHindi = UTF8ToUTF16("\u0915\u093f");
const base::string16 kThai = UTF8ToUTF16("\u0e08\u0e33");
@@ -1997,8 +1877,7 @@ TEST_P(RenderTextHarfBuzzTest, MidGraphemeSelectionBounds) {
}
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, FindCursorPosition) {
+TEST_F(RenderTextTest, FindCursorPosition) {
const char* kTestStrings[] = {kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl};
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(0, 0, 100, 20));
@@ -2017,7 +1896,7 @@ TEST_P(RenderTextHarfBuzzTest, FindCursorPosition) {
}
// Tests that FindCursorPosition behaves correctly for multi-line text.
-TEST_P(RenderTextHarfBuzzTest, FindCursorPositionMultiline) {
+TEST_F(RenderTextTest, FindCursorPositionMultiline) {
const char* kTestStrings[] = {"abc def",
"\u05d0\u05d1\u05d2 \u05d3\u05d4\u05d5"};
@@ -2053,7 +1932,7 @@ TEST_P(RenderTextHarfBuzzTest, FindCursorPositionMultiline) {
// Ensure FindCursorPosition returns positions only at valid grapheme
// boundaries.
-TEST_P(RenderTextHarfBuzzTest, FindCursorPosition_GraphemeBoundaries) {
+TEST_F(RenderTextTest, FindCursorPosition_GraphemeBoundaries) {
struct {
base::string16 text;
std::set<size_t> expected_cursor_positions;
@@ -2081,7 +1960,7 @@ TEST_P(RenderTextHarfBuzzTest, FindCursorPosition_GraphemeBoundaries) {
}
}
-TEST_P(RenderTextTest, EdgeSelectionModels) {
+TEST_F(RenderTextTest, EdgeSelectionModels) {
// Simple Latin text.
const base::string16 kLatin = UTF8ToUTF16("abc");
// LTR कि (DEVANAGARI KA with VOWEL I).
@@ -2120,7 +1999,7 @@ TEST_P(RenderTextTest, EdgeSelectionModels) {
}
}
-TEST_P(RenderTextTest, SelectAll) {
+TEST_F(RenderTextTest, SelectAll) {
const char* const cases[] = {kWeak, kLtr, kLtrRtl, kLtrRtlLtr,
kRtl, kRtlLtr, kRtlLtrRtl};
@@ -2150,8 +2029,7 @@ TEST_P(RenderTextTest, SelectAll) {
EXPECT_EQ(was_rtl, base::i18n::IsRTL());
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightWithSelection) {
+TEST_F(RenderTextTest, MoveCursorLeftRightWithSelection) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abc\u05d0\u05d1\u05d2"));
// Left arrow on select ranging (6, 4).
@@ -2191,7 +2069,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveCursorLeftRightWithSelection) {
EXPECT_EQ(Range(4), render_text->selection());
}
-TEST_P(RenderTextTest, CenteredDisplayOffset) {
+TEST_F(RenderTextTest, CenteredDisplayOffset) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcdefghij"));
render_text->SetHorizontalAlignment(ALIGN_CENTER);
@@ -2213,49 +2091,52 @@ TEST_P(RenderTextTest, CenteredDisplayOffset) {
render_text->SetDisplayRect(display_rect);
EXPECT_EQ(display_rect.x(), render_text->GetUpdatedCursorBounds().x());
- // TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
- if (GetParam() != RENDER_TEXT_MAC) {
- // Move the cursor to the end of the text and, by checking the cursor
- // bounds, make sure no empty space is to the right of the text.
- render_text->SetCursorPosition(render_text->text().length());
- EXPECT_EQ(display_rect.right(),
- render_text->GetUpdatedCursorBounds().right());
-
- // Widen the display rect and, by checking the cursor bounds, make sure no
- // empty space is introduced to the right of the text.
- display_rect.Inset(0, 0, -kEnlargement, 0);
- render_text->SetDisplayRect(display_rect);
- EXPECT_EQ(display_rect.right(),
- render_text->GetUpdatedCursorBounds().right());
- }
+ // Move the cursor to the end of the text and, by checking the cursor
+ // bounds, make sure no empty space is to the right of the text.
+ render_text->SetCursorPosition(render_text->text().length());
+ EXPECT_EQ(display_rect.right(),
+ render_text->GetUpdatedCursorBounds().right());
+
+ // Widen the display rect and, by checking the cursor bounds, make sure no
+ // empty space is introduced to the right of the text.
+ display_rect.Inset(0, 0, -kEnlargement, 0);
+ render_text->SetDisplayRect(display_rect);
+ EXPECT_EQ(display_rect.right(),
+ render_text->GetUpdatedCursorBounds().right());
}
void MoveLeftRightByWordVerifier(RenderText* render_text, const char* str) {
- render_text->SetText(UTF8ToUTF16(str));
+ SCOPED_TRACE(str);
+ const base::string16 str16(UTF8ToUTF16(str));
+ render_text->SetText(str16);
// Test moving by word from left to right.
render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, SELECTION_NONE);
- bool first_word = true;
- while (true) {
+ const size_t num_words = (str16.length() + 1) / 4;
+ for (size_t i = 0; i < num_words; ++i) {
// First, test moving by word from a word break position, such as from
// "|abc def" to "abc| def".
const SelectionModel start = render_text->selection_model();
render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
const SelectionModel end = render_text->selection_model();
- if (end == start) // reach the end.
- break;
// For testing simplicity, each word is a 3-character word.
- int num_of_character_moves = first_word ? 3 : 4;
- first_word = false;
+#if defined(OS_WIN)
+ // Windows moves from "|abc def" to "abc |def" instead of "abc| def", so
+ // traverse 4 characters on all but the last word instead of all but the
+ // first.
+ const int num_character_moves = (i == num_words - 1) ? 3 : 4;
+#else
+ const int num_character_moves = (i == 0) ? 3 : 4;
+#endif
render_text->SetSelection(start);
- for (int j = 0; j < num_of_character_moves; ++j)
+ for (int j = 0; j < num_character_moves; ++j)
render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_NONE);
EXPECT_EQ(end, render_text->selection_model());
// Then, test moving by word from positions inside the word, such as from
// "a|bc def" to "abc| def", and from "ab|c def" to "abc| def".
- for (int j = 1; j < num_of_character_moves; ++j) {
+ for (int j = 1; j < num_character_moves; ++j) {
render_text->SetSelection(start);
for (int k = 0; k < j; ++k)
render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_NONE);
@@ -2266,22 +2147,18 @@ void MoveLeftRightByWordVerifier(RenderText* render_text, const char* str) {
// Test moving by word from right to left.
render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, SELECTION_NONE);
- first_word = true;
- while (true) {
+ for (size_t i = 0; i < num_words; ++i) {
const SelectionModel start = render_text->selection_model();
render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, SELECTION_NONE);
const SelectionModel end = render_text->selection_model();
- if (end == start) // reach the end.
- break;
- int num_of_character_moves = first_word ? 3 : 4;
- first_word = false;
+ const int num_character_moves = (i == 0) ? 3 : 4;
render_text->SetSelection(start);
- for (int j = 0; j < num_of_character_moves; ++j)
+ for (int j = 0; j < num_character_moves; ++j)
render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, SELECTION_NONE);
EXPECT_EQ(end, render_text->selection_model());
- for (int j = 1; j < num_of_character_moves; ++j) {
+ for (int j = 1; j < num_character_moves; ++j) {
render_text->SetSelection(start);
for (int k = 0; k < j; ++k)
render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, SELECTION_NONE);
@@ -2291,10 +2168,15 @@ void MoveLeftRightByWordVerifier(RenderText* render_text, const char* str) {
}
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-// TODO(msw): Make these work on Windows. http://crbug.com/196326
-#if !defined(OS_WIN)
-TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInBidiText) {
+#if defined(OS_WIN)
+// TODO(aleventhal): https://crbug.com/906308 Fix bugs, update verifier code
+// above, and enable for Windows.
+#define MAYBE_MoveLeftRightByWordInBidiText \
+ DISABLED_MoveLeftRightByWordInBidiText
+#else
+#define MAYBE_MoveLeftRightByWordInBidiText MoveLeftRightByWordInBidiText
+#endif
+TEST_F(RenderTextTest, MAYBE_MoveLeftRightByWordInBidiText) {
RenderText* render_text = GetRenderText();
// For testing simplicity, each word is a 3-character word.
std::vector<const char*> test;
@@ -2333,8 +2215,7 @@ TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInBidiText) {
MoveLeftRightByWordVerifier(render_text, test[i]);
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInBidiText_TestEndOfText) {
+TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText_TestEndOfText) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("ab\u05E1"));
@@ -2367,22 +2248,23 @@ TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInBidiText_TestEndOfText) {
// EXPECT_EQ(SelectionModel(), render_text->selection_model());
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInTextWithMultiSpaces) {
+TEST_F(RenderTextTest, MoveLeftRightByWordInTextWithMultiSpaces) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abc def"));
render_text->SetCursorPosition(5);
render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
+#if defined(OS_WIN)
+ EXPECT_EQ(8U, render_text->cursor_position());
+#else
EXPECT_EQ(11U, render_text->cursor_position());
+#endif
render_text->SetCursorPosition(5);
render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, SELECTION_NONE);
EXPECT_EQ(0U, render_text->cursor_position());
}
-#endif // !defined(OS_WIN)
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInThaiText) {
+TEST_F(RenderTextTest, MoveLeftRightByWordInThaiText) {
RenderText* render_text = GetRenderText();
// เรียกดูรวดเร็ว is broken to เรียก|ดู|รวดเร็ว.
render_text->SetText(UTF8ToUTF16("เรียกดูรวดเร็ว"));
@@ -2409,14 +2291,8 @@ TEST_P(RenderTextHarfBuzzTest, MoveLeftRightByWordInThaiText) {
// TODO(crbug.com/865527): Chinese and Japanese tokenization doesn't work on
// mobile.
-#if defined(OS_ANDROID)
-#define MAYBE_MoveLeftRightByWordInChineseText \
- DISABLED_MoveLeftRightByWordInChineseText
-#else
-#define MAYBE_MoveLeftRightByWordInChineseText MoveLeftRightByWordInChineseText
-#endif
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, MAYBE_MoveLeftRightByWordInChineseText) {
+#if !defined(OS_ANDROID)
+TEST_F(RenderTextTest, MoveLeftRightByWordInChineseText) {
RenderText* render_text = GetRenderText();
// zh-Hans-CN: 我们去公园玩, broken to 我们|去|公园|玩.
render_text->SetText(UTF8ToUTF16("\u6211\u4EEC\u53BB\u516C\u56ED\u73A9"));
@@ -2444,11 +2320,12 @@ TEST_P(RenderTextHarfBuzzTest, MAYBE_MoveLeftRightByWordInChineseText) {
render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, SELECTION_NONE);
EXPECT_EQ(0U, render_text->cursor_position());
}
+#endif
// Test the correct behavior of undirected selections: selections where the
// "end" of the selection that holds the cursor is only determined after the
// first cursor movement.
-TEST_P(RenderTextHarfBuzzTest, DirectedSelections) {
+TEST_F(RenderTextTest, DirectedSelections) {
RenderText* render_text = GetRenderText();
auto ResultAfter = [&](VisualCursorDirection direction) -> base::string16 {
@@ -2559,7 +2436,7 @@ TEST_P(RenderTextHarfBuzzTest, DirectedSelections) {
EXPECT_EQ(Range(2, 2), render_text->selection()); // Collapse right.
}
-TEST_P(RenderTextTest, StringSizeSanity) {
+TEST_F(RenderTextTest, StringSizeSanity) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("Hello World"));
const Size string_size = render_text->GetStringSize();
@@ -2567,7 +2444,7 @@ TEST_P(RenderTextTest, StringSizeSanity) {
EXPECT_GT(string_size.height(), 0);
}
-TEST_P(RenderTextTest, StringSizeLongStrings) {
+TEST_F(RenderTextTest, StringSizeLongStrings) {
RenderText* render_text = GetRenderText();
Size previous_string_size;
for (size_t length = 10; length < 1000000; length *= 10) {
@@ -2579,7 +2456,7 @@ TEST_P(RenderTextTest, StringSizeLongStrings) {
}
}
-TEST_P(RenderTextTest, StringSizeEmptyString) {
+TEST_F(RenderTextTest, StringSizeEmptyString) {
// Ascent and descent of Arial and Symbol are different on most platforms.
const FontList font_list(
base::StringPrintf("Arial,%s, 16px", kSymbolFontName));
@@ -2599,26 +2476,15 @@ TEST_P(RenderTextTest, StringSizeEmptyString) {
EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline());
}
-// TODO(865540): Find two system fonts on Android with different baseline and
-// different height.
-// See also: FontListTest::Fonts_GetHeight_GetBaseline.
-#if defined(OS_ANDROID)
-#define MAYBE_StringSizeRespectsFontListMetrics \
- DISABLED_StringSizeRespectsFontListMetrics
-#else
-#define MAYBE_StringSizeRespectsFontListMetrics \
- StringSizeRespectsFontListMetrics
-#endif
-TEST_P(RenderTextTest, MAYBE_StringSizeRespectsFontListMetrics) {
- // Check that the test font and the CJK font have different font metrics.
+TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) {
+ // NOTE: On most platforms, kCJKFontName has different metrics than
+ // kTestFontName, but on Android it does not.
Font test_font(kTestFontName, 16);
ASSERT_EQ(base::ToLowerASCII(kTestFontName),
base::ToLowerASCII(test_font.GetActualFontNameForTesting()));
Font cjk_font(kCJKFontName, 16);
ASSERT_EQ(base::ToLowerASCII(kCJKFontName),
base::ToLowerASCII(cjk_font.GetActualFontNameForTesting()));
- EXPECT_NE(test_font.GetHeight(), cjk_font.GetHeight());
- EXPECT_NE(test_font.GetBaseline(), cjk_font.GetBaseline());
// "a" should be rendered with the test font, not with the CJK font.
const char* test_font_text = "a";
// "円" (U+5168 Han character YEN) should render with the CJK font, not
@@ -2633,8 +2499,8 @@ TEST_P(RenderTextTest, MAYBE_StringSizeRespectsFontListMetrics) {
std::swap(smaller_font, larger_font);
std::swap(smaller_font_text, larger_font_text);
}
- ASSERT_LT(smaller_font.GetHeight(), larger_font.GetHeight());
- ASSERT_LT(smaller_font.GetBaseline(), larger_font.GetBaseline());
+ ASSERT_LE(smaller_font.GetHeight(), larger_font.GetHeight());
+ ASSERT_LE(smaller_font.GetBaseline(), larger_font.GetBaseline());
// Check |smaller_font_text| is rendered with the smaller font.
RenderText* render_text = GetRenderText();
@@ -2661,13 +2527,13 @@ TEST_P(RenderTextTest, MAYBE_StringSizeRespectsFontListMetrics) {
EXPECT_STRCASEEQ(
render_text->GetFontSpansForTesting()[0].first.GetFontName().c_str(),
smaller_font.GetFontName().c_str());
- EXPECT_LT(smaller_font.GetHeight(), render_text->GetStringSize().height());
- EXPECT_LT(smaller_font.GetBaseline(), render_text->GetBaseline());
+ EXPECT_LE(smaller_font.GetHeight(), render_text->GetStringSize().height());
+ EXPECT_LE(smaller_font.GetBaseline(), render_text->GetBaseline());
EXPECT_EQ(font_list.GetHeight(), render_text->GetStringSize().height());
EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline());
}
-TEST_P(RenderTextTest, MinLineHeight) {
+TEST_F(RenderTextTest, MinLineHeight) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("Hello!"));
SizeF default_size = render_text->GetStringSizeF();
@@ -2686,8 +2552,7 @@ TEST_P(RenderTextTest, MinLineHeight) {
// Check that, for Latin characters, typesetting text in the default fonts and
// sizes does not discover any glyphs that would exceed the line spacing
// recommended by gfx::Font.
-// Disabled since this relies on machine configuration. http://crbug.com/701241.
-TEST_P(RenderTextTest, DISABLED_DefaultLineHeights) {
+TEST_F(RenderTextTest, DefaultLineHeights) {
RenderText* render_text = GetRenderText();
render_text->SetText(
UTF8ToUTF16("A quick brown fox jumped over the lazy dog!"));
@@ -2722,7 +2587,7 @@ TEST_P(RenderTextTest, DISABLED_DefaultLineHeights) {
}
}
-TEST_P(RenderTextTest, SetFontList) {
+TEST_F(RenderTextTest, SetFontList) {
RenderText* render_text = GetRenderText();
render_text->SetFontList(
FontList(base::StringPrintf("Arial,%s, 13px", kSymbolFontName)));
@@ -2733,9 +2598,7 @@ TEST_P(RenderTextTest, SetFontList) {
EXPECT_EQ(13, render_text->font_list().GetFontSize());
}
-// http://crbug/624513
-#if !defined(OS_WIN)
-TEST_P(RenderTextTest, StringSizeBoldWidth) {
+TEST_F(RenderTextTest, StringSizeBoldWidth) {
// TODO(mboc): Add some unittests for other weights (currently not
// implemented because of test system font configuration).
RenderText* render_text = GetRenderText();
@@ -2761,9 +2624,8 @@ TEST_P(RenderTextTest, StringSizeBoldWidth) {
EXPECT_GT(plain_bold_width, plain_width);
EXPECT_LT(plain_bold_width, bold_width);
}
-#endif // !defined(OS_WIN)
-TEST_P(RenderTextTest, StringSizeHeight) {
+TEST_F(RenderTextTest, StringSizeHeight) {
base::string16 cases[] = {
UTF8ToUTF16("Hello World!"), // English
UTF8ToUTF16("\u6328\u62f6"), // Japanese 挨拶 (characters press & near)
@@ -2791,14 +2653,14 @@ TEST_P(RenderTextTest, StringSizeHeight) {
}
}
-TEST_P(RenderTextTest, GetBaselineSanity) {
+TEST_F(RenderTextTest, GetBaselineSanity) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("Hello World"));
const int baseline = render_text->GetBaseline();
EXPECT_GT(baseline, 0);
}
-TEST_P(RenderTextTest, CursorBoundsInReplacementMode) {
+TEST_F(RenderTextTest, CursorBoundsInReplacementMode) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcdefg"));
render_text->SetDisplayRect(Rect(100, 17));
@@ -2811,7 +2673,7 @@ TEST_P(RenderTextTest, CursorBoundsInReplacementMode) {
EXPECT_EQ(cursor_around_b.right(), cursor_before_c.x());
}
-TEST_P(RenderTextTest, GetTextOffset) {
+TEST_F(RenderTextTest, GetTextOffset) {
// The default horizontal text offset differs for LTR and RTL, and is only set
// when the RenderText object is created. This test will check the default in
// LTR mode, and the next test will check the RTL default.
@@ -2866,7 +2728,7 @@ TEST_P(RenderTextTest, GetTextOffset) {
SetRTL(was_rtl);
}
-TEST_P(RenderTextTest, GetTextOffsetHorizontalDefaultInRTL) {
+TEST_F(RenderTextTest, GetTextOffsetHorizontalDefaultInRTL) {
// This only checks the default horizontal alignment in RTL mode; all other
// GetLineOffset(0) attributes are checked by the test above.
const bool was_rtl = base::i18n::IsRTL();
@@ -2888,7 +2750,7 @@ TEST_P(RenderTextTest, GetTextOffsetHorizontalDefaultInRTL) {
SetRTL(was_rtl);
}
-TEST_P(RenderTextTest, SetDisplayOffset) {
+TEST_F(RenderTextTest, SetDisplayOffset) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcdefg"));
render_text->SetFontList(FontList("Arial, 13px"));
@@ -2962,7 +2824,7 @@ TEST_P(RenderTextTest, SetDisplayOffset) {
}
}
-TEST_P(RenderTextTest, SameFontForParentheses) {
+TEST_F(RenderTextTest, SameFontForParentheses) {
struct {
const base::char16 left_char;
const base::char16 right_char;
@@ -3039,13 +2901,13 @@ TEST_P(RenderTextTest, SameFontForParentheses) {
// Make sure the caret width is always >=1 so that the correct
// caret is drawn at high DPI. crbug.com/164100.
-TEST_P(RenderTextTest, CaretWidth) {
+TEST_F(RenderTextTest, CaretWidth) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcdefg"));
EXPECT_GE(render_text->GetUpdatedCursorBounds().width(), 1);
}
-TEST_P(RenderTextTest, SelectWord) {
+TEST_F(RenderTextTest, SelectWord) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16(" foo a.bc.d bar"));
@@ -3082,7 +2944,7 @@ TEST_P(RenderTextTest, SelectWord) {
}
// Make sure the last word is selected when the cursor is at text.length().
-TEST_P(RenderTextTest, LastWordSelected) {
+TEST_F(RenderTextTest, LastWordSelected) {
const std::string kTestURL1 = "http://www.google.com";
const std::string kTestURL2 = "http://www.google.com/something/";
@@ -3103,7 +2965,7 @@ TEST_P(RenderTextTest, LastWordSelected) {
// When given a non-empty selection, SelectWord should expand the selection to
// nearest word boundaries.
-TEST_P(RenderTextTest, SelectMultipleWords) {
+TEST_F(RenderTextTest, SelectMultipleWords) {
const std::string kTestURL = "http://www.google.com";
RenderText* render_text = GetRenderText();
@@ -3121,8 +2983,7 @@ TEST_P(RenderTextTest, SelectMultipleWords) {
EXPECT_TRUE(render_text->selection().is_reversed());
}
-// TODO(asvitkine): RenderTextMac cursor movements. http://crbug.com/131618
-TEST_P(RenderTextHarfBuzzTest, DisplayRectShowsCursorLTR) {
+TEST_F(RenderTextTest, DisplayRectShowsCursorLTR) {
ASSERT_FALSE(base::i18n::IsRTL());
ASSERT_FALSE(base::i18n::ICUIsRTL());
@@ -3177,7 +3038,7 @@ TEST_P(RenderTextHarfBuzzTest, DisplayRectShowsCursorLTR) {
EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
}
-TEST_P(RenderTextTest, DisplayRectShowsCursorRTL) {
+TEST_F(RenderTextTest, DisplayRectShowsCursorRTL) {
// Set the application default text direction to RTL.
const bool was_rtl = base::i18n::IsRTL();
SetRTL(true);
@@ -3240,7 +3101,7 @@ TEST_P(RenderTextTest, DisplayRectShowsCursorRTL) {
}
// Changing colors between or inside ligated glyphs should not break shaping.
-TEST_P(RenderTextTest, SelectionKeepsLigatures) {
+TEST_F(RenderTextTest, SelectionKeepsLigatures) {
const char* kTestStrings[] = {"\u0644\u0623", "\u0633\u0627"};
RenderText* render_text = GetRenderText();
render_text->set_selection_color(SK_ColorRED);
@@ -3261,7 +3122,7 @@ TEST_P(RenderTextTest, SelectionKeepsLigatures) {
// normally only used in a Katakana script, is also used on occasion when in
// Hiragana scripts. It shouldn't cause a Hiragana text run break since that
// could upset kerning.
-TEST_P(RenderTextTest, ScriptExtensionsDoNotBreak) {
+TEST_F(RenderTextTest, ScriptExtensionsDoNotBreak) {
// Apparently ramen restaurants prefer "らーめん" over "らあめん". The "dash"
// is the long sound symbol and usually just appears in Katakana writing.
const base::string16 ramen_hiragana = UTF8ToUTF16("らーめん");
@@ -3273,17 +3134,13 @@ TEST_P(RenderTextTest, ScriptExtensionsDoNotBreak) {
EXPECT_EQ(std::vector<base::string16>({ramen_katakana}),
RunsFor(ramen_katakana));
- // Currently Harfbuzz breaks this, but not Mac.
- if (GetParam() == RENDER_TEXT_HARFBUZZ)
- EXPECT_EQ(ToString16Vec({"らあ", "メン"}), RunsFor(ramen_mixed));
- else
- EXPECT_EQ(std::vector<base::string16>({ramen_mixed}), RunsFor(ramen_mixed));
+ EXPECT_EQ(ToString16Vec({"らあ", "メン"}), RunsFor(ramen_mixed));
}
// Test that whitespace breaks runs of text. E.g. this can permit better fonts
// to be chosen by the fallback mechanism when a font does not provide
// whitespace glyphs for all scripts. See http://crbug.com/731563.
-TEST_P(RenderTextTest, WhitespaceDoesBreak) {
+TEST_F(RenderTextTest, WhitespaceDoesBreak) {
// Title of the Wikipedia page for "bit". ASCII spaces. In Hebrew and English.
// Note that the hyphens that Wikipedia uses are different. English uses
// ASCII (U+002D) "hyphen minus", Hebrew uses the U+2013 "EN Dash".
@@ -3293,36 +3150,16 @@ TEST_P(RenderTextTest, WhitespaceDoesBreak) {
// This says "thank you very much" with a full-width non-ascii space (U+3000).
const base::string16 full_width_space = UTF8ToUTF16("ども ありがと");
- if (GetParam() == RENDER_TEXT_HARFBUZZ) {
- // Old behavior:
- // { "סיבית ", "–", " ", "ויקיפדיה"" }
- // { "Bit ", "- ", "Wikipedia" }
- // { "ども ありがと"" }.
- EXPECT_EQ(ToString16Vec({"סיבית", " ", "–", " ", "ויקיפדיה"}),
- RunsFor(ascii_space_he));
- EXPECT_EQ(ToString16Vec({"Bit", " - ", "Wikipedia"}),
- RunsFor(ascii_space_en));
- EXPECT_EQ(ToString16Vec({"ども", " ", "ありがと"}),
- RunsFor(full_width_space));
- } else {
- // Mac is a black box. From this it seems to draw RTL runs right to left and
- // is able to use typeface characteristics when breaking runs. On 10.9, the
- // Hebrew string is given a single run, and on 10.12 it's given 3 runs. It
- // doesn't really matter as far as the rest of the RenderText machinery is
- // concerned.
- auto actual = RunsFor(ascii_space_he);
- if (actual.size() == 3) {
- EXPECT_EQ(ToString16Vec({"ויקיפדיה", " – ", "סיבית"}), actual);
- } else {
- EXPECT_EQ(ToString16Vec({"סיבית – ויקיפדיה"}), actual);
- }
- EXPECT_EQ(ToString16Vec({"Bit - Wikipedia"}), RunsFor(ascii_space_en));
- EXPECT_EQ(ToString16Vec({"ども ありがと"}), RunsFor(full_width_space));
- }
+ EXPECT_EQ(ToString16Vec({"סיבית", " ", "–", " ", "ויקיפדיה"}),
+ RunsFor(ascii_space_he));
+ EXPECT_EQ(ToString16Vec({"Bit", " - ", "Wikipedia"}),
+ RunsFor(ascii_space_en));
+ EXPECT_EQ(ToString16Vec({"ども", " ", "ありがと"}),
+ RunsFor(full_width_space));
}
// Ensure strings wrap onto multiple lines for a small available width.
-TEST_P(RenderTextHarfBuzzTest, Multiline_MinWidth) {
+TEST_F(RenderTextTest, Multiline_MinWidth) {
const char* kTestStrings[] = {kWeak, kLtr, kLtrRtl, kLtrRtlLtr,
kRtl, kRtlLtr, kRtlLtrRtl};
@@ -3340,7 +3177,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_MinWidth) {
}
// Ensure strings wrap onto multiple lines for a normal available width.
-TEST_P(RenderTextHarfBuzzTest, Multiline_NormalWidth) {
+TEST_F(RenderTextTest, Multiline_NormalWidth) {
// Should RenderText suppress drawing whitespace at the end of a line?
// Currently it does not.
const struct {
@@ -3378,7 +3215,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_NormalWidth) {
2,
false}};
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
// Specify the fixed width for characters to suppress the possible variations
// of linebreak results.
@@ -3425,7 +3262,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_NormalWidth) {
// Ensure strings don't wrap onto multiple lines for a sufficient available
// width.
-TEST_P(RenderTextHarfBuzzTest, Multiline_SufficientWidth) {
+TEST_F(RenderTextTest, Multiline_SufficientWidth) {
const char* kTestStrings[] = {"", " ", ".", " . ", "abc", "a b c",
"\u062E\u0628\u0632", "\u062E \u0628 \u0632"};
@@ -3441,7 +3278,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_SufficientWidth) {
}
}
-TEST_P(RenderTextHarfBuzzTest, Multiline_Newline) {
+TEST_F(RenderTextTest, Multiline_Newline) {
const struct {
const char* const text;
const size_t lines_count;
@@ -3484,7 +3321,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_Newline) {
}
// Make sure that multiline mode ignores elide behavior.
-TEST_P(RenderTextHarfBuzzTest, Multiline_IgnoreElide) {
+TEST_F(RenderTextTest, Multiline_IgnoreElide) {
const char kTestString[] =
"very very very long string xxxxxxxxxxxxxxxxxxxxxxxxxx";
const char kEllipsis[] = "\u2026";
@@ -3501,7 +3338,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_IgnoreElide) {
render_text->GetDisplayText().find(base::UTF8ToUTF16(kEllipsis)));
}
-TEST_P(RenderTextHarfBuzzTest, Multiline_NewlineCharacterReplacement) {
+TEST_F(RenderTextTest, Multiline_NewlineCharacterReplacement) {
const char* kTestStrings[] = {
"abc\ndef", "a \n b ", "ab\n", "a\n\nb", "\nab", "\n",
};
@@ -3526,7 +3363,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_NewlineCharacterReplacement) {
}
// Ensure horizontal alignment works in multiline mode.
-TEST_P(RenderTextHarfBuzzTest, Multiline_HorizontalAlignment) {
+TEST_F(RenderTextTest, Multiline_HorizontalAlignment) {
constexpr struct {
const char* const text;
const HorizontalAlignment alignment;
@@ -3556,7 +3393,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_HorizontalAlignment) {
base::i18n::RIGHT_TO_LEFT},
};
const int kGlyphSize = 5;
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetHorizontalAlignment(ALIGN_TO_HEAD);
SetGlyphWidth(kGlyphSize);
render_text->SetDisplayRect(Rect(100, 1000));
@@ -3595,7 +3432,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_HorizontalAlignment) {
}
}
-TEST_P(RenderTextHarfBuzzTest, Multiline_WordWrapBehavior) {
+TEST_F(RenderTextTest, Multiline_WordWrapBehavior) {
const int kGlyphSize = 5;
const struct {
const WordWrapBehavior behavior;
@@ -3610,7 +3447,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_WordWrapBehavior) {
{ Range(0, 4), Range(4, 8), Range(8, 11), Range(11, 14) } },
// TODO(mukai): implement ELIDE_LONG_WORDS. It's not used right now.
};
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetMultiline(true);
render_text->SetText(UTF8ToUTF16("foo fooooo foo"));
SetGlyphWidth(kGlyphSize);
@@ -3633,7 +3470,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_WordWrapBehavior) {
}
}
-TEST_P(RenderTextHarfBuzzTest, Multiline_LineBreakerBehavior) {
+TEST_F(RenderTextTest, Multiline_LineBreakerBehavior) {
const int kGlyphSize = 5;
const struct {
const char* const text;
@@ -3669,7 +3506,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_LineBreakerBehavior) {
{Range(0, 4), Range(4, 7), Range(7, 11)}},
};
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetMultiline(true);
SetGlyphWidth(kGlyphSize);
render_text->SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
@@ -3691,16 +3528,22 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_LineBreakerBehavior) {
test_api()->lines()[j].segments[0].char_range.start(),
test_api()->lines()[j].segments[segment_size - 1].char_range.end());
EXPECT_EQ(kTestScenarios[i].char_ranges[j], line_range);
- EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize,
- test_api()->lines()[j].size.width());
+ // Depending on kerning pairs in the font, a run's length is not strictly
+ // equal to number of glyphs * kGlyphsize. Size should match within a
+ // small margin.
+ const float kSizeMargin = 0.127;
+ EXPECT_LT(
+ std::abs(kTestScenarios[i].char_ranges[j].length() * kGlyphSize -
+ test_api()->lines()[j].size.width()),
+ kSizeMargin);
}
}
}
// Test that Surrogate pairs or combining character sequences do not get
// separated by line breaking.
-TEST_P(RenderTextHarfBuzzTest, Multiline_SurrogatePairsOrCombiningChars) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, Multiline_SurrogatePairsOrCombiningChars) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetMultiline(true);
render_text->SetWordWrapBehavior(WRAP_LONG_WORDS);
@@ -3748,8 +3591,8 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_SurrogatePairsOrCombiningChars) {
}
// Test that Zero width characters have the correct line breaking behavior.
-TEST_P(RenderTextHarfBuzzTest, Multiline_ZeroWidthChars) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, Multiline_ZeroWidthChars) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
#if defined(OS_MACOSX)
// Don't use Helvetica Neue on 10.10 - it has a buggy zero-width space that
@@ -3786,7 +3629,7 @@ TEST_P(RenderTextHarfBuzzTest, Multiline_ZeroWidthChars) {
}
}
-TEST_P(RenderTextHarfBuzzTest, NewlineWithoutMultilineFlag) {
+TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) {
const char* kTestStrings[] = {
"abc\ndef", "a \n b ", "ab\n", "a\n\nb", "\nab", "\n",
};
@@ -3805,7 +3648,7 @@ TEST_P(RenderTextHarfBuzzTest, NewlineWithoutMultilineFlag) {
// Make sure the horizontal positions of runs in a line (left-to-right for
// LTR languages and right-to-left for RTL languages).
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_HorizontalPositions) {
+TEST_F(RenderTextTest, HarfBuzz_HorizontalPositions) {
const struct {
const char* const text;
const char* expected_runs;
@@ -3814,7 +3657,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_HorizontalPositions) {
{"\u062A\u0641\u0627\u062D\u05EA\u05E4\u05D5\u05D6", "[7<-4][3<-0]"},
};
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
@@ -3845,7 +3688,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_HorizontalPositions) {
}
// Test TextRunHarfBuzz's cluster finding logic.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_Clusters) {
+TEST_F(RenderTextTest, HarfBuzz_Clusters) {
struct {
uint32_t glyph_to_char[4];
Range chars[4];
@@ -3901,7 +3744,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_Clusters) {
}
// Ensures GetClusterAt does not crash on invalid conditions. crbug.com/724880
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_NoCrashOnTextRunGetClusterAt) {
+TEST_F(RenderTextTest, HarfBuzz_NoCrashOnTextRunGetClusterAt) {
internal::TextRunHarfBuzz run((Font()));
run.range = Range(0, 4);
run.shape.glyph_count = 4;
@@ -3914,7 +3757,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_NoCrashOnTextRunGetClusterAt) {
}
// Ensure that graphemes with multiple code points do not get split.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemeCases) {
+TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemeCases) {
const char* cases[] = {
// Ä (A with combining umlaut), followed by a "B".
"A\u0308B",
@@ -3924,7 +3767,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemeCases) {
"\u0e08\u0e33\u0E50",
};
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
for (size_t i = 0; i < arraysize(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("Case %" PRIuS, i));
@@ -3944,7 +3787,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemeCases) {
}
// Test the partition of a multi-grapheme cluster into grapheme ranges.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemePartition) {
+TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemePartition) {
struct {
uint32_t glyph_to_char[2];
Range bounds[4];
@@ -3979,7 +3822,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemePartition) {
run.shape.positions.resize(4);
run.shape.width = 20;
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcd"));
for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -3997,8 +3840,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_SubglyphGraphemePartition) {
}
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_RunDirection) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
const base::string16 mixed = UTF8ToUTF16("\u05D0\u05D11234\u05D2\u05D3abc");
render_text->SetText(mixed);
@@ -4012,8 +3855,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection) {
EXPECT_EQ("[8->10][7<-6][2->5][1<-0]", GetRunListStructureString());
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection_URLs) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_RunDirection_URLs) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// This string, unescaped (logical order):
// ‭www.אב.גד/הוabc/def?זח=טי‬
const base::string16 mixed = UTF8ToUTF16(
@@ -4065,11 +3908,11 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection_URLs) {
}
// More detailed tests of the LeftToRightUrls flag.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection_URLs_LeftToRight) {
+TEST_F(RenderTextTest, HarfBuzz_RunDirection_URLs_LeftToRight) {
base::test::ScopedFeatureList scoped_list;
scoped_list.InitAndEnableFeature(features::kLeftToRightUrls);
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetDirectionalityMode(DIRECTIONALITY_AS_URL);
// Systematic test of all ASCII punctuation marks, interleaved with the Hebrew
@@ -4107,8 +3950,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_RunDirection_URLs_LeftToRight) {
EXPECT_EQ(kExpectedRunListArabic, GetRunListStructureString());
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// The ▶ (U+25B6) "play character" should break runs. http://crbug.com/278913
render_text->SetText(UTF8ToUTF16("x\u25B6y"));
@@ -4122,8 +3965,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
EXPECT_EQ("[0][1][2][3][4]", GetRunListStructureString());
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByEmoji) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// 😁 (U+1F601, a smile emoji) and ✨ (U+2728, a sparkle icon) can both be
// drawn with color emoji fonts, so runs should be separated. crbug.com/448909
@@ -4142,10 +3985,10 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByEmoji) {
EXPECT_EQ("[0][1->2][3->4]", GetRunListStructureString());
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByEmojiVariationSelectors) {
+TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmojiVariationSelectors) {
constexpr int kGlyphWidth = 30;
SetGlyphWidth(30);
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
// ☎ (U+260E BLACK TELEPHONE) and U+FE0F (a variation selector) combine to
// form (on some platforms), ☎️, a red (or blue) telephone. The run can
@@ -4190,8 +4033,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByEmojiVariationSelectors) {
EXPECT_EQ(3 * kGlyphWidth, render_text->GetUpdatedCursorBounds().x());
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_OrphanedVariationSelector) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_OrphanedVariationSelector) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// It should never happen in normal usage, but a variation selector can appear
// by itself. In this case, it can form its own text run, with no glyphs.
@@ -4202,8 +4045,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_OrphanedVariationSelector) {
CheckBoundsForCursorPositions();
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_AsciiVariationSelector) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_AsciiVariationSelector) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
#if defined(OS_MACOSX)
// Don't use a system font on macOS - asking for a variation selector on
// ASCII glyphs can tickle OS bugs. See http://crbug.com/785522.
@@ -4219,8 +4062,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_AsciiVariationSelector) {
CheckBoundsForCursorPositions();
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_LeadingVariationSelector) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_LeadingVariationSelector) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// When a variation selector appears either side of an emoji, ensure the one
// after is in the same run.
@@ -4231,8 +4074,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_LeadingVariationSelector) {
CheckBoundsForCursorPositions();
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_TrailingVariationSelector) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_TrailingVariationSelector) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// If a redundant variation selector appears in an emoji run, it also gets
// merged into the emoji run. Usually there should be no effect. That's
@@ -4245,8 +4088,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_TrailingVariationSelector) {
CheckBoundsForCursorPositions();
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_MultipleVariationSelectorEmoji) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_MultipleVariationSelectorEmoji) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// Two emoji with variation selectors appearing in a correct sequence should
// be in the same run.
@@ -4257,8 +4100,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_MultipleVariationSelectorEmoji) {
CheckBoundsForCursorPositions();
}
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByAscii) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_BreakRunsByAscii) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
// 🐱 (U+1F431, a cat face) and an ASCII period should have separate runs.
// Windows requires wide strings for \Unnnnnnnn universal character names.
@@ -4271,7 +4114,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_BreakRunsByAscii) {
// Test that, on Mac, font fallback mechanisms and Harfbuzz configuration cause
// the correct glyphs to be chosen for unicode regional indicators.
-TEST_P(RenderTextHarfBuzzTest, EmojiFlagGlyphCount) {
+TEST_F(RenderTextTest, EmojiFlagGlyphCount) {
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(1000, 1000));
// Two flags: UK and Japan. Note macOS 10.9 only has flags for 10 countries.
@@ -4293,7 +4136,7 @@ TEST_P(RenderTextHarfBuzzTest, EmojiFlagGlyphCount) {
#endif
}
-TEST_P(RenderTextHarfBuzzTest, GlyphBounds) {
+TEST_F(RenderTextTest, GlyphBounds) {
const char* kTestStrings[] = {"asdf 1234 qwer", "\u0647\u0654",
"\u0645\u0631\u062D\u0628\u0627"};
RenderText* render_text = GetRenderText();
@@ -4308,8 +4151,8 @@ TEST_P(RenderTextHarfBuzzTest, GlyphBounds) {
}
// Ensure that shaping with a non-existent font does not cause a crash.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_NonExistentFont) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_NonExistentFont) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("test"));
test_api()->EnsureLayout();
const internal::TextRunList* run_list = GetHarfBuzzRunList();
@@ -4320,9 +4163,9 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_NonExistentFont) {
}
// Ensure an empty run returns sane values to queries.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_EmptyRun) {
+TEST_F(RenderTextTest, HarfBuzz_EmptyRun) {
internal::TextRunHarfBuzz run((Font()));
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("abcdefgh"));
run.range = Range(3, 8);
@@ -4338,8 +4181,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_EmptyRun) {
// Ensure the line breaker doesn't compute the word's width bigger than the
// actual size. See http://crbug.com/470073
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_WordWidthWithDiacritics) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_WordWidthWithDiacritics) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
const base::string16 kWord = UTF8ToUTF16("\u0906\u092A\u0915\u0947 ");
render_text->SetText(kWord);
const SizeF text_size = render_text->GetStringSizeF();
@@ -4354,7 +4197,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_WordWidthWithDiacritics) {
}
// Ensure a string fits in a display rect with a width equal to the string's.
-TEST_P(RenderTextTest, StringFitsOwnWidth) {
+TEST_F(RenderTextTest, StringFitsOwnWidth) {
RenderText* render_text = GetRenderText();
const base::string16 kString = UTF8ToUTF16("www.example.com");
@@ -4368,12 +4211,11 @@ TEST_P(RenderTextTest, StringFitsOwnWidth) {
EXPECT_EQ(kString, render_text->GetDisplayText());
}
-// TODO(derat): Figure out why this fails on Windows: http://crbug.com/427184
// TODO(865715): Figure out why this fails on Android.
-#if !defined(OS_WIN) && !defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
// Ensure that RenderText examines all of the fonts in its FontList before
// falling back to other fonts.
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_FontListFallback) {
+TEST_F(RenderTextTest, HarfBuzz_FontListFallback) {
// Double-check that the requested fonts are present.
std::string format = std::string(kTestFontName) + ", %s, 12px";
FontList font_list(base::StringPrintf(format.c_str(), kSymbolFontName));
@@ -4386,7 +4228,7 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_FontListFallback) {
// "⊕" (U+2295, CIRCLED PLUS) should be rendered with Symbol rather than
// falling back to some other font that's present on the system.
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetFontList(font_list);
render_text->SetText(UTF8ToUTF16("\u2295"));
const std::vector<RenderText::FontSpan> spans =
@@ -4394,12 +4236,12 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_FontListFallback) {
ASSERT_EQ(static_cast<size_t>(1), spans.size());
EXPECT_STRCASEEQ(kSymbolFontName, spans[0].first.GetFontName().c_str());
}
-#endif // !defined(OS_WIN) && !defined(OS_ANDROID)
+#endif // !defined(OS_ANDROID)
// Ensure that the fallback fonts of the Uniscribe font are tried for shaping.
#if defined(OS_WIN)
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_UniscribeFallback) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_UniscribeFallback) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
PlatformFontWin* font_win = new PlatformFontWin("Meiryo", 12);
// Japanese name for Meiryo. This name won't be found in the system's linked
// fonts, forcing RTHB to try the Uniscribe font and its fallbacks.
@@ -4421,8 +4263,8 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_UniscribeFallback) {
// particular character, and that there is a system fallback font which does.
// TODO(msw): Fallback doesn't find a glyph on Linux and Android.
#if !defined(OS_LINUX) && !defined(OS_ANDROID)
-TEST_P(RenderTextHarfBuzzTest, HarfBuzz_UnicodeFallback) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, HarfBuzz_UnicodeFallback) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetFontList(FontList("Arial, 12px"));
// An invalid Unicode character that somehow yields Korean character "han".
@@ -4432,11 +4274,11 @@ TEST_P(RenderTextHarfBuzzTest, HarfBuzz_UnicodeFallback) {
ASSERT_EQ(1U, run_list->size());
EXPECT_EQ(0U, run_list->runs()[0]->CountMissingGlyphs());
}
-#endif // !defined(OS_LINUX)
+#endif // !defined(OS_LINUX) && !defined(OS_ANDROID)
// Ensure that the width reported by RenderText is sufficient for drawing. Draws
// to a canvas and checks if any pixel beyond the bounding rectangle is colored.
-TEST_P(RenderTextTest, TextDoesntClip) {
+TEST_F(RenderTextTest, TextDoesntClip) {
const char* kTestStrings[] = {
" ",
// TODO(dschuyler): Underscores draw outside GetStringSize;
@@ -4532,7 +4374,7 @@ TEST_P(RenderTextTest, TextDoesntClip) {
// Ensure that the text will clip to the display rect. Draws to a canvas and
// checks whether any pixel beyond the bounding rectangle is colored.
-TEST_P(RenderTextTest, TextDoesClip) {
+TEST_F(RenderTextTest, TextDoesClip) {
const char* kTestStrings[] = {"TEST", "W", "WWWW", "gAXAXWWWW"};
const Size kCanvasSize(300, 50);
const int kTestSize = 10;
@@ -4585,41 +4427,8 @@ TEST_P(RenderTextTest, TextDoesClip) {
}
}
-#if defined(OS_MACOSX)
-TEST_P(RenderTextMacTest, Mac_ElidedText) {
- RenderTextMac* render_text = GetRenderTextMac();
- base::string16 text(UTF8ToUTF16("This is an example."));
- render_text->SetText(text);
- Size string_size = render_text->GetStringSize();
- render_text->SetDisplayRect(Rect(string_size));
- test_api()->EnsureLayout();
- // NOTE: Character and glyph counts are only comparable for simple text.
- EXPECT_EQ(text.size(),
- static_cast<size_t>(CTLineGetGlyphCount(GetCoreTextLine())));
-
- render_text->SetElideBehavior(ELIDE_TAIL);
- string_size.set_width(string_size.width() / 2);
- render_text->SetDisplayRect(Rect(string_size));
- test_api()->EnsureLayout();
- CFIndex glyph_count = CTLineGetGlyphCount(GetCoreTextLine());
- EXPECT_GT(text.size(), static_cast<size_t>(glyph_count));
- EXPECT_NE(0, glyph_count);
-}
-
-TEST_P(RenderTextMacTest, LinesInvalidationOnElideBehaviorChange) {
- RenderTextMac* render_text = GetRenderTextMac();
- render_text->SetText(UTF8ToUTF16("This is an example"));
- test_api()->EnsureLayout();
- EXPECT_TRUE(GetCoreTextLine());
-
- // Lines are cleared when elide behavior changes.
- render_text->SetElideBehavior(gfx::ELIDE_TAIL);
- EXPECT_FALSE(GetCoreTextLine());
-}
-#endif // defined(OS_MACOSX)
-
// Ensure color changes are picked up by the RenderText implementation.
-TEST_P(RenderTextTest, ColorChange) {
+TEST_F(RenderTextTest, ColorChange) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("x"));
DrawVisualText();
@@ -4638,7 +4447,7 @@ TEST_P(RenderTextTest, ColorChange) {
}
// Ensure style information propagates to the typeface on the text renderer.
-TEST_P(RenderTextTest, StylePropagated) {
+TEST_F(RenderTextTest, StylePropagated) {
RenderText* render_text = GetRenderText();
// Default-constructed fonts on Mac are system fonts. These can have all kinds
// of weird weights and style, which are preserved by PlatformFontMac, but do
@@ -4669,7 +4478,7 @@ TEST_P(RenderTextTest, StylePropagated) {
}
// Ensure the painter adheres to RenderText::subpixel_rendering_suppressed().
-TEST_P(RenderTextTest, SubpixelRenderingSuppressed) {
+TEST_F(RenderTextTest, SubpixelRenderingSuppressed) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("x"));
@@ -4702,9 +4511,50 @@ TEST_P(RenderTextTest, SubpixelRenderingSuppressed) {
EXPECT_FALSE(GetRendererPaint().isLCDRenderText());
}
+// Ensure the SkFont Edging is computed accurately.
+TEST_F(RenderTextTest, SkFontEdging) {
+ const auto edging = [this]() {
+ return GetRendererPaint().ToSkFont().getEdging();
+ };
+
+ FontRenderParams params;
+ EXPECT_TRUE(params.antialiasing);
+ EXPECT_EQ(params.subpixel_rendering,
+ FontRenderParams::SUBPIXEL_RENDERING_NONE);
+
+ // aa: true, subpixel: false, subpixel_suppressed: false -> kAntiAlias
+ renderer()->SetFontRenderParams(params,
+ false /*subpixel_rendering_suppressed*/);
+ EXPECT_EQ(edging(), SkFont::Edging::kAntiAlias);
+
+ // aa: false, subpixel: false, subpixel_suppressed: false -> kAlias
+ params.antialiasing = false;
+ renderer()->SetFontRenderParams(params,
+ false /*subpixel_rendering_suppressed*/);
+ EXPECT_EQ(edging(), SkFont::Edging::kAlias);
+
+ // aa: true, subpixel: true, subpixel_suppressed: false -> kSubpixelAntiAlias
+ params.antialiasing = true;
+ params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
+ renderer()->SetFontRenderParams(params,
+ false /*subpixel_rendering_suppressed*/);
+ EXPECT_EQ(edging(), SkFont::Edging::kSubpixelAntiAlias);
+
+ // aa: true, subpixel: true, subpixel_suppressed: true -> kAntiAlias
+ renderer()->SetFontRenderParams(params,
+ true /*subpixel_rendering_suppressed*/);
+ EXPECT_EQ(edging(), SkFont::Edging::kAntiAlias);
+
+ // aa: false, subpixel: true, subpixel_suppressed: false -> kAlias
+ params.antialiasing = false;
+ renderer()->SetFontRenderParams(params,
+ false /*subpixel_rendering_suppressed*/);
+ EXPECT_EQ(edging(), SkFont::Edging::kAlias);
+}
+
// Verify GetWordLookupDataAtPoint returns the correct baseline point and
// decorated word for an LTR string.
-TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_LTR) {
+TEST_F(RenderTextTest, GetWordLookupDataAtPoint_LTR) {
const base::string16 ltr = UTF8ToUTF16(" ab c ");
const int kWordOneStartIndex = 2;
const int kWordTwoStartIndex = 6;
@@ -4784,7 +4634,7 @@ TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_LTR) {
// Verify GetWordLookupDataAtPoint returns the correct baseline point and
// decorated word for an RTL string.
-TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_RTL) {
+TEST_F(RenderTextTest, GetWordLookupDataAtPoint_RTL) {
const base::string16 rtl = UTF8ToUTF16(" \u0634\u0632 \u0634");
const int kWordOneStartIndex = 1;
const int kWordTwoStartIndex = 5;
@@ -4862,7 +4712,7 @@ TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_RTL) {
}
// Test that GetWordLookupDataAtPoint behaves correctly for multiline text.
-TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_Multiline) {
+TEST_F(RenderTextTest, GetWordLookupDataAtPoint_Multiline) {
const base::string16 text = UTF8ToUTF16("a b\n..\ncd.");
const size_t kWordOneIndex = 0; // Index of character 'a'.
const size_t kWordTwoIndex = 2; // Index of character 'b'.
@@ -4941,7 +4791,7 @@ TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_Multiline) {
}
// Verify the boolean return value of GetWordLookupDataAtPoint.
-TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_Return) {
+TEST_F(RenderTextTest, GetWordLookupDataAtPoint_Return) {
RenderText* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("..."));
@@ -4970,7 +4820,7 @@ TEST_P(RenderTextHarfBuzzTest, GetWordLookupDataAtPoint_Return) {
}
// Test that GetLookupDataAtPoint behaves correctly when the range spans lines.
-TEST_P(RenderTextHarfBuzzTest, GetLookupDataAtRange_Multiline) {
+TEST_F(RenderTextTest, GetLookupDataAtRange_Multiline) {
const base::string16 text = UTF8ToUTF16("a\nb");
constexpr Range kWordOneRange = Range(0, 1); // Range of character 'a'.
constexpr Range kWordTwoRange = Range(2, 3); // Range of character 'b'.
@@ -5040,7 +4890,7 @@ TEST_P(RenderTextHarfBuzzTest, GetLookupDataAtRange_Multiline) {
// Tests text selection made at end points of individual lines of multiline
// text.
-TEST_P(RenderTextHarfBuzzTest, LineEndSelections) {
+TEST_F(RenderTextTest, LineEndSelections) {
const char* const ltr = "abc\n\ndef";
const char* const rtl = "\u05d0\u05d1\u05d2\n\n\u05d3\u05d4\u05d5";
const int left_x = -100;
@@ -5083,7 +4933,7 @@ TEST_P(RenderTextHarfBuzzTest, LineEndSelections) {
}
// Tests that GetSubstringBounds returns the correct bounds for multiline text.
-TEST_P(RenderTextHarfBuzzTest, GetSubstringBoundsMultiline) {
+TEST_F(RenderTextTest, GetSubstringBoundsMultiline) {
RenderText* render_text = GetRenderText();
render_text->SetMultiline(true);
render_text->SetDisplayRect(Rect(200, 1000));
@@ -5116,7 +4966,7 @@ TEST_P(RenderTextHarfBuzzTest, GetSubstringBoundsMultiline) {
// Tests that RenderText doesn't crash even if it's passed an invalid font. Test
// for crbug.com/668058.
-TEST_P(RenderTextTest, InvalidFont) {
+TEST_F(RenderTextTest, InvalidFont) {
const std::string font_name = "invalid_font";
const int kFontSize = 13;
RenderText* render_text = GetRenderText();
@@ -5126,7 +4976,7 @@ TEST_P(RenderTextTest, InvalidFont) {
DrawVisualText();
}
-TEST_P(RenderTextTest, ExpandToBeVerticallySymmetric) {
+TEST_F(RenderTextTest, ExpandToBeVerticallySymmetric) {
Rect test_display_rect(0, 0, 400, 100);
// Basic case.
@@ -5156,8 +5006,8 @@ TEST_P(RenderTextTest, ExpandToBeVerticallySymmetric) {
Rect(20, 20, 400, 40), test_display_rect));
}
-TEST_P(RenderTextHarfBuzzTest, LinesInvalidationOnElideBehaviorChange) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, LinesInvalidationOnElideBehaviorChange) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(UTF8ToUTF16("This is an example"));
test_api()->EnsureLayout();
EXPECT_FALSE(test_api()->lines().empty());
@@ -5172,7 +5022,7 @@ TEST_P(RenderTextHarfBuzzTest, LinesInvalidationOnElideBehaviorChange) {
// display rectangle height changes, or when the minimum line height changes.
// The difference between the two is the selection rectangle, which should match
// the line height.
-TEST_P(RenderTextHarfBuzzTest, BaselineWithLineHeight) {
+TEST_F(RenderTextTest, BaselineWithLineHeight) {
RenderText* render_text = GetRenderText();
const int font_height = render_text->font_list().GetHeight();
render_text->SetDisplayRect(Rect(500, font_height));
@@ -5262,7 +5112,7 @@ TEST_P(RenderTextHarfBuzzTest, BaselineWithLineHeight) {
EXPECT_EQ(gfx::Vector2d(), current_selection_bounds.OffsetFromOrigin());
}
-TEST_P(RenderTextHarfBuzzTest, TeluguGraphemeBoundaries) {
+TEST_F(RenderTextTest, TeluguGraphemeBoundaries) {
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(50, 1000));
// This is first syllable of the Telugu word for "New" in Chrome. It's a
@@ -5307,7 +5157,7 @@ TEST_P(RenderTextHarfBuzzTest, TeluguGraphemeBoundaries) {
// Test cursor bounds for Emoji flags (unicode regional indicators) when the
// flag does not merge into a single glyph.
-TEST_P(RenderTextHarfBuzzTest, MissingFlagEmoji) {
+TEST_F(RenderTextTest, MissingFlagEmoji) {
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(1000, 1000));
@@ -5371,9 +5221,9 @@ TEST_P(RenderTextHarfBuzzTest, MissingFlagEmoji) {
}
// Ensures that glyph spacing is correctly applied to obscured texts.
-TEST_P(RenderTextHarfBuzzTest, GlyphSpacing) {
+TEST_F(RenderTextTest, GlyphSpacing) {
const base::string16 seuss = UTF8ToUTF16("hop on pop");
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+ RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(seuss);
render_text->SetObscured(true);
test_api()->EnsureLayout();
@@ -5394,8 +5244,8 @@ TEST_P(RenderTextHarfBuzzTest, GlyphSpacing) {
}
// Ensure font size overrides propagate through to text runs.
-TEST_P(RenderTextHarfBuzzTest, FontSizeOverride) {
- RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
+TEST_F(RenderTextTest, FontSizeOverride) {
+ RenderTextHarfBuzz* render_text = GetRenderText();
const int default_font_size = render_text->font_list().GetFontSize();
const int test_font_size_override = default_font_size + 5;
render_text->SetText(UTF8ToUTF16("0123456789"));
@@ -5414,28 +5264,4 @@ TEST_P(RenderTextHarfBuzzTest, FontSizeOverride) {
run_list->runs()[2].get()->font_params.font_size);
}
-// Prefix for test instantiations intentionally left blank since each test
-// fixture class has a single parameterization.
-#if defined(OS_MACOSX)
-INSTANTIATE_TEST_CASE_P(,
- RenderTextTest,
- ::testing::Values(RENDER_TEXT_HARFBUZZ,
- RENDER_TEXT_MAC),
- PrintRenderTextBackend());
-INSTANTIATE_TEST_CASE_P(,
- RenderTextMacTest,
- ::testing::Values(RENDER_TEXT_MAC),
- PrintRenderTextBackend());
-#else
-INSTANTIATE_TEST_CASE_P(,
- RenderTextTest,
- ::testing::Values(RENDER_TEXT_HARFBUZZ),
- PrintRenderTextBackend());
-#endif
-
-INSTANTIATE_TEST_CASE_P(,
- RenderTextHarfBuzzTest,
- ::testing::Values(RENDER_TEXT_HARFBUZZ),
- PrintRenderTextBackend());
-
} // namespace gfx
diff --git a/chromium/ui/gfx/selection_model.cc b/chromium/ui/gfx/selection_model.cc
index 5352d8653cd..813bf2110ac 100644
--- a/chromium/ui/gfx/selection_model.cc
+++ b/chromium/ui/gfx/selection_model.cc
@@ -4,6 +4,8 @@
#include "ui/gfx/selection_model.h"
+#include <ostream>
+
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
@@ -37,4 +39,9 @@ std::string SelectionModel::ToString() const {
return str + (backward ? ",BACKWARD}" : ",FORWARD}");
}
+std::ostream& operator<<(std::ostream& out, const SelectionModel& model) {
+ out << model.ToString();
+ return out;
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/selection_model.h b/chromium/ui/gfx/selection_model.h
index 73bf113da5c..134a5f377a0 100644
--- a/chromium/ui/gfx/selection_model.h
+++ b/chromium/ui/gfx/selection_model.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <iosfwd>
#include <string>
#include "ui/gfx/gfx_export.h"
@@ -107,6 +108,9 @@ class GFX_EXPORT SelectionModel {
LogicalCursorDirection caret_affinity_;
};
+GFX_EXPORT std::ostream& operator<<(std::ostream& out,
+ const SelectionModel& model);
+
} // namespace gfx
#endif // UI_GFX_SELECTION_MODEL_H_
diff --git a/chromium/ui/gfx/skia_font_delegate.cc b/chromium/ui/gfx/skia_font_delegate.cc
new file mode 100644
index 00000000000..f7c24c5f5b8
--- /dev/null
+++ b/chromium/ui/gfx/skia_font_delegate.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/skia_font_delegate.h"
+
+namespace {
+
+gfx::SkiaFontDelegate* g_skia_font_delegate = 0;
+
+} // namespace
+
+namespace gfx {
+
+void SkiaFontDelegate::SetInstance(SkiaFontDelegate* instance) {
+ g_skia_font_delegate = instance;
+}
+
+const SkiaFontDelegate* SkiaFontDelegate::instance() {
+ return g_skia_font_delegate;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/linux_font_delegate.h b/chromium/ui/gfx/skia_font_delegate.h
index 12eaf584b5f..05636e98fab 100644
--- a/chromium/ui/gfx/linux_font_delegate.h
+++ b/chromium/ui/gfx/skia_font_delegate.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_LINUX_FONT_DELEGATE_H_
-#define UI_GFX_LINUX_FONT_DELEGATE_H_
+#ifndef UI_GFX_SKIA_FONT_DELEGATE_H_
+#define UI_GFX_SKIA_FONT_DELEGATE_H_
#include <memory>
#include <string>
@@ -14,21 +14,21 @@
namespace gfx {
// Allows a Linux platform-specific overriding of font preferences.
-class GFX_EXPORT LinuxFontDelegate {
+class GFX_EXPORT SkiaFontDelegate {
public:
- virtual ~LinuxFontDelegate() {}
+ virtual ~SkiaFontDelegate() {}
// Sets the dynamically loaded singleton that provides font preferences.
// This pointer is not owned, and if this method is called a second time,
// the first instance is not deleted.
- static void SetInstance(LinuxFontDelegate* instance);
+ static void SetInstance(SkiaFontDelegate* instance);
- // Returns a LinuxFontDelegate instance for the toolkit used in
+ // Returns a SkiaFontDelegate instance for the toolkit used in
// the user's desktop environment.
//
// Can return NULL, in case no toolkit has been set. (For example, if we're
// running with the "--ash" flag.)
- static const LinuxFontDelegate* instance();
+ static const SkiaFontDelegate* instance();
// Returns the default font rendering settings.
virtual FontRenderParams GetDefaultFontRenderParams() const = 0;
@@ -45,4 +45,4 @@ class GFX_EXPORT LinuxFontDelegate {
} // namespace gfx
-#endif // UI_GFX_LINUX_FONT_DELEGATE_H_
+#endif // UI_GFX_SKIA_FONT_DELEGATE_H_
diff --git a/chromium/ui/gfx/skia_vector_animation.cc b/chromium/ui/gfx/skia_vector_animation.cc
index 8e16dc9dcc6..b2e0f7f9bdf 100644
--- a/chromium/ui/gfx/skia_vector_animation.cc
+++ b/chromium/ui/gfx/skia_vector_animation.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/skia_vector_animation.h"
#include "base/trace_event/trace_event.h"
+#include "cc/paint/skottie_wrapper.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImage.h"
@@ -13,7 +14,6 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/skia_vector_animation_observer.h"
-#include "ui/gfx/skottie_wrapper.h"
namespace gfx {
@@ -69,7 +69,8 @@ double SkiaVectorAnimation::TimerControl::GetNormalizedEndOffset() const {
return end_offset_.InMillisecondsF() * progress_per_millisecond_;
}
-SkiaVectorAnimation::SkiaVectorAnimation(scoped_refptr<SkottieWrapper> skottie)
+SkiaVectorAnimation::SkiaVectorAnimation(
+ scoped_refptr<cc::SkottieWrapper> skottie)
: skottie_(skottie) {}
SkiaVectorAnimation::~SkiaVectorAnimation() {}
@@ -203,22 +204,9 @@ void SkiaVectorAnimation::Paint(gfx::Canvas* canvas,
void SkiaVectorAnimation::PaintFrame(gfx::Canvas* canvas,
float t,
const gfx::Size& size) {
- TRACE_EVENT0("ui", "SkiaVectorAnimation Paint");
DCHECK_GE(t, 0.f);
DCHECK_LE(t, 1.f);
-
- float scale = canvas->UndoDeviceScaleFactor();
- gfx::Size pixel_size = gfx::ScaleToRoundedSize(size, scale);
-
- SkBitmap bitmap;
- bitmap.allocN32Pixels(std::round(pixel_size.width()),
- std::round(pixel_size.height()), false);
- SkCanvas skcanvas(bitmap);
- skcanvas.clear(SK_ColorTRANSPARENT);
-
- skottie_->Draw(&skcanvas, t, pixel_size);
-
- canvas->DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(bitmap), 0, 0);
+ canvas->DrawSkottie(skottie(), gfx::Rect(size), t);
}
void SkiaVectorAnimation::InitTimer(const base::TimeTicks& timestamp) {
diff --git a/chromium/ui/gfx/skia_vector_animation.h b/chromium/ui/gfx/skia_vector_animation.h
index 14081bfd3e0..9a0f6cc1239 100644
--- a/chromium/ui/gfx/skia_vector_animation.h
+++ b/chromium/ui/gfx/skia_vector_animation.h
@@ -16,11 +16,14 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gfx_export.h"
+namespace cc {
+class SkottieWrapper;
+} // namespace cc
+
namespace gfx {
class Canvas;
class SkiaVectorAnimationTest;
class SkiaVectorAnimationObserver;
-class SkottieWrapper;
// This class is a wrapper over the Skia object for lottie vector graphic
// animations. It has its own timeline manager for the animation controls. The
@@ -81,7 +84,7 @@ class GFX_EXPORT SkiaVectorAnimation {
kLoop // Same as LINEAR, except the animation repeats after it ends.
};
- explicit SkiaVectorAnimation(scoped_refptr<SkottieWrapper> skottie);
+ explicit SkiaVectorAnimation(scoped_refptr<cc::SkottieWrapper> skottie);
~SkiaVectorAnimation();
void SetAnimationObserver(SkiaVectorAnimationObserver* Observer);
@@ -138,7 +141,7 @@ class GFX_EXPORT SkiaVectorAnimation {
void PaintFrame(gfx::Canvas* canvas, float t, const gfx::Size& size);
// Returns the skottie object that contins the animation data.
- scoped_refptr<SkottieWrapper> skottie() const { return skottie_; }
+ scoped_refptr<cc::SkottieWrapper> skottie() const { return skottie_; }
private:
friend class SkiaVectorAnimationTest;
@@ -231,7 +234,7 @@ class GFX_EXPORT SkiaVectorAnimation {
SkiaVectorAnimationObserver* observer_ = nullptr;
- scoped_refptr<SkottieWrapper> skottie_;
+ scoped_refptr<cc::SkottieWrapper> skottie_;
DISALLOW_COPY_AND_ASSIGN(SkiaVectorAnimation);
};
diff --git a/chromium/ui/gfx/skia_vector_animation_unittest.cc b/chromium/ui/gfx/skia_vector_animation_unittest.cc
index e7394e2ae7d..75b6a671f80 100644
--- a/chromium/ui/gfx/skia_vector_animation_unittest.cc
+++ b/chromium/ui/gfx/skia_vector_animation_unittest.cc
@@ -10,12 +10,12 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/simple_test_tick_clock.h"
+#include "cc/paint/skottie_wrapper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkStream.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/skia_vector_animation_observer.h"
-#include "ui/gfx/skottie_wrapper.h"
namespace gfx {
namespace {
@@ -102,7 +102,7 @@ class SkiaVectorAnimationTest : public testing::Test {
void SetUp() override {
canvas_.reset(new gfx::Canvas(gfx::Size(kAnimationWidth, kAnimationHeight),
1.f, false));
- skottie_ = base::MakeRefCounted<SkottieWrapper>(
+ skottie_ = base::MakeRefCounted<cc::SkottieWrapper>(
std::make_unique<SkMemoryStream>(kData, std::strlen(kData)));
animation_ = std::make_unique<SkiaVectorAnimation>(skottie_);
}
@@ -190,7 +190,7 @@ class SkiaVectorAnimationTest : public testing::Test {
protected:
std::unique_ptr<SkiaVectorAnimation> animation_;
- scoped_refptr<SkottieWrapper> skottie_;
+ scoped_refptr<cc::SkottieWrapper> skottie_;
private:
std::unique_ptr<gfx::Canvas> canvas_;
@@ -202,7 +202,7 @@ class SkiaVectorAnimationTest : public testing::Test {
TEST_F(SkiaVectorAnimationTest, InitializationAndLoadingData) {
auto bytes = base::MakeRefCounted<base::RefCountedBytes>(
std::vector<unsigned char>(kData, kData + std::strlen(kData)));
- skottie_ = base::MakeRefCounted<SkottieWrapper>(bytes.get());
+ skottie_ = base::MakeRefCounted<cc::SkottieWrapper>(bytes.get());
animation_ = std::make_unique<SkiaVectorAnimation>(skottie_);
EXPECT_FLOAT_EQ(animation_->GetOriginalSize().width(), kAnimationWidth);
EXPECT_FLOAT_EQ(animation_->GetOriginalSize().height(), kAnimationHeight);
@@ -210,7 +210,7 @@ TEST_F(SkiaVectorAnimationTest, InitializationAndLoadingData) {
kAnimationDuration);
EXPECT_TRUE(IsStopped());
- skottie_ = base::MakeRefCounted<SkottieWrapper>(
+ skottie_ = base::MakeRefCounted<cc::SkottieWrapper>(
std::make_unique<SkMemoryStream>(kData, std::strlen(kData)));
animation_ = std::make_unique<SkiaVectorAnimation>(skottie_);
EXPECT_FLOAT_EQ(animation_->GetOriginalSize().width(), kAnimationWidth);
diff --git a/chromium/ui/gfx/skottie_wrapper.cc b/chromium/ui/gfx/skottie_wrapper.cc
deleted file mode 100644
index 1cba085fb46..00000000000
--- a/chromium/ui/gfx/skottie_wrapper.cc
+++ /dev/null
@@ -1,36 +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.
-
-#include "ui/gfx/skottie_wrapper.h"
-
-#include "base/memory/ref_counted_memory.h"
-#include "base/trace_event/trace_event.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "third_party/skia/include/core/SkStream.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace gfx {
-
-SkottieWrapper::SkottieWrapper(
- const scoped_refptr<base::RefCountedMemory>& data_stream) {
- TRACE_EVENT0("ui", "SkottieWrapper Parse");
- SkMemoryStream sk_stream(data_stream->front(), data_stream->size());
- animation_ = skottie::Animation::Make(&sk_stream);
-}
-
-SkottieWrapper::SkottieWrapper(std::unique_ptr<SkMemoryStream> stream)
- : animation_(skottie::Animation::Make(stream.get())) {}
-
-SkottieWrapper::~SkottieWrapper() {}
-
-void SkottieWrapper::Draw(SkCanvas* canvas, float t, const gfx::Size& size) {
- SkRect dst = SkRect::MakeXYWH(0, 0, size.width(), size.height());
- {
- base::AutoLock lock(lock_);
- animation_->seek(t);
- animation_->render(canvas, &dst);
- }
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/skottie_wrapper.h b/chromium/ui/gfx/skottie_wrapper.h
deleted file mode 100644
index 006d0cd26bf..00000000000
--- a/chromium/ui/gfx/skottie_wrapper.h
+++ /dev/null
@@ -1,55 +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_GFX_SKOTTIE_WRAPPER_H_
-#define UI_GFX_SKOTTIE_WRAPPER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "third_party/skia/modules/skottie/include/Skottie.h"
-#include "ui/gfx/gfx_export.h"
-
-class SkCanvas;
-class SkMemoryStream;
-
-namespace base {
-class RefCountedMemory;
-} // namespace base
-
-namespace gfx {
-class Size;
-
-// A wrapper over Skia's Skottie object that can be shared by multiple
-// SkiaVectorAnimation objects. This class is thread safe when performing a draw
-// on an SkCanvas.
-class GFX_EXPORT SkottieWrapper
- : public base::RefCountedThreadSafe<SkottieWrapper> {
- public:
- explicit SkottieWrapper(
- const scoped_refptr<base::RefCountedMemory>& data_stream);
- explicit SkottieWrapper(std::unique_ptr<SkMemoryStream> stream);
-
- // A thread safe call that will draw an image of size |size| for the frame at
- // normalized time instant |t| onto the |canvas|.
- void Draw(SkCanvas* canvas, float t, const Size& size);
-
- float duration() const { return animation_->duration(); }
- SkSize size() const { return animation_->size(); }
-
- private:
- friend class base::RefCountedThreadSafe<SkottieWrapper>;
- ~SkottieWrapper();
-
- base::Lock lock_;
- sk_sp<skottie::Animation> animation_;
-
- DISALLOW_COPY_AND_ASSIGN(SkottieWrapper);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_SKOTTIE_WRAPPER_H_
diff --git a/chromium/ui/gfx/switches.cc b/chromium/ui/gfx/switches.cc
index b0c3d1daf7a..606cbb42070 100644
--- a/chromium/ui/gfx/switches.cc
+++ b/chromium/ui/gfx/switches.cc
@@ -35,12 +35,6 @@ const base::Feature kLeftToRightUrls{"LeftToRightUrls",
// ImageSkiaReps. This may reduce load on the UI thread by moving rasterization
// of drawables away from this thread.
const base::Feature kUsePaintRecordForImageSkia{
- "UsePaintRecordForImageSkia",
-#if defined(OS_CHROMEOS)
- base::FEATURE_ENABLED_BY_DEFAULT
-#else
- base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
+ "UsePaintRecordForImageSkia", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
diff --git a/chromium/ui/gfx/text_elider_unittest.cc b/chromium/ui/gfx/text_elider_unittest.cc
index 1ceab0aedc3..43852b6afe8 100644
--- a/chromium/ui/gfx/text_elider_unittest.cc
+++ b/chromium/ui/gfx/text_elider_unittest.cc
@@ -58,15 +58,7 @@ struct TestData {
} // namespace
-// TODO(crbug.com/546240): This test fails on iOS because iOS version of
-// GetStringWidthF that calls [NSString sizeWithFont] returns the rounded string
-// width.
-#if defined(OS_IOS)
-#define MAYBE_ElideEmail DISABLED_ElideEmail
-#else
-#define MAYBE_ElideEmail ElideEmail
-#endif
-TEST(TextEliderTest, MAYBE_ElideEmail) {
+TEST(TextEliderTest, ElideEmail) {
const std::string kEllipsisStr(kEllipsis);
// Test emails and their expected elided forms (from which the available
@@ -147,15 +139,7 @@ TEST(TextEliderTest, ElideEmailMoreSpace) {
}
}
-// TODO(crbug.com/546240): This test fails on iOS because iOS version of
-// GetStringWidthF that calls [NSString sizeWithFont] returns the rounded string
-// width.
-#if defined(OS_IOS)
-#define MAYBE_TestFilenameEliding DISABLED_TestFilenameEliding
-#else
-#define MAYBE_TestFilenameEliding TestFilenameEliding
-#endif
-TEST(TextEliderTest, MAYBE_TestFilenameEliding) {
+TEST(TextEliderTest, TestFilenameEliding) {
const std::string kEllipsisStr(kEllipsis);
const base::FilePath::StringType kPathSeparator =
base::FilePath::StringType().append(1, base::FilePath::kSeparators[0]);
diff --git a/chromium/ui/gfx/text_utils_ios.mm b/chromium/ui/gfx/text_utils_ios.mm
index 0fdf2ae51ea..0794043995c 100644
--- a/chromium/ui/gfx/text_utils_ios.mm
+++ b/chromium/ui/gfx/text_utils_ios.mm
@@ -10,7 +10,6 @@
#include "base/strings/sys_string_conversions.h"
#include "ui/gfx/font_list.h"
-#include "ui/gfx/ios/NSString+CrStringDrawing.h"
namespace gfx {
@@ -25,7 +24,8 @@ float GetStringWidthF(const base::string16& text,
Typesetter typesetter) {
NSString* ns_text = base::SysUTF16ToNSString(text);
NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont();
- return [ns_text cr_sizeWithFont:native_font].width;
+ NSDictionary* attributes = @{NSFontAttributeName : native_font};
+ return [ns_text sizeWithAttributes:attributes].width;
}
} // namespace gfx
diff --git a/chromium/ui/gfx/text_utils_unittest.cc b/chromium/ui/gfx/text_utils_unittest.cc
index 32841c12eca..7cf42c827ee 100644
--- a/chromium/ui/gfx/text_utils_unittest.cc
+++ b/chromium/ui/gfx/text_utils_unittest.cc
@@ -64,13 +64,7 @@ TEST(TextUtilsTest, RemoveAcceleratorChar) {
}
}
-// Disabled on Ozone since there are no fonts: crbug.com/320050
-#if defined(USE_OZONE)
-#define MAYBE_GetStringWidth DISABLED_GetStringWidth
-#else
-#define MAYBE_GetStringWidth GetStringWidth
-#endif
-TEST(TextUtilsTest, MAYBE_GetStringWidth) {
+TEST(TextUtilsTest, GetStringWidth) {
FontList font_list;
EXPECT_EQ(GetStringWidth(base::string16(), font_list), 0);
EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("a"), font_list),
diff --git a/chromium/ui/gfx/transform_unittest.cc b/chromium/ui/gfx/transform_unittest.cc
index 50eabc07dbf..6df8868b387 100644
--- a/chromium/ui/gfx/transform_unittest.cc
+++ b/chromium/ui/gfx/transform_unittest.cc
@@ -754,13 +754,7 @@ TEST(XFormTest, CanBlend180DegreeRotation) {
}
}
-#if defined(_WIN64)
-// https://crbug.com/406574
-#define MAYBE_BlendScale DISABLED_BlendScale
-#else
-#define MAYBE_BlendScale BlendScale
-#endif
-TEST(XFormTest, MAYBE_BlendScale) {
+TEST(XFormTest, BlendScale) {
Transform from;
for (int i = -5; i < 15; ++i) {
Transform to;
@@ -800,13 +794,7 @@ TEST(XFormTest, ExtrapolateSkew) {
}
}
-#if defined(_WIN64)
-// http://crbug.com/406574
-#define MAYBE_BlendPerspective DISABLED_BlendPerspective
-#else
-#define MAYBE_BlendPerspective BlendPerspective
-#endif
-TEST(XFormTest, MAYBE_BlendPerspective) {
+TEST(XFormTest, BlendPerspective) {
Transform from;
from.ApplyPerspectiveDepth(200);
for (int i = -1; i < 3; ++i) {
@@ -1016,13 +1004,7 @@ TEST(XFormTest, VerifyBlendForSkew) {
EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-#if defined(_WIN64)
-// http://crbug.com/406574
-#define MAYBE_VerifyBlendForRotationAboutX DISABLED_VerifyBlendForRotationAboutX
-#else
-#define MAYBE_VerifyBlendForRotationAboutX VerifyBlendForRotationAboutX
-#endif
-TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
+TEST(XFormTest, VerifyBlendForRotationAboutX) {
// Even though.Blending uses quaternions, axis-aligned rotations should.
// Blend the same with quaternions or Euler angles. So we can test
// rotation.Blending by comparing against manually specified matrices from
@@ -1084,13 +1066,7 @@ TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutX) {
EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-#if defined(_WIN64)
-// http://crbug.com/406574
-#define MAYBE_VerifyBlendForRotationAboutY DISABLED_VerifyBlendForRotationAboutY
-#else
-#define MAYBE_VerifyBlendForRotationAboutY VerifyBlendForRotationAboutY
-#endif
-TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
+TEST(XFormTest, VerifyBlendForRotationAboutY) {
Transform from;
from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
@@ -1147,13 +1123,7 @@ TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutY) {
EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-#if defined(_WIN64)
-// http://crbug.com/406574
-#define MAYBE_VerifyBlendForRotationAboutZ DISABLED_VerifyBlendForRotationAboutZ
-#else
-#define MAYBE_VerifyBlendForRotationAboutZ VerifyBlendForRotationAboutZ
-#endif
-TEST(XFormTest, MAYBE_VerifyBlendForRotationAboutZ) {
+TEST(XFormTest, VerifyBlendForRotationAboutZ) {
Transform from;
from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
diff --git a/chromium/ui/gfx/win/singleton_hwnd.cc b/chromium/ui/gfx/win/singleton_hwnd.cc
index 7d3aa6ef7b4..28e567bbafc 100644
--- a/chromium/ui/gfx/win/singleton_hwnd.cc
+++ b/chromium/ui/gfx/win/singleton_hwnd.cc
@@ -21,13 +21,23 @@ BOOL SingletonHwnd::ProcessWindowMessage(HWND window,
LPARAM lparam,
LRESULT& result,
DWORD msg_map_id) {
+ if (!base::MessageLoopCurrentForUI::IsSet()) {
+ // If there is no MessageLoop and SingletonHwnd is receiving messages, this
+ // means it is receiving messages via an external message pump such as COM
+ // uninitialization.
+ //
+ // It is unsafe to forward these messages as observers may depend on the
+ // existence of a MessageLoop to proceed.
+ return false;
+ }
+
for (SingletonHwndObserver& observer : observer_list_)
observer.OnWndProc(window, message, wparam, lparam);
return false;
}
SingletonHwnd::SingletonHwnd() {
- if (!base::MessageLoopForUI::IsCurrent()) {
+ if (!base::MessageLoopCurrentForUI::IsSet()) {
// Creating this window in (e.g.) a renderer inhibits shutdown on
// Windows. See http://crbug.com/230122 and http://crbug.com/236039.
return;
diff --git a/chromium/ui/gl/BUILD.gn b/chromium/ui/gl/BUILD.gn
index 67cedb57328..a3f8e6b24ca 100644
--- a/chromium/ui/gl/BUILD.gn
+++ b/chromium/ui/gl/BUILD.gn
@@ -14,7 +14,9 @@ import("//testing/test.gni")
declare_args() {
enable_swiftshader = (is_win || is_linux || (is_mac && use_egl) ||
is_chromeos || is_fuchsia) &&
- (target_cpu == "x86" || target_cpu == "x64")
+ (target_cpu == "x86" || target_cpu == "x64" ||
+ target_cpu == "arm64" || target_cpu == "mipsel" ||
+ target_cpu == "mips64el")
}
use_glx = use_x11 || ozone_platform_x11
@@ -51,8 +53,8 @@ jumbo_component("gl") {
output_name = "gl_wrapper" # Avoid colliding with OS X"s libGL.dylib.
sources = [
- "android/android_surface_composer_compat.cc",
- "android/android_surface_composer_compat.h",
+ "android/android_surface_control_compat.cc",
+ "android/android_surface_control_compat.h",
"android/scoped_java_surface.cc",
"android/scoped_java_surface.h",
"android/surface_texture.cc",
diff --git a/chromium/ui/gl/PRESUBMIT.py b/chromium/ui/gl/PRESUBMIT.py
deleted file mode 100644
index 290b06c5d06..00000000000
--- a/chromium/ui/gl/PRESUBMIT.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (c) 2017 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.
-
-"""Presubmit script for //ui/gl.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def PostUploadHook(cl, change, output_api):
- """git cl upload will call this hook after the issue is created/modified.
-
- This hook modifies the CL description in order to run extra GPU
- tests (in particular, the WebGL 2.0 conformance tests) in addition
- to the regular CQ try bots. This test suite is too large to run
- against all Chromium commits, but should be run against changes
- likely to affect these tests.
-
- When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
- ui/gl/PRESUBMIT.py are updated.
- """
- return output_api.EnsureCQIncludeTrybotsAreAdded(
- cl,
- [
- 'luci.chromium.try:linux_optional_gpu_tests_rel',
- 'luci.chromium.try:mac_optional_gpu_tests_rel',
- 'luci.chromium.try:win_optional_gpu_tests_rel',
- 'luci.chromium.try:android_optional_gpu_tests_rel',
- ],
- 'Automatically added optional GPU tests to run on CQ.')
diff --git a/chromium/ui/gl/android/android_surface_composer_compat.cc b/chromium/ui/gl/android/android_surface_composer_compat.cc
deleted file mode 100644
index f34d25cae13..00000000000
--- a/chromium/ui/gl/android/android_surface_composer_compat.cc
+++ /dev/null
@@ -1,253 +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.
-
-#include "ui/gl/android/android_surface_composer_compat.h"
-
-#include "base/android/build_info.h"
-#include "base/memory/ptr_util.h"
-#include "base/no_destructor.h"
-
-#include <dlfcn.h>
-
-extern "C" {
-// ASurfaceComposer
-using pASurfaceComposer_Create = ASurfaceComposer* (*)(ANativeWindow*);
-using pASurfaceComposer_Delete = void (*)(ASurfaceComposer*);
-
-// ASurface
-using pASurfaceComposer_CreateSurface = ASurface* (*)(ASurfaceComposer*,
- int32_t content_type,
- ASurface* parent,
- const char* name);
-using pASurfaceComposer_DeleteSurface = void (*)(ASurface*);
-
-// ASurfaceTransaction
-using pASurfaceComposer_CreateTransaction = ASurfaceTransaction* (*)(void);
-using pASurfaceComposer_DeleteTransaction = void (*)(ASurfaceTransaction*);
-using pASurfaceComposer_TransactionApply = int64_t (*)(ASurfaceTransaction*);
-using pASurfaceComposer_TransactionSetVisibility =
- void (*)(ASurfaceTransaction*, ASurface*, bool show);
-using pASurfaceComposer_TransactionSetPosition = void (*)(ASurfaceTransaction*,
- ASurface*,
- float x,
- float y);
-using pASurfaceComposer_TransactionSetZOrder =
- void (*)(ASurfaceTransaction* transaction, ASurface*, int32_t z);
-using pASurfaceComposer_TransactionSetBuffer =
- void (*)(ASurfaceTransaction* transaction,
- ASurface*,
- AHardwareBuffer*,
- int32_t fence_fd);
-using pASurfaceComposer_TransactionSetSize =
- void (*)(ASurfaceTransaction* transaction,
- ASurface* surface,
- uint32_t width,
- uint32_t height);
-using pASurfaceComposer_TransactionSetCropRect =
- void (*)(ASurfaceTransaction* transaction,
- ASurface* surface,
- int32_t left,
- int32_t top,
- int32_t right,
- int32_t bottom);
-using pASurfaceComposer_TransactionSetOpaque =
- void (*)(ASurfaceTransaction* transaction,
- ASurface* surface,
- uint32_t transform);
-}
-
-namespace gl {
-namespace {
-
-#define LOAD_FUNCTION(lib, func) \
- do { \
- func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
- if (!func##Fn) { \
- supported = false; \
- LOG(ERROR) << "Unable to load function " << #func; \
- } \
- } while (0)
-
-struct SurfaceComposerMethods {
- public:
- static const SurfaceComposerMethods& Get() {
- static const base::NoDestructor<SurfaceComposerMethods> instance;
- return *instance;
- }
-
- SurfaceComposerMethods() {
- void* main_dl_handle = dlopen(nullptr, RTLD_NOW);
- if (!main_dl_handle) {
- LOG(ERROR) << "Couldnt load android so";
- supported = false;
- return;
- }
-
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_Create);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_Delete);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_CreateSurface);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_DeleteSurface);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_CreateTransaction);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_DeleteTransaction);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionApply);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetVisibility);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetPosition);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetZOrder);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetBuffer);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetSize);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetCropRect);
- LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetOpaque);
- }
-
- ~SurfaceComposerMethods() = default;
-
- bool supported = true;
- pASurfaceComposer_Create ASurfaceComposer_CreateFn;
- pASurfaceComposer_Delete ASurfaceComposer_DeleteFn;
- pASurfaceComposer_CreateSurface ASurfaceComposer_CreateSurfaceFn;
- pASurfaceComposer_DeleteSurface ASurfaceComposer_DeleteSurfaceFn;
- pASurfaceComposer_CreateTransaction ASurfaceComposer_CreateTransactionFn;
- pASurfaceComposer_DeleteTransaction ASurfaceComposer_DeleteTransactionFn;
- pASurfaceComposer_TransactionApply ASurfaceComposer_TransactionApplyFn;
- pASurfaceComposer_TransactionSetVisibility
- ASurfaceComposer_TransactionSetVisibilityFn;
- pASurfaceComposer_TransactionSetPosition
- ASurfaceComposer_TransactionSetPositionFn;
- pASurfaceComposer_TransactionSetZOrder
- ASurfaceComposer_TransactionSetZOrderFn;
- pASurfaceComposer_TransactionSetBuffer
- ASurfaceComposer_TransactionSetBufferFn;
- pASurfaceComposer_TransactionSetSize ASurfaceComposer_TransactionSetSizeFn;
- pASurfaceComposer_TransactionSetCropRect
- ASurfaceComposer_TransactionSetCropRectFn;
- pASurfaceComposer_TransactionSetOpaque
- ASurfaceComposer_TransactionSetOpaqueFn;
-};
-};
-
-// static
-bool SurfaceComposer::IsSupported() {
- const int sdk_int = base::android::BuildInfo::GetInstance()->sdk_int();
- if (sdk_int < 29) {
- LOG(ERROR) << "SurfaceControl not supported on sdk: " << sdk_int;
- return false;
- }
- return SurfaceComposerMethods::Get().supported;
-}
-
-// static
-std::unique_ptr<SurfaceComposer> SurfaceComposer::Create(
- ANativeWindow* window) {
- DCHECK(SurfaceComposerMethods::Get().supported);
- auto* a_composer =
- SurfaceComposerMethods::Get().ASurfaceComposer_CreateFn(window);
- if (!a_composer)
- return nullptr;
- return base::WrapUnique(new SurfaceComposer(a_composer));
-}
-
-SurfaceComposer::SurfaceComposer(ASurfaceComposer* composer)
- : composer_(composer) {}
-
-SurfaceComposer::~SurfaceComposer() {
- SurfaceComposerMethods::Get().ASurfaceComposer_DeleteFn(composer_);
-}
-
-SurfaceComposer::Surface::Surface() = default;
-
-SurfaceComposer::Surface::Surface(SurfaceComposer* composer,
- SurfaceContentType content_type,
- const char* name,
- Surface* parent) {
- surface_ = SurfaceComposerMethods::Get().ASurfaceComposer_CreateSurfaceFn(
- composer->composer_, static_cast<int32_t>(content_type),
- parent ? parent->surface() : nullptr, name);
- DCHECK(surface_);
-}
-
-SurfaceComposer::Surface::~Surface() {
- if (surface_)
- SurfaceComposerMethods::Get().ASurfaceComposer_DeleteSurfaceFn(surface_);
-}
-
-SurfaceComposer::Surface::Surface(Surface&& other) {
- surface_ = other.surface_;
- other.surface_ = nullptr;
-}
-
-SurfaceComposer::Surface& SurfaceComposer::Surface::operator=(Surface&& other) {
- if (surface_)
- SurfaceComposerMethods::Get().ASurfaceComposer_DeleteSurfaceFn(surface_);
-
- surface_ = other.surface_;
- other.surface_ = nullptr;
- return *this;
-}
-
-SurfaceComposer::Transaction::Transaction() {
- transaction_ =
- SurfaceComposerMethods::Get().ASurfaceComposer_CreateTransactionFn();
- DCHECK(transaction_);
-}
-
-SurfaceComposer::Transaction::~Transaction() {
- SurfaceComposerMethods::Get().ASurfaceComposer_DeleteTransactionFn(
- transaction_);
-}
-
-void SurfaceComposer::Transaction::SetVisibility(const Surface& surface,
- bool show) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetVisibilityFn(
- transaction_, surface.surface(), show);
-}
-
-void SurfaceComposer::Transaction::SetPosition(const Surface& surface,
- float x,
- float y) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetPositionFn(
- transaction_, surface.surface(), x, y);
-}
-
-void SurfaceComposer::Transaction::SetZOrder(const Surface& surface,
- int32_t z) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetZOrderFn(
- transaction_, surface.surface(), z);
-}
-
-void SurfaceComposer::Transaction::SetBuffer(const Surface& surface,
- AHardwareBuffer* buffer,
- base::ScopedFD fence_fd) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetBufferFn(
- transaction_, surface.surface(), buffer,
- fence_fd.is_valid() ? fence_fd.release() : -1);
-}
-
-void SurfaceComposer::Transaction::SetSize(const Surface& surface,
- uint32_t width,
- uint32_t height) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetSizeFn(
- transaction_, surface.surface(), width, height);
-}
-
-void SurfaceComposer::Transaction::SetCropRect(const Surface& surface,
- int32_t left,
- int32_t top,
- int32_t right,
- int32_t bottom) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetCropRectFn(
- transaction_, surface.surface(), left, top, right, bottom);
-}
-
-void SurfaceComposer::Transaction::SetOpaque(const Surface& surface,
- bool opaque) {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetOpaqueFn(
- transaction_, surface.surface(), opaque);
-}
-
-void SurfaceComposer::Transaction::Apply() {
- SurfaceComposerMethods::Get().ASurfaceComposer_TransactionApplyFn(
- transaction_);
-}
-
-} // namespace gl
diff --git a/chromium/ui/gl/android/android_surface_control_compat.cc b/chromium/ui/gl/android/android_surface_control_compat.cc
new file mode 100644
index 00000000000..ea826e06f3b
--- /dev/null
+++ b/chromium/ui/gl/android/android_surface_control_compat.cc
@@ -0,0 +1,246 @@
+// 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/gl/android/android_surface_control_compat.h"
+
+#include <dlfcn.h>
+
+#include "base/android/build_info.h"
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
+
+extern "C" {
+// ASurface
+using pASurfaceControl_CreateSurfaceForWindow =
+ ASurface* (*)(ANativeWindow* parent, const char* name);
+using pASurfaceControl_CreateSurface = ASurface* (*)(ASurface* parent,
+ const char* name);
+using pASurfaceControl_DeleteSurface = void (*)(ASurface*);
+
+// ASurfaceTransaction
+using pASurfaceControl_CreateTransaction = ASurfaceTransaction* (*)(void);
+using pASurfaceControl_DeleteTransaction = void (*)(ASurfaceTransaction*);
+using pASurfaceControl_TransactionApply = int64_t (*)(ASurfaceTransaction*);
+using pASurfaceControl_TransactionSetCompletedFunc =
+ void (*)(ASurfaceTransaction*, void* ctx, TransactionCompletedFunc);
+using pASurfaceControl_TransactionSetVisibility = void (*)(ASurfaceTransaction*,
+ ASurface*,
+ bool show);
+using pASurfaceControl_TransactionSetZOrder =
+ void (*)(ASurfaceTransaction* transaction, ASurface*, int32_t z);
+using pASurfaceControl_TransactionSetBuffer =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurface*,
+ AHardwareBuffer*,
+ int32_t fence_fd);
+using pASurfaceControl_TransactionSetCropRect =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurface* surface,
+ const ARect& rect);
+using pASurfaceControl_TransactionSetDisplayFrame =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurface* surface,
+ const ARect& rect);
+using pASurfaceControl_TransactionSetBufferOpaque =
+ void (*)(ASurfaceTransaction* transaction, ASurface* surface, bool opaque);
+using pASurfaceControl_TransactionSetDamageRegion =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurface* surface,
+ const ARect rects[],
+ uint32_t count);
+}
+
+namespace gl {
+namespace {
+
+#define LOAD_FUNCTION(lib, func) \
+ do { \
+ func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
+ if (!func##Fn) { \
+ supported = false; \
+ LOG(ERROR) << "Unable to load function " << #func; \
+ } \
+ } while (0)
+
+struct SurfaceControlMethods {
+ public:
+ static const SurfaceControlMethods& Get() {
+ static const base::NoDestructor<SurfaceControlMethods> instance;
+ return *instance;
+ }
+
+ SurfaceControlMethods() {
+ void* main_dl_handle = dlopen(nullptr, RTLD_NOW);
+ if (!main_dl_handle) {
+ LOG(ERROR) << "Couldnt load android so";
+ supported = false;
+ return;
+ }
+
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_CreateSurfaceForWindow);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_CreateSurface);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_DeleteSurface);
+
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_CreateTransaction);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_DeleteTransaction);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionApply);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetCompletedFunc);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetVisibility);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetZOrder);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetBuffer);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetCropRect);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetDisplayFrame);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetBufferOpaque);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceControl_TransactionSetDamageRegion);
+ }
+
+ ~SurfaceControlMethods() = default;
+
+ bool supported = true;
+ // Surface methods.
+ pASurfaceControl_CreateSurfaceForWindow
+ ASurfaceControl_CreateSurfaceForWindowFn;
+ pASurfaceControl_CreateSurface ASurfaceControl_CreateSurfaceFn;
+ pASurfaceControl_DeleteSurface ASurfaceControl_DeleteSurfaceFn;
+
+ // Transaction methods.
+ pASurfaceControl_CreateTransaction ASurfaceControl_CreateTransactionFn;
+ pASurfaceControl_DeleteTransaction ASurfaceControl_DeleteTransactionFn;
+ pASurfaceControl_TransactionApply ASurfaceControl_TransactionApplyFn;
+ pASurfaceControl_TransactionSetCompletedFunc
+ ASurfaceControl_TransactionSetCompletedFuncFn;
+ pASurfaceControl_TransactionSetVisibility
+ ASurfaceControl_TransactionSetVisibilityFn;
+ pASurfaceControl_TransactionSetZOrder ASurfaceControl_TransactionSetZOrderFn;
+ pASurfaceControl_TransactionSetBuffer ASurfaceControl_TransactionSetBufferFn;
+ pASurfaceControl_TransactionSetCropRect
+ ASurfaceControl_TransactionSetCropRectFn;
+ pASurfaceControl_TransactionSetDisplayFrame
+ ASurfaceControl_TransactionSetDisplayFrameFn;
+ pASurfaceControl_TransactionSetBufferOpaque
+ ASurfaceControl_TransactionSetBufferOpaqueFn;
+ pASurfaceControl_TransactionSetDamageRegion
+ ASurfaceControl_TransactionSetDamageRegionFn;
+};
+
+ARect RectToARect(const gfx::Rect& rect) {
+ return ARect{rect.x(), rect.y(), rect.right(), rect.bottom()};
+}
+};
+
+// static
+bool SurfaceControl::IsSupported() {
+#if 0
+ // TODO(khushalsagar): Enable this code when the frame is correctly reporting
+ // SDK version for P+.
+ const int sdk_int = base::android::BuildInfo::GetInstance()->sdk_int();
+ if (sdk_int < 29) {
+ LOG(ERROR) << "SurfaceControl not supported on sdk: " << sdk_int;
+ return false;
+ }
+#endif
+ return SurfaceControlMethods::Get().supported;
+}
+
+SurfaceControl::Surface::Surface() = default;
+
+SurfaceControl::Surface::Surface(const Surface& parent, const char* name) {
+ surface_ = SurfaceControlMethods::Get().ASurfaceControl_CreateSurfaceFn(
+ parent.surface(), name);
+ DCHECK(surface_);
+}
+
+SurfaceControl::Surface::Surface(ANativeWindow* parent, const char* name) {
+ surface_ =
+ SurfaceControlMethods::Get().ASurfaceControl_CreateSurfaceForWindowFn(
+ parent, name);
+ DCHECK(surface_);
+}
+
+SurfaceControl::Surface::~Surface() {
+ if (surface_)
+ SurfaceControlMethods::Get().ASurfaceControl_DeleteSurfaceFn(surface_);
+}
+
+SurfaceControl::Surface::Surface(Surface&& other) {
+ surface_ = other.surface_;
+ other.surface_ = nullptr;
+}
+
+SurfaceControl::Surface& SurfaceControl::Surface::operator=(Surface&& other) {
+ if (surface_)
+ SurfaceControlMethods::Get().ASurfaceControl_DeleteSurfaceFn(surface_);
+
+ surface_ = other.surface_;
+ other.surface_ = nullptr;
+ return *this;
+}
+
+SurfaceControl::Transaction::Transaction() {
+ transaction_ =
+ SurfaceControlMethods::Get().ASurfaceControl_CreateTransactionFn();
+ DCHECK(transaction_);
+}
+
+SurfaceControl::Transaction::~Transaction() {
+ SurfaceControlMethods::Get().ASurfaceControl_DeleteTransactionFn(
+ transaction_);
+}
+
+void SurfaceControl::Transaction::SetVisibility(const Surface& surface,
+ bool show) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetVisibilityFn(
+ transaction_, surface.surface(), show);
+}
+
+void SurfaceControl::Transaction::SetZOrder(const Surface& surface, int32_t z) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetZOrderFn(
+ transaction_, surface.surface(), z);
+}
+
+void SurfaceControl::Transaction::SetBuffer(const Surface& surface,
+ AHardwareBuffer* buffer,
+ base::ScopedFD fence_fd) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetBufferFn(
+ transaction_, surface.surface(), buffer,
+ fence_fd.is_valid() ? fence_fd.release() : -1);
+}
+
+void SurfaceControl::Transaction::SetCropRect(const Surface& surface,
+ const gfx::Rect& rect) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetCropRectFn(
+ transaction_, surface.surface(), RectToARect(rect));
+}
+
+void SurfaceControl::Transaction::SetDisplayFrame(const Surface& surface,
+ const gfx::Rect& rect) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetDisplayFrameFn(
+ transaction_, surface.surface(), RectToARect(rect));
+}
+
+void SurfaceControl::Transaction::SetOpaque(const Surface& surface,
+ bool opaque) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetBufferOpaqueFn(
+ transaction_, surface.surface(), opaque);
+}
+
+void SurfaceControl::Transaction::SetDamageRect(const Surface& surface,
+ const gfx::Rect& rect) {
+ auto a_rect = RectToARect(rect);
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetDamageRegionFn(
+ transaction_, surface.surface(), &a_rect, 1u);
+}
+
+void SurfaceControl::Transaction::SetCompletedFunc(
+ TransactionCompletedFunc func,
+ void* ctx) {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionSetCompletedFuncFn(
+ transaction_, ctx, func);
+}
+
+void SurfaceControl::Transaction::Apply() {
+ SurfaceControlMethods::Get().ASurfaceControl_TransactionApplyFn(transaction_);
+}
+
+} // namespace gl
diff --git a/chromium/ui/gl/android/android_surface_composer_compat.h b/chromium/ui/gl/android/android_surface_control_compat.h
index 05b6c874794..0c3434ff2c3 100644
--- a/chromium/ui/gl/android/android_surface_composer_compat.h
+++ b/chromium/ui/gl/android/android_surface_control_compat.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_ANDROID_ANDROID_SURFACE_COMPOSER_COMPAT_H_
-#define UI_GL_ANDROID_ANDROID_SURFACE_COMPOSER_COMPAT_H_
+#ifndef UI_GL_ANDROID_ANDROID_SURFACE_CONTROL_COMPAT_H_
+#define UI_GL_ANDROID_ANDROID_SURFACE_CONTROL_COMPAT_H_
#include <memory>
@@ -11,30 +11,27 @@
#include <android/native_window.h>
#include "base/files/scoped_file.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gl/gl_export.h"
extern "C" {
typedef struct ASurface ASurface;
-typedef struct ASurfaceComposer ASurfaceComposer;
typedef struct ASurfaceTransaction ASurfaceTransaction;
+typedef void (*TransactionCompletedFunc)(void* context,
+ int64_t present_time_ns);
}
namespace gl {
-class GL_EXPORT SurfaceComposer {
+class GL_EXPORT SurfaceControl {
public:
- enum class SurfaceContentType : int32_t {
- kNone = 0,
- kAHardwareBuffer = 1,
- };
+ static bool IsSupported();
class GL_EXPORT Surface {
public:
Surface();
- Surface(SurfaceComposer* composer,
- SurfaceContentType content_type,
- const char* name,
- Surface* parent = nullptr);
+ Surface(const Surface& parent, const char* name);
+ Surface(ANativeWindow* parent, const char* name);
~Surface();
Surface(Surface&& other);
@@ -52,35 +49,21 @@ class GL_EXPORT SurfaceComposer {
~Transaction();
void SetVisibility(const Surface& surface, bool show);
- void SetPosition(const Surface& surface, float x, float y);
void SetZOrder(const Surface& surface, int32_t z);
void SetBuffer(const Surface& surface,
AHardwareBuffer* buffer,
base::ScopedFD fence_fd);
- void SetSize(const Surface& surface, uint32_t width, uint32_t height);
- void SetCropRect(const Surface& surface,
- int32_t left,
- int32_t top,
- int32_t right,
- int32_t bottom);
+ void SetCropRect(const Surface& surface, const gfx::Rect& rect);
+ void SetDisplayFrame(const Surface& surface, const gfx::Rect& rect);
void SetOpaque(const Surface& surface, bool opaque);
+ void SetDamageRect(const Surface& surface, const gfx::Rect& rect);
+ void SetCompletedFunc(TransactionCompletedFunc func, void* ctx);
void Apply();
private:
ASurfaceTransaction* transaction_;
};
-
- static bool IsSupported();
-
- static std::unique_ptr<SurfaceComposer> Create(ANativeWindow* window);
- ~SurfaceComposer();
-
- private:
- explicit SurfaceComposer(ASurfaceComposer* composer);
-
- ASurfaceComposer* composer_;
};
-
}; // namespace gl
-#endif // UI_GL_ANDROID_ANDROID_SURFACE_COMPOSER_COMPAT_H_
+#endif // UI_GL_ANDROID_ANDROID_SURFACE_CONTROL_COMPAT_H_
diff --git a/chromium/ui/gl/android/surface_texture.cc b/chromium/ui/gl/android/surface_texture.cc
index 2ddad6c5447..a781d502a74 100644
--- a/chromium/ui/gl/android/surface_texture.cc
+++ b/chromium/ui/gl/android/surface_texture.cc
@@ -59,8 +59,7 @@ void SurfaceTexture::GetTransformMatrix(float mtx[16]) {
Java_SurfaceTexturePlatformWrapper_getTransformMatrix(env, j_surface_texture_,
jmatrix);
- jboolean is_copy;
- jfloat* elements = env->GetFloatArrayElements(jmatrix.obj(), &is_copy);
+ jfloat* elements = env->GetFloatArrayElements(jmatrix.obj(), nullptr);
for (int i = 0; i < 16; ++i) {
mtx[i] = static_cast<float>(elements[i]);
}
diff --git a/chromium/ui/gl/dc_renderer_layer_params.cc b/chromium/ui/gl/dc_renderer_layer_params.cc
index 594dac43053..479dcf68032 100644
--- a/chromium/ui/gl/dc_renderer_layer_params.cc
+++ b/chromium/ui/gl/dc_renderer_layer_params.cc
@@ -20,7 +20,7 @@ DCRendererLayerParams::DCRendererLayerParams(
unsigned edge_aa_mask,
float opacity,
unsigned filter,
- bool is_protected_video)
+ ProtectedVideoType protected_video_type)
: is_clipped(is_clipped),
clip_rect(clip_rect),
z_order(z_order),
@@ -32,7 +32,7 @@ DCRendererLayerParams::DCRendererLayerParams(
edge_aa_mask(edge_aa_mask),
opacity(opacity),
filter(filter),
- is_protected_video(is_protected_video) {}
+ protected_video_type(protected_video_type) {}
DCRendererLayerParams::DCRendererLayerParams(
const DCRendererLayerParams& other) = default;
diff --git a/chromium/ui/gl/dc_renderer_layer_params.h b/chromium/ui/gl/dc_renderer_layer_params.h
index de92d58ddf6..d3ea2ab1cfe 100644
--- a/chromium/ui/gl/dc_renderer_layer_params.h
+++ b/chromium/ui/gl/dc_renderer_layer_params.h
@@ -21,6 +21,13 @@ class GLImage;
namespace ui {
+enum class ProtectedVideoType : uint32_t {
+ kClear = 0,
+ kSoftwareProtected = 1,
+ kHardwareProtected = 2,
+ kMaxValue = kHardwareProtected,
+};
+
struct GL_EXPORT DCRendererLayerParams {
DCRendererLayerParams(bool is_clipped,
const gfx::Rect clip_rect,
@@ -33,7 +40,7 @@ struct GL_EXPORT DCRendererLayerParams {
unsigned edge_aa_mask,
float opacity,
unsigned filter,
- bool is_protected_video);
+ ProtectedVideoType protected_video_type);
DCRendererLayerParams(const DCRendererLayerParams& other);
~DCRendererLayerParams();
@@ -48,7 +55,7 @@ struct GL_EXPORT DCRendererLayerParams {
unsigned edge_aa_mask;
float opacity;
unsigned filter;
- bool is_protected_video;
+ ProtectedVideoType protected_video_type;
// This is a subset of cc::FilterOperation::FilterType.
enum class FilterEffectType : uint32_t {
diff --git a/chromium/ui/gl/generate_bindings.py b/chromium/ui/gl/generate_bindings.py
index 864919616df..6d5edc9cd4f 100755
--- a/chromium/ui/gl/generate_bindings.py
+++ b/chromium/ui/gl/generate_bindings.py
@@ -1344,6 +1344,29 @@ GL_FUNCTIONS = [
'names': ['glMinSampleShading'],
'arguments': 'GLfloat value', },
{ 'return_type': 'void',
+ 'versions' : [{'name': 'glMultiDrawArraysANGLE',
+ 'extensions': ['GL_ANGLE_multi_draw'] }],
+ 'arguments': 'GLenum mode, const GLint* firsts, '
+ 'const GLsizei* counts, GLsizei drawcount', },
+{ 'return_type': 'void',
+ 'versions' : [{'name': 'glMultiDrawArraysInstancedANGLE',
+ 'extensions': ['GL_ANGLE_multi_draw'] }],
+ 'arguments': 'GLenum mode, const GLint* firsts, '
+ 'const GLsizei* counts, const GLsizei* instanceCounts, '
+ 'GLsizei drawcount', },
+{ 'return_type': 'void',
+ 'versions' : [{'name': 'glMultiDrawElementsANGLE',
+ 'extensions': ['GL_ANGLE_multi_draw'] }],
+ 'arguments': 'GLenum mode, const GLsizei* counts, '
+ 'GLenum type, const GLvoid* const* indices, '
+ 'GLsizei drawcount', },
+{ 'return_type': 'void',
+ 'versions' : [{'name': 'glMultiDrawElementsInstancedANGLE',
+ 'extensions': ['GL_ANGLE_multi_draw'] }],
+ 'arguments': 'GLenum mode, const GLsizei* counts, '
+ 'GLenum type, const GLvoid* const* indices, '
+ 'const GLsizei* instanceCounts, GLsizei drawcount', },
+{ 'return_type': 'void',
'versions': [{ 'name': 'glObjectLabel' },
{ 'name': 'glObjectLabelKHR',
'extensions': ['GL_KHR_debug'] }],
diff --git a/chromium/ui/gl/gl_bindings.h b/chromium/ui/gl/gl_bindings.h
index ae88b309acf..dd756620a91 100644
--- a/chromium/ui/gl/gl_bindings.h
+++ b/chromium/ui/gl/gl_bindings.h
@@ -129,6 +129,9 @@
#define GL_REQUESTABLE_EXTENSIONS_ANGLE 0x93A8
#define GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE 0x93A8
+// GL_ANGLE_memory_size
+#define GL_MEMORY_SIZE_ANGLE 0x93AD
+
// GL_EXT_occlusion_query_boolean
#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
@@ -419,6 +422,12 @@
#define GL_COMPLETION_STATUS_KHR 0x91B1
#endif /* GL_KHR_parallel_shader_compile */
+#ifndef GL_CHROMIUM_shared_image
+#define GL_CHROMIUM_shared_image 1
+#define GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM 0x8AF5
+#define GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM 0x8AF6
+#endif /* GL_CHROMIUM_shared_image */
+
#define GL_GLEXT_PROTOTYPES 1
#if defined(OS_WIN)
diff --git a/chromium/ui/gl/gl_bindings_api_autogen_gl.h b/chromium/ui/gl/gl_bindings_api_autogen_gl.h
index 2247ae06d71..b36d9e8f959 100644
--- a/chromium/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/chromium/ui/gl/gl_bindings_api_autogen_gl.h
@@ -871,6 +871,26 @@ void glMaxShaderCompilerThreadsKHRFn(GLuint count) override;
void glMemoryBarrierByRegionFn(GLbitfield barriers) override;
void glMemoryBarrierEXTFn(GLbitfield barriers) override;
void glMinSampleShadingFn(GLfloat value) override;
+void glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) override;
+void glMultiDrawArraysInstancedANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) override;
+void glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) override;
+void glMultiDrawElementsInstancedANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) override;
void glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.cc b/chromium/ui/gl/gl_bindings_autogen_gl.cc
index 9666e7b3320..d9780a4a473 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.cc
@@ -285,6 +285,8 @@ void DriverGL::InitializeDynamicBindings(const GLVersionInfo* ver,
gfx::HasExtension(extensions, "GL_ANGLE_framebuffer_multisample");
ext.b_GL_ANGLE_instanced_arrays =
gfx::HasExtension(extensions, "GL_ANGLE_instanced_arrays");
+ ext.b_GL_ANGLE_multi_draw =
+ gfx::HasExtension(extensions, "GL_ANGLE_multi_draw");
ext.b_GL_ANGLE_multiview =
gfx::HasExtension(extensions, "GL_ANGLE_multiview");
ext.b_GL_ANGLE_request_extension =
@@ -1856,6 +1858,29 @@ void DriverGL::InitializeDynamicBindings(const GLVersionInfo* ver,
GetGLProcAddress("glMinSampleShading"));
}
+ if (ext.b_GL_ANGLE_multi_draw) {
+ fn.glMultiDrawArraysANGLEFn = reinterpret_cast<glMultiDrawArraysANGLEProc>(
+ GetGLProcAddress("glMultiDrawArraysANGLE"));
+ }
+
+ if (ext.b_GL_ANGLE_multi_draw) {
+ fn.glMultiDrawArraysInstancedANGLEFn =
+ reinterpret_cast<glMultiDrawArraysInstancedANGLEProc>(
+ GetGLProcAddress("glMultiDrawArraysInstancedANGLE"));
+ }
+
+ if (ext.b_GL_ANGLE_multi_draw) {
+ fn.glMultiDrawElementsANGLEFn =
+ reinterpret_cast<glMultiDrawElementsANGLEProc>(
+ GetGLProcAddress("glMultiDrawElementsANGLE"));
+ }
+
+ if (ext.b_GL_ANGLE_multi_draw) {
+ fn.glMultiDrawElementsInstancedANGLEFn =
+ reinterpret_cast<glMultiDrawElementsInstancedANGLEProc>(
+ GetGLProcAddress("glMultiDrawElementsInstancedANGLE"));
+ }
+
if (ver->IsAtLeastGL(4u, 3u) || ver->IsAtLeastGLES(3u, 2u)) {
fn.glObjectLabelFn =
reinterpret_cast<glObjectLabelProc>(GetGLProcAddress("glObjectLabel"));
@@ -4486,6 +4511,42 @@ void GLApiBase::glMinSampleShadingFn(GLfloat value) {
driver_->fn.glMinSampleShadingFn(value);
}
+void GLApiBase::glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) {
+ driver_->fn.glMultiDrawArraysANGLEFn(mode, firsts, counts, drawcount);
+}
+
+void GLApiBase::glMultiDrawArraysInstancedANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ driver_->fn.glMultiDrawArraysInstancedANGLEFn(mode, firsts, counts,
+ instanceCounts, drawcount);
+}
+
+void GLApiBase::glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) {
+ driver_->fn.glMultiDrawElementsANGLEFn(mode, counts, type, indices,
+ drawcount);
+}
+
+void GLApiBase::glMultiDrawElementsInstancedANGLEFn(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ driver_->fn.glMultiDrawElementsInstancedANGLEFn(mode, counts, type, indices,
+ instanceCounts, drawcount);
+}
+
void GLApiBase::glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
@@ -7846,6 +7907,48 @@ void TraceGLApi::glMinSampleShadingFn(GLfloat value) {
gl_api_->glMinSampleShadingFn(value);
}
+void TraceGLApi::glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMultiDrawArraysANGLE")
+ gl_api_->glMultiDrawArraysANGLEFn(mode, firsts, counts, drawcount);
+}
+
+void TraceGLApi::glMultiDrawArraysInstancedANGLEFn(
+ GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glMultiDrawArraysInstancedANGLE")
+ gl_api_->glMultiDrawArraysInstancedANGLEFn(mode, firsts, counts,
+ instanceCounts, drawcount);
+}
+
+void TraceGLApi::glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glMultiDrawElementsANGLE")
+ gl_api_->glMultiDrawElementsANGLEFn(mode, counts, type, indices, drawcount);
+}
+
+void TraceGLApi::glMultiDrawElementsInstancedANGLEFn(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glMultiDrawElementsInstancedANGLE")
+ gl_api_->glMultiDrawElementsInstancedANGLEFn(mode, counts, type, indices,
+ instanceCounts, drawcount);
+}
+
void TraceGLApi::glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
@@ -12106,6 +12209,64 @@ void DebugGLApi::glMinSampleShadingFn(GLfloat value) {
gl_api_->glMinSampleShadingFn(value);
}
+void DebugGLApi::glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) {
+ GL_SERVICE_LOG("glMultiDrawArraysANGLE"
+ << "(" << GLEnums::GetStringEnum(mode) << ", "
+ << static_cast<const void*>(firsts) << ", "
+ << static_cast<const void*>(counts) << ", " << drawcount
+ << ")");
+ gl_api_->glMultiDrawArraysANGLEFn(mode, firsts, counts, drawcount);
+}
+
+void DebugGLApi::glMultiDrawArraysInstancedANGLEFn(
+ GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ GL_SERVICE_LOG("glMultiDrawArraysInstancedANGLE"
+ << "(" << GLEnums::GetStringEnum(mode) << ", "
+ << static_cast<const void*>(firsts) << ", "
+ << static_cast<const void*>(counts) << ", "
+ << static_cast<const void*>(instanceCounts) << ", "
+ << drawcount << ")");
+ gl_api_->glMultiDrawArraysInstancedANGLEFn(mode, firsts, counts,
+ instanceCounts, drawcount);
+}
+
+void DebugGLApi::glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) {
+ GL_SERVICE_LOG("glMultiDrawElementsANGLE"
+ << "(" << GLEnums::GetStringEnum(mode) << ", "
+ << static_cast<const void*>(counts) << ", "
+ << GLEnums::GetStringEnum(type) << ", " << indices << ", "
+ << drawcount << ")");
+ gl_api_->glMultiDrawElementsANGLEFn(mode, counts, type, indices, drawcount);
+}
+
+void DebugGLApi::glMultiDrawElementsInstancedANGLEFn(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ GL_SERVICE_LOG("glMultiDrawElementsInstancedANGLE"
+ << "(" << GLEnums::GetStringEnum(mode) << ", "
+ << static_cast<const void*>(counts) << ", "
+ << GLEnums::GetStringEnum(type) << ", " << indices << ", "
+ << static_cast<const void*>(instanceCounts) << ", "
+ << drawcount << ")");
+ gl_api_->glMultiDrawElementsInstancedANGLEFn(mode, counts, type, indices,
+ instanceCounts, drawcount);
+}
+
void DebugGLApi::glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
@@ -15745,6 +15906,40 @@ void NoContextGLApi::glMinSampleShadingFn(GLfloat value) {
NoContextHelper("glMinSampleShading");
}
+void NoContextGLApi::glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) {
+ NoContextHelper("glMultiDrawArraysANGLE");
+}
+
+void NoContextGLApi::glMultiDrawArraysInstancedANGLEFn(
+ GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ NoContextHelper("glMultiDrawArraysInstancedANGLE");
+}
+
+void NoContextGLApi::glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) {
+ NoContextHelper("glMultiDrawElementsANGLE");
+}
+
+void NoContextGLApi::glMultiDrawElementsInstancedANGLEFn(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ NoContextHelper("glMultiDrawElementsInstancedANGLE");
+}
+
void NoContextGLApi::glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
diff --git a/chromium/ui/gl/gl_bindings_autogen_gl.h b/chromium/ui/gl/gl_bindings_autogen_gl.h
index 7de89ead0e7..8b83c70bbe2 100644
--- a/chromium/ui/gl/gl_bindings_autogen_gl.h
+++ b/chromium/ui/gl/gl_bindings_autogen_gl.h
@@ -1024,6 +1024,29 @@ typedef void(GL_BINDING_CALL* glMaxShaderCompilerThreadsKHRProc)(GLuint count);
typedef void(GL_BINDING_CALL* glMemoryBarrierByRegionProc)(GLbitfield barriers);
typedef void(GL_BINDING_CALL* glMemoryBarrierEXTProc)(GLbitfield barriers);
typedef void(GL_BINDING_CALL* glMinSampleShadingProc)(GLfloat value);
+typedef void(GL_BINDING_CALL* glMultiDrawArraysANGLEProc)(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount);
+typedef void(GL_BINDING_CALL* glMultiDrawArraysInstancedANGLEProc)(
+ GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount);
+typedef void(GL_BINDING_CALL* glMultiDrawElementsANGLEProc)(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount);
+typedef void(GL_BINDING_CALL* glMultiDrawElementsInstancedANGLEProc)(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount);
typedef void(GL_BINDING_CALL* glObjectLabelProc)(GLenum identifier,
GLuint name,
GLsizei length,
@@ -1750,6 +1773,7 @@ struct ExtensionsGL {
bool b_GL_ANGLE_framebuffer_blit;
bool b_GL_ANGLE_framebuffer_multisample;
bool b_GL_ANGLE_instanced_arrays;
+ bool b_GL_ANGLE_multi_draw;
bool b_GL_ANGLE_multiview;
bool b_GL_ANGLE_request_extension;
bool b_GL_ANGLE_robust_client_memory;
@@ -2116,6 +2140,10 @@ struct ProcsGL {
glMemoryBarrierByRegionProc glMemoryBarrierByRegionFn;
glMemoryBarrierEXTProc glMemoryBarrierEXTFn;
glMinSampleShadingProc glMinSampleShadingFn;
+ glMultiDrawArraysANGLEProc glMultiDrawArraysANGLEFn;
+ glMultiDrawArraysInstancedANGLEProc glMultiDrawArraysInstancedANGLEFn;
+ glMultiDrawElementsANGLEProc glMultiDrawElementsANGLEFn;
+ glMultiDrawElementsInstancedANGLEProc glMultiDrawElementsInstancedANGLEFn;
glObjectLabelProc glObjectLabelFn;
glObjectPtrLabelProc glObjectPtrLabelFn;
glPathCommandsNVProc glPathCommandsNVFn;
@@ -3193,6 +3221,27 @@ class GL_EXPORT GLApi {
virtual void glMemoryBarrierByRegionFn(GLbitfield barriers) = 0;
virtual void glMemoryBarrierEXTFn(GLbitfield barriers) = 0;
virtual void glMinSampleShadingFn(GLfloat value) = 0;
+ virtual void glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) = 0;
+ virtual void glMultiDrawArraysInstancedANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) = 0;
+ virtual void glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) = 0;
+ virtual void glMultiDrawElementsInstancedANGLEFn(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) = 0;
virtual void glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
@@ -4269,6 +4318,14 @@ class GL_EXPORT GLApi {
::gl::g_current_gl_context->glMemoryBarrierByRegionFn
#define glMemoryBarrierEXT ::gl::g_current_gl_context->glMemoryBarrierEXTFn
#define glMinSampleShading ::gl::g_current_gl_context->glMinSampleShadingFn
+#define glMultiDrawArraysANGLE \
+ ::gl::g_current_gl_context->glMultiDrawArraysANGLEFn
+#define glMultiDrawArraysInstancedANGLE \
+ ::gl::g_current_gl_context->glMultiDrawArraysInstancedANGLEFn
+#define glMultiDrawElementsANGLE \
+ ::gl::g_current_gl_context->glMultiDrawElementsANGLEFn
+#define glMultiDrawElementsInstancedANGLE \
+ ::gl::g_current_gl_context->glMultiDrawElementsInstancedANGLEFn
#define glObjectLabel ::gl::g_current_gl_context->glObjectLabelFn
#define glObjectPtrLabel ::gl::g_current_gl_context->glObjectPtrLabelFn
#define glPathCommandsNV ::gl::g_current_gl_context->glPathCommandsNVFn
diff --git a/chromium/ui/gl/gl_bindings_autogen_mock.cc b/chromium/ui/gl/gl_bindings_autogen_mock.cc
index 206df2d9ecb..33dc1aa73c4 100644
--- a/chromium/ui/gl/gl_bindings_autogen_mock.cc
+++ b/chromium/ui/gl/gl_bindings_autogen_mock.cc
@@ -2963,6 +2963,48 @@ void GL_BINDING_CALL MockGLInterface::Mock_glMinSampleShading(GLfloat value) {
interface_->MinSampleShading(value);
}
+void GL_BINDING_CALL
+MockGLInterface::Mock_glMultiDrawArraysANGLE(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) {
+ MakeGlMockFunctionUnique("glMultiDrawArraysANGLE");
+ interface_->MultiDrawArraysANGLE(mode, firsts, counts, drawcount);
+}
+
+void GL_BINDING_CALL MockGLInterface::Mock_glMultiDrawArraysInstancedANGLE(
+ GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ MakeGlMockFunctionUnique("glMultiDrawArraysInstancedANGLE");
+ interface_->MultiDrawArraysInstancedANGLE(mode, firsts, counts,
+ instanceCounts, drawcount);
+}
+
+void GL_BINDING_CALL
+MockGLInterface::Mock_glMultiDrawElementsANGLE(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) {
+ MakeGlMockFunctionUnique("glMultiDrawElementsANGLE");
+ interface_->MultiDrawElementsANGLE(mode, counts, type, indices, drawcount);
+}
+
+void GL_BINDING_CALL MockGLInterface::Mock_glMultiDrawElementsInstancedANGLE(
+ GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) {
+ MakeGlMockFunctionUnique("glMultiDrawElementsInstancedANGLE");
+ interface_->MultiDrawElementsInstancedANGLE(mode, counts, type, indices,
+ instanceCounts, drawcount);
+}
+
void GL_BINDING_CALL MockGLInterface::Mock_glObjectLabel(GLenum identifier,
GLuint name,
GLsizei length,
@@ -5658,6 +5700,17 @@ MockGLInterface::GetGLProcAddress(const char* name) {
return reinterpret_cast<GLFunctionPointerType>(Mock_glMemoryBarrierEXT);
if (strcmp(name, "glMinSampleShading") == 0)
return reinterpret_cast<GLFunctionPointerType>(Mock_glMinSampleShading);
+ if (strcmp(name, "glMultiDrawArraysANGLE") == 0)
+ return reinterpret_cast<GLFunctionPointerType>(Mock_glMultiDrawArraysANGLE);
+ if (strcmp(name, "glMultiDrawArraysInstancedANGLE") == 0)
+ return reinterpret_cast<GLFunctionPointerType>(
+ Mock_glMultiDrawArraysInstancedANGLE);
+ if (strcmp(name, "glMultiDrawElementsANGLE") == 0)
+ return reinterpret_cast<GLFunctionPointerType>(
+ Mock_glMultiDrawElementsANGLE);
+ if (strcmp(name, "glMultiDrawElementsInstancedANGLE") == 0)
+ return reinterpret_cast<GLFunctionPointerType>(
+ Mock_glMultiDrawElementsInstancedANGLE);
if (strcmp(name, "glObjectLabel") == 0)
return reinterpret_cast<GLFunctionPointerType>(Mock_glObjectLabel);
if (strcmp(name, "glObjectLabelKHR") == 0)
diff --git a/chromium/ui/gl/gl_bindings_autogen_mock.h b/chromium/ui/gl/gl_bindings_autogen_mock.h
index 42545f14529..d3a5c646cc0 100644
--- a/chromium/ui/gl/gl_bindings_autogen_mock.h
+++ b/chromium/ui/gl/gl_bindings_autogen_mock.h
@@ -1237,6 +1237,29 @@ static void GL_BINDING_CALL Mock_glMemoryBarrier(GLbitfield barriers);
static void GL_BINDING_CALL Mock_glMemoryBarrierByRegion(GLbitfield barriers);
static void GL_BINDING_CALL Mock_glMemoryBarrierEXT(GLbitfield barriers);
static void GL_BINDING_CALL Mock_glMinSampleShading(GLfloat value);
+static void GL_BINDING_CALL Mock_glMultiDrawArraysANGLE(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount);
+static void GL_BINDING_CALL
+Mock_glMultiDrawArraysInstancedANGLE(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount);
+static void GL_BINDING_CALL
+Mock_glMultiDrawElementsANGLE(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount);
+static void GL_BINDING_CALL
+Mock_glMultiDrawElementsInstancedANGLE(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount);
static void GL_BINDING_CALL Mock_glObjectLabel(GLenum identifier,
GLuint name,
GLsizei length,
diff --git a/chromium/ui/gl/gl_context.cc b/chromium/ui/gl/gl_context.cc
index b268e3de009..abbacc0dcd7 100644
--- a/chromium/ui/gl/gl_context.cc
+++ b/chromium/ui/gl/gl_context.cc
@@ -188,6 +188,10 @@ void GLContext::ForceReleaseVirtuallyCurrent() {
NOTREACHED();
}
+void GLContext::DirtyVirtualContextState() {
+ current_virtual_context_ = nullptr;
+}
+
#if defined(OS_MACOSX)
uint64_t GLContext::BackpressureFenceCreate() {
return 0;
diff --git a/chromium/ui/gl/gl_context.h b/chromium/ui/gl/gl_context.h
index 9e38ea80199..e1668245e3d 100644
--- a/chromium/ui/gl/gl_context.h
+++ b/chromium/ui/gl/gl_context.h
@@ -194,6 +194,11 @@ class GL_EXPORT GLContext : public base::RefCounted<GLContext> {
// current.
virtual void ForceReleaseVirtuallyCurrent();
+ // Indicates that some GL state was modified that was not tracked by virtual
+ // contexts. Forces full reset from unknown state the next time a virtual
+ // context is made current.
+ void DirtyVirtualContextState();
+
#if defined(OS_MACOSX)
// Create a fence for all work submitted to this context so far, and return a
// monotonically increasing handle to it. This returned handle never needs to
diff --git a/chromium/ui/gl/gl_context_cgl.cc b/chromium/ui/gl/gl_context_cgl.cc
index a563920ef19..7d4fc5d5279 100644
--- a/chromium/ui/gl/gl_context_cgl.cc
+++ b/chromium/ui/gl/gl_context_cgl.cc
@@ -13,7 +13,6 @@
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
@@ -155,7 +154,7 @@ void GLContextCGL::Destroy() {
}
}
if (discrete_pixelformat_) {
- if (base::MessageLoop::current() != nullptr) {
+ if (base::ThreadTaskRunnerHandle::IsSet()) {
// Delay releasing the pixel format for 10 seconds to reduce the number of
// unnecessary GPU switches.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
diff --git a/chromium/ui/gl/gl_enums_implementation_autogen.h b/chromium/ui/gl/gl_enums_implementation_autogen.h
index 8a576262b60..f1321998717 100644
--- a/chromium/ui/gl/gl_enums_implementation_autogen.h
+++ b/chromium/ui/gl/gl_enums_implementation_autogen.h
@@ -1732,6 +1732,9 @@ static const GLEnums::EnumToString enum_to_string_table[] = {
0x8867, "GL_QUERY_RESULT_AVAILABLE_EXT",
},
{
+ 0x8868, "GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT",
+ },
+ {
0x8869, "GL_MAX_VERTEX_ATTRIBS",
},
{
@@ -2020,6 +2023,12 @@ static const GLEnums::EnumToString enum_to_string_table[] = {
0x8AF4, "GL_COLOR_SPACE_DISPLAY_P3_CHROMIUM",
},
{
+ 0x8AF5, "GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM",
+ },
+ {
+ 0x8AF6, "GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM",
+ },
+ {
0x8B30, "GL_FRAGMENT_SHADER",
},
{
diff --git a/chromium/ui/gl/gl_image_memory.cc b/chromium/ui/gl/gl_image_memory.cc
index 26bc08d82cd..4f0641c0e52 100644
--- a/chromium/ui/gl/gl_image_memory.cc
+++ b/chromium/ui/gl/gl_image_memory.cc
@@ -21,20 +21,6 @@ using gfx::BufferFormat;
namespace gl {
namespace {
-bool ValidInternalFormat(unsigned internalformat) {
- switch (internalformat) {
- case GL_RED:
- case GL_RG:
- case GL_RGB:
- case GL_RGBA:
- case GL_RGB10_A2_EXT:
- case GL_BGRA_EXT:
- return true;
- default:
- return false;
- }
-}
-
GLenum TextureFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::R_8:
@@ -286,9 +272,8 @@ std::unique_ptr<uint8_t[]> GLES2Data(const gfx::Size& size,
} // namespace
-GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat)
+GLImageMemory::GLImageMemory(const gfx::Size& size)
: size_(size),
- internalformat_(internalformat),
memory_(nullptr),
format_(gfx::BufferFormat::RGBA_8888),
stride_(0) {}
@@ -305,12 +290,6 @@ GLImageMemory* GLImageMemory::FromGLImage(GLImage* image) {
bool GLImageMemory::Initialize(const unsigned char* memory,
gfx::BufferFormat format,
size_t stride) {
- if (!ValidInternalFormat(internalformat_)) {
- LOG(ERROR) << "Invalid internalformat: "
- << GLEnums::GetStringEnum(internalformat_);
- return false;
- }
-
if (!ValidFormat(format)) {
LOG(ERROR) << "Invalid format: " << gfx::BufferFormatToString(format);
return false;
@@ -334,7 +313,7 @@ gfx::Size GLImageMemory::GetSize() {
}
unsigned GLImageMemory::GetInternalFormat() {
- return internalformat_;
+ return TextureFormat(format_);
}
bool GLImageMemory::BindTexImage(unsigned target) {
@@ -426,12 +405,6 @@ GLImageMemory::Type GLImageMemory::GetType() const {
}
// static
-unsigned GLImageMemory::GetInternalFormatForTesting(gfx::BufferFormat format) {
- DCHECK(ValidFormat(format));
- return TextureFormat(format);
-}
-
-// static
bool GLImageMemory::ValidFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::R_8:
diff --git a/chromium/ui/gl/gl_image_memory.h b/chromium/ui/gl/gl_image_memory.h
index 052a5ed4086..3e9aea8c0d4 100644
--- a/chromium/ui/gl/gl_image_memory.h
+++ b/chromium/ui/gl/gl_image_memory.h
@@ -18,7 +18,7 @@ namespace gl {
class GL_EXPORT GLImageMemory : public GLImage {
public:
- GLImageMemory(const gfx::Size& size, unsigned internalformat);
+ explicit GLImageMemory(const gfx::Size& size);
bool Initialize(const unsigned char* memory,
gfx::BufferFormat format,
@@ -47,8 +47,6 @@ class GL_EXPORT GLImageMemory : public GLImage {
void Flush() override {}
Type GetType() const override;
- static unsigned GetInternalFormatForTesting(gfx::BufferFormat format);
-
const unsigned char* memory() { return memory_; }
size_t stride() const { return stride_; }
gfx::BufferFormat format() const { return format_; }
@@ -60,7 +58,6 @@ class GL_EXPORT GLImageMemory : public GLImage {
static bool ValidFormat(gfx::BufferFormat format);
const gfx::Size size_;
- const unsigned internalformat_;
const unsigned char* memory_;
gfx::BufferFormat format_;
size_t stride_;
diff --git a/chromium/ui/gl/gl_image_ref_counted_memory.cc b/chromium/ui/gl/gl_image_ref_counted_memory.cc
index 327d0e64e7a..259ba08650e 100644
--- a/chromium/ui/gl/gl_image_ref_counted_memory.cc
+++ b/chromium/ui/gl/gl_image_ref_counted_memory.cc
@@ -15,9 +15,8 @@
namespace gl {
-GLImageRefCountedMemory::GLImageRefCountedMemory(const gfx::Size& size,
- unsigned internalformat)
- : GLImageMemory(size, internalformat) {}
+GLImageRefCountedMemory::GLImageRefCountedMemory(const gfx::Size& size)
+ : GLImageMemory(size) {}
GLImageRefCountedMemory::~GLImageRefCountedMemory() {}
diff --git a/chromium/ui/gl/gl_image_ref_counted_memory.h b/chromium/ui/gl/gl_image_ref_counted_memory.h
index 17f12f91124..02923210466 100644
--- a/chromium/ui/gl/gl_image_ref_counted_memory.h
+++ b/chromium/ui/gl/gl_image_ref_counted_memory.h
@@ -20,7 +20,7 @@ namespace gl {
class GL_EXPORT GLImageRefCountedMemory : public GLImageMemory {
public:
- GLImageRefCountedMemory(const gfx::Size& size, unsigned internalformat);
+ explicit GLImageRefCountedMemory(const gfx::Size& size);
bool Initialize(base::RefCountedMemory* ref_counted_memory,
gfx::BufferFormat format);
diff --git a/chromium/ui/gl/gl_image_ref_counted_memory_unittest.cc b/chromium/ui/gl/gl_image_ref_counted_memory_unittest.cc
index 8aa5fc74166..791480b02c7 100644
--- a/chromium/ui/gl/gl_image_ref_counted_memory_unittest.cc
+++ b/chromium/ui/gl/gl_image_ref_counted_memory_unittest.cc
@@ -28,8 +28,7 @@ class GLImageRefCountedMemoryTestDelegate : public GLImageTestDelegateBase {
size.width(), size.height(),
static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)), 0,
format, color, &bytes->data().front());
- scoped_refptr<GLImageRefCountedMemory> image(new GLImageRefCountedMemory(
- size, GLImageMemory::GetInternalFormatForTesting(format)));
+ auto image = base::MakeRefCounted<GLImageRefCountedMemory>(size);
bool rv = image->Initialize(bytes.get(), format);
EXPECT_TRUE(rv);
return image;
diff --git a/chromium/ui/gl/gl_image_shared_memory.cc b/chromium/ui/gl/gl_image_shared_memory.cc
index 3b832c9e04e..d736cd2febe 100644
--- a/chromium/ui/gl/gl_image_shared_memory.cc
+++ b/chromium/ui/gl/gl_image_shared_memory.cc
@@ -5,10 +5,9 @@
#include "ui/gl/gl_image_shared_memory.h"
#include "base/logging.h"
-#include "base/memory/shared_memory.h"
#include "base/numerics/safe_math.h"
#include "base/process/process_handle.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
@@ -16,24 +15,20 @@
namespace gl {
-GLImageSharedMemory::GLImageSharedMemory(const gfx::Size& size,
- unsigned internalformat)
- : GLImageMemory(size, internalformat) {}
+GLImageSharedMemory::GLImageSharedMemory(const gfx::Size& size)
+ : GLImageMemory(size) {}
GLImageSharedMemory::~GLImageSharedMemory() {}
bool GLImageSharedMemory::Initialize(
- const base::SharedMemoryHandle& handle,
+ const base::UnsafeSharedMemoryRegion& region,
gfx::GenericSharedMemoryId shared_memory_id,
gfx::BufferFormat format,
size_t offset,
size_t stride) {
- if (!base::SharedMemory::IsHandleValid(handle))
+ if (!region.IsValid())
return false;
- std::unique_ptr<base::SharedMemory> shared_memory(
- new base::SharedMemory(handle, true));
-
if (NumberOfPlanesForBufferFormat(format) != 1)
return false;
@@ -52,20 +47,21 @@ bool GLImageSharedMemory::Initialize(
if (!checked_size.IsValid())
return false;
- if (!shared_memory->MapAt(static_cast<off_t>(map_offset),
- checked_size.ValueOrDie())) {
+ auto shared_memory_mapping =
+ region.MapAt(static_cast<off_t>(map_offset), checked_size.ValueOrDie());
+ if (!shared_memory_mapping.IsValid()) {
DVLOG(0) << "Failed to map shared memory.";
return false;
}
if (!GLImageMemory::Initialize(
- static_cast<uint8_t*>(shared_memory->memory()) + memory_offset,
+ static_cast<uint8_t*>(shared_memory_mapping.memory()) + memory_offset,
format, stride)) {
return false;
}
- DCHECK(!shared_memory_);
- shared_memory_ = std::move(shared_memory);
+ DCHECK(!shared_memory_mapping_.IsValid());
+ shared_memory_mapping_ = std::move(shared_memory_mapping);
shared_memory_id_ = shared_memory_id;
return true;
}
@@ -86,7 +82,7 @@ void GLImageSharedMemory::OnMemoryDump(
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
static_cast<uint64_t>(size_in_bytes));
- auto shared_memory_guid = shared_memory_->mapped_id();
+ auto shared_memory_guid = shared_memory_mapping_.guid();
if (!shared_memory_guid.is_empty()) {
pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_memory_guid,
0 /* importance */);
diff --git a/chromium/ui/gl/gl_image_shared_memory.h b/chromium/ui/gl/gl_image_shared_memory.h
index e80d55a3a1c..bc642418534 100644
--- a/chromium/ui/gl/gl_image_shared_memory.h
+++ b/chromium/ui/gl/gl_image_shared_memory.h
@@ -11,22 +11,18 @@
#include <memory>
#include "base/macros.h"
-#include "base/memory/shared_memory_handle.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "ui/gfx/generic_shared_memory_id.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_image_memory.h"
-namespace base {
-class SharedMemory;
-}
-
namespace gl {
class GL_EXPORT GLImageSharedMemory : public GLImageMemory {
public:
- GLImageSharedMemory(const gfx::Size& size, unsigned internalformat);
+ explicit GLImageSharedMemory(const gfx::Size& size);
- bool Initialize(const base::SharedMemoryHandle& handle,
+ bool Initialize(const base::UnsafeSharedMemoryRegion& shared_memory_region,
gfx::GenericSharedMemoryId shared_memory_id,
gfx::BufferFormat format,
size_t offset,
@@ -41,7 +37,7 @@ class GL_EXPORT GLImageSharedMemory : public GLImageMemory {
~GLImageSharedMemory() override;
private:
- std::unique_ptr<base::SharedMemory> shared_memory_;
+ base::WritableSharedMemoryMapping shared_memory_mapping_;
gfx::GenericSharedMemoryId shared_memory_id_;
DISALLOW_COPY_AND_ASSIGN(GLImageSharedMemory);
diff --git a/chromium/ui/gl/gl_image_shared_memory_unittest.cc b/chromium/ui/gl/gl_image_shared_memory_unittest.cc
index b0490ea4a57..02c13674b5e 100644
--- a/chromium/ui/gl/gl_image_shared_memory_unittest.cc
+++ b/chromium/ui/gl/gl_image_shared_memory_unittest.cc
@@ -5,8 +5,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/memory/shared_memory.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_image_shared_memory.h"
@@ -23,19 +22,20 @@ class GLImageSharedMemoryTestDelegate : public GLImageTestDelegateBase {
scoped_refptr<GLImage> CreateSolidColorImage(const gfx::Size& size,
const uint8_t color[4]) const {
DCHECK_EQ(NumberOfPlanesForBufferFormat(format), 1u);
- base::SharedMemory shared_memory;
- bool rv = shared_memory.CreateAndMapAnonymous(
- gfx::BufferSizeForBufferFormat(size, format));
- DCHECK(rv);
+ base::UnsafeSharedMemoryRegion shared_memory_region =
+ base::UnsafeSharedMemoryRegion::Create(
+ gfx::BufferSizeForBufferFormat(size, format));
+ base::WritableSharedMemoryMapping shared_memory_mapping =
+ shared_memory_region.Map();
+ DCHECK(shared_memory_mapping.IsValid());
+
GLImageTestSupport::SetBufferDataToColor(
size.width(), size.height(),
static_cast<int>(RowSizeForBufferFormat(size.width(), format, 0)), 0,
- format, color, static_cast<uint8_t*>(shared_memory.memory()));
- scoped_refptr<GLImageSharedMemory> image(new GLImageSharedMemory(
- size, GLImageMemory::GetInternalFormatForTesting(format)));
- rv = image->Initialize(
- base::SharedMemory::DuplicateHandle(shared_memory.handle()),
- gfx::GenericSharedMemoryId(0), format, 0,
+ format, color, static_cast<uint8_t*>(shared_memory_mapping.memory()));
+ auto image = base::MakeRefCounted<GLImageSharedMemory>(size);
+ bool rv = image->Initialize(
+ shared_memory_region, gfx::GenericSharedMemoryId(0), format, 0,
gfx::RowSizeForBufferFormat(size.width(), format, 0));
EXPECT_TRUE(rv);
return image;
@@ -87,23 +87,23 @@ class GLImageSharedMemoryPoolTestDelegate : public GLImageTestDelegateBase {
2;
size_t pool_size =
stride * size.height() + base::SysInfo::VMAllocationGranularity() * 3;
- base::SharedMemory shared_memory;
- bool rv = shared_memory.CreateAndMapAnonymous(pool_size);
- DCHECK(rv);
+ base::UnsafeSharedMemoryRegion shared_memory_region =
+ base::UnsafeSharedMemoryRegion::Create(pool_size);
+ base::WritableSharedMemoryMapping shared_memory_mapping =
+ shared_memory_region.Map();
+ DCHECK(shared_memory_mapping.IsValid());
// Initialize memory to a value that is easy to recognize if test fails.
- memset(shared_memory.memory(), 0x55, pool_size);
+ memset(shared_memory_mapping.memory(), 0x55, pool_size);
// Place buffer at a non-zero non-page-aligned offset in shared memory.
size_t buffer_offset = 3 * base::SysInfo::VMAllocationGranularity() / 2;
GLImageTestSupport::SetBufferDataToColor(
size.width(), size.height(), static_cast<int>(stride), 0,
gfx::BufferFormat::RGBA_8888, color,
- static_cast<uint8_t*>(shared_memory.memory()) + buffer_offset);
- scoped_refptr<GLImageSharedMemory> image(
- new GLImageSharedMemory(size, GL_RGBA));
- rv = image->Initialize(
- base::SharedMemory::DuplicateHandle(shared_memory.handle()),
- gfx::GenericSharedMemoryId(0), gfx::BufferFormat::RGBA_8888,
- buffer_offset, stride);
+ static_cast<uint8_t*>(shared_memory_mapping.memory()) + buffer_offset);
+ auto image = base::MakeRefCounted<GLImageSharedMemory>(size);
+ bool rv =
+ image->Initialize(shared_memory_region, gfx::GenericSharedMemoryId(0),
+ gfx::BufferFormat::RGBA_8888, buffer_offset, stride);
EXPECT_TRUE(rv);
return image;
}
diff --git a/chromium/ui/gl/gl_implementation.h b/chromium/ui/gl/gl_implementation.h
index f3e43f76039..fd6290c6efa 100644
--- a/chromium/ui/gl/gl_implementation.h
+++ b/chromium/ui/gl/gl_implementation.h
@@ -21,16 +21,20 @@ namespace gl {
class GLApi;
// The GL implementation currently in use.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. It should match enum GLImplementation
+// in /tool/metrics/histograms/enums.xml
enum GLImplementation {
- kGLImplementationNone,
- kGLImplementationDesktopGL,
- kGLImplementationDesktopGLCoreProfile,
- kGLImplementationSwiftShaderGL,
- kGLImplementationAppleGL,
- kGLImplementationEGLGLES2,
- kGLImplementationMockGL,
- kGLImplementationStubGL,
- kGLImplementationDisabled,
+ kGLImplementationNone = 0,
+ kGLImplementationDesktopGL = 1,
+ kGLImplementationDesktopGLCoreProfile = 2,
+ kGLImplementationSwiftShaderGL = 3,
+ kGLImplementationAppleGL = 4,
+ kGLImplementationEGLGLES2 = 5,
+ kGLImplementationMockGL = 6,
+ kGLImplementationStubGL = 7,
+ kGLImplementationDisabled = 8,
+ kMaxValue = kGLImplementationDisabled,
};
struct GL_EXPORT GLWindowSystemBindingInfo {
diff --git a/chromium/ui/gl/gl_mock_autogen_gl.h b/chromium/ui/gl/gl_mock_autogen_gl.h
index 37c95a26582..40ffe994c16 100644
--- a/chromium/ui/gl/gl_mock_autogen_gl.h
+++ b/chromium/ui/gl/gl_mock_autogen_gl.h
@@ -872,6 +872,30 @@ MOCK_METHOD1(MaxShaderCompilerThreadsKHR, void(GLuint count));
MOCK_METHOD1(MemoryBarrierByRegion, void(GLbitfield barriers));
MOCK_METHOD1(MemoryBarrierEXT, void(GLbitfield barriers));
MOCK_METHOD1(MinSampleShading, void(GLfloat value));
+MOCK_METHOD4(MultiDrawArraysANGLE,
+ void(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount));
+MOCK_METHOD5(MultiDrawArraysInstancedANGLE,
+ void(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount));
+MOCK_METHOD5(MultiDrawElementsANGLE,
+ void(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount));
+MOCK_METHOD6(MultiDrawElementsInstancedANGLE,
+ void(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount));
MOCK_METHOD4(
ObjectLabel,
void(GLenum identifier, GLuint name, GLsizei length, const char* label));
diff --git a/chromium/ui/gl/gl_stub_autogen_gl.h b/chromium/ui/gl/gl_stub_autogen_gl.h
index 3f30f249b80..64a6a67bcf4 100644
--- a/chromium/ui/gl/gl_stub_autogen_gl.h
+++ b/chromium/ui/gl/gl_stub_autogen_gl.h
@@ -880,6 +880,26 @@ void glMaxShaderCompilerThreadsKHRFn(GLuint count) override {}
void glMemoryBarrierByRegionFn(GLbitfield barriers) override {}
void glMemoryBarrierEXTFn(GLbitfield barriers) override {}
void glMinSampleShadingFn(GLfloat value) override {}
+void glMultiDrawArraysANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ GLsizei drawcount) override {}
+void glMultiDrawArraysInstancedANGLEFn(GLenum mode,
+ const GLint* firsts,
+ const GLsizei* counts,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) override {}
+void glMultiDrawElementsANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ GLsizei drawcount) override {}
+void glMultiDrawElementsInstancedANGLEFn(GLenum mode,
+ const GLsizei* counts,
+ GLenum type,
+ const GLvoid* const* indices,
+ const GLsizei* instanceCounts,
+ GLsizei drawcount) override {}
void glObjectLabelFn(GLenum identifier,
GLuint name,
GLsizei length,
diff --git a/chromium/ui/gl/gl_surface_egl.cc b/chromium/ui/gl/gl_surface_egl.cc
index bb5e68bc4ff..c447ed27b13 100644
--- a/chromium/ui/gl/gl_surface_egl.cc
+++ b/chromium/ui/gl/gl_surface_egl.cc
@@ -18,7 +18,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "ui/gfx/geometry/rect.h"
@@ -150,13 +150,13 @@ bool g_egl_surface_orientation_supported = false;
bool g_egl_context_priority_supported = false;
bool g_egl_khr_colorspace = false;
bool g_egl_ext_colorspace_display_p3 = false;
-bool g_use_direct_composition = false;
+bool g_egl_flexible_surface_compatibility_supported = false;
bool g_egl_robust_resource_init_supported = false;
bool g_egl_display_texture_share_group_supported = false;
bool g_egl_create_context_client_arrays_supported = false;
bool g_egl_android_native_fence_sync_supported = false;
-const char kSwapEventTraceCategories[] = "gpu";
+constexpr const char kSwapEventTraceCategories[] = "gpu";
constexpr size_t kMaxTimestampsSupportable = 9;
@@ -598,8 +598,13 @@ void GetEGLInitDisplays(bool supports_angle_d3d,
if (supports_angle_opengl) {
if (use_angle_default && !supports_angle_d3d) {
+#if defined(OS_ANDROID)
+ // Don't request desktopGL on android
+ AddInitDisplay(init_displays, ANGLE_OPENGLES);
+#else
AddInitDisplay(init_displays, ANGLE_OPENGL);
AddInitDisplay(init_displays, ANGLE_OPENGLES);
+#endif
} else {
if (requested_renderer == kANGLEImplementationOpenGLName) {
AddInitDisplay(init_displays, ANGLE_OPENGL);
@@ -681,8 +686,7 @@ bool GLSurfaceEGL::InitializeOneOffCommon() {
HasEGLExtension("EGL_CHROMIUM_create_context_bind_generates_resource");
g_egl_create_context_webgl_compatability_supported =
HasEGLExtension("EGL_ANGLE_create_context_webgl_compatibility");
- g_egl_sync_control_supported =
- HasEGLExtension("EGL_CHROMIUM_sync_control");
+ g_egl_sync_control_supported = HasEGLExtension("EGL_CHROMIUM_sync_control");
g_egl_window_fixed_size_supported =
HasEGLExtension("EGL_ANGLE_window_fixed_size");
g_egl_surface_orientation_supported =
@@ -704,15 +708,9 @@ bool GLSurfaceEGL::InitializeOneOffCommon() {
#if defined(OS_WIN)
// Need EGL_ANGLE_flexible_surface_compatibility to allow surfaces with and
- // without alpha to be bound to the same context. Blacklist direct composition
- // if MCTU.dll or MCTUX.dll are injected. These are user mode drivers for
- // display adapters from Magic Control Technology Corporation.
- g_use_direct_composition =
- HasEGLExtension("EGL_ANGLE_direct_composition") &&
- HasEGLExtension("EGL_ANGLE_flexible_surface_compatibility") &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableDirectComposition) &&
- !GetModuleHandle(TEXT("MCTU.dll")) && !GetModuleHandle(TEXT("MCTUX.dll"));
+ // without alpha to be bound to the same context.
+ g_egl_flexible_surface_compatibility_supported =
+ HasEGLExtension("EGL_ANGLE_flexible_surface_compatibility");
#endif
g_egl_display_texture_share_group_supported =
@@ -739,7 +737,7 @@ bool GLSurfaceEGL::InitializeOneOffCommon() {
scoped_refptr<GLSurface> surface = new SurfacelessEGL(gfx::Size(1, 1));
scoped_refptr<GLContext> context = InitializeGLContext(
new GLContextEGL(nullptr), surface.get(), GLContextAttribs());
- if (!context->MakeCurrent(surface.get()))
+ if (!context || !context->MakeCurrent(surface.get()))
g_egl_surfaceless_context_supported = false;
// Ensure context supports GL_OES_surfaceless_context.
@@ -798,7 +796,6 @@ void GLSurfaceEGL::ShutdownOneOff() {
g_egl_sync_control_supported = false;
g_egl_window_fixed_size_supported = false;
g_egl_surface_orientation_supported = false;
- g_use_direct_composition = false;
g_egl_surfaceless_context_supported = false;
g_egl_robust_resource_init_supported = false;
g_egl_display_texture_share_group_supported = false;
@@ -851,8 +848,8 @@ bool GLSurfaceEGL::IsEGLContextPrioritySupported() {
}
// static
-bool GLSurfaceEGL::IsDirectCompositionSupported() {
- return g_use_direct_composition;
+bool GLSurfaceEGL::IsEGLFlexibleSurfaceCompatibilitySupported() {
+ return g_egl_flexible_surface_compatibility_supported;
}
bool GLSurfaceEGL::IsRobustResourceInitSupported() {
@@ -1023,14 +1020,6 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) {
egl_window_attributes.push_back(EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE);
}
- if (g_use_direct_composition) {
- egl_window_attributes.push_back(
- EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE);
- egl_window_attributes.push_back(EGL_TRUE);
- egl_window_attributes.push_back(EGL_DIRECT_COMPOSITION_ANGLE);
- egl_window_attributes.push_back(EGL_TRUE);
- }
-
switch (format_.GetColorSpace()) {
case GLSurfaceFormat::COLOR_SPACE_UNSPECIFIED:
break;
@@ -1407,10 +1396,6 @@ bool NativeViewGLSurfaceEGL::FlipsVertically() const {
return flips_vertically_;
}
-bool NativeViewGLSurfaceEGL::BuffersFlipped() const {
- return g_use_direct_composition;
-}
-
EGLTimestampClient* NativeViewGLSurfaceEGL::GetEGLTimestampClient() {
// This api call is used by GLSurfacePresentationHelper class which is member
// of this class NativeViewGLSurfaceEGL. Hence its guaranteed "this" pointer
@@ -1659,22 +1644,12 @@ bool PbufferGLSurfaceEGL::Initialize(GLSurfaceFormat format) {
// they have different addresses. If they have the same address then a
// future call to MakeCurrent might early out because it appears the current
// context and surface have not changed.
- std::vector<EGLint> pbuffer_attribs;
- pbuffer_attribs.push_back(EGL_WIDTH);
- pbuffer_attribs.push_back(size_.width());
- pbuffer_attribs.push_back(EGL_HEIGHT);
- pbuffer_attribs.push_back(size_.height());
-
- if (g_use_direct_composition) {
- pbuffer_attribs.push_back(
- EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE);
- pbuffer_attribs.push_back(EGL_TRUE);
- }
-
- pbuffer_attribs.push_back(EGL_NONE);
+ EGLint pbuffer_attribs[] = {
+ EGL_WIDTH, size_.width(), EGL_HEIGHT, size_.height(), EGL_NONE,
+ };
EGLSurface new_surface =
- eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]);
+ eglCreatePbufferSurface(display, GetConfig(), pbuffer_attribs);
if (!new_surface) {
LOG(ERROR) << "eglCreatePbufferSurface failed with error "
<< GetLastEGLErrorString();
diff --git a/chromium/ui/gl/gl_surface_egl.h b/chromium/ui/gl/gl_surface_egl.h
index 3d44351cecb..5f740e31ece 100644
--- a/chromium/ui/gl/gl_surface_egl.h
+++ b/chromium/ui/gl/gl_surface_egl.h
@@ -85,7 +85,7 @@ class GL_EXPORT GLSurfaceEGL : public GLSurface {
static bool IsCreateContextWebGLCompatabilitySupported();
static bool IsEGLSurfacelessContextSupported();
static bool IsEGLContextPrioritySupported();
- static bool IsDirectCompositionSupported();
+ static bool IsEGLFlexibleSurfaceCompatibilitySupported();
static bool IsRobustResourceInitSupported();
static bool IsDisplayTextureShareGroupSupported();
static bool IsCreateContextClientArraysSupported();
@@ -145,7 +145,6 @@ class GL_EXPORT NativeViewGLSurfaceEGL : public GLSurfaceEGL,
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) override;
bool FlipsVertically() const override;
- bool BuffersFlipped() const override;
EGLTimestampClient* GetEGLTimestampClient() override;
// EGLTimestampClient implementation.
diff --git a/chromium/ui/gl/gl_surface_egl_surface_control.cc b/chromium/ui/gl/gl_surface_egl_surface_control.cc
index 4a7cbb99290..8eaaf175635 100644
--- a/chromium/ui/gl/gl_surface_egl_surface_control.cc
+++ b/chromium/ui/gl/gl_surface_egl_surface_control.cc
@@ -4,6 +4,7 @@
#include "ui/gl/gl_surface_egl_surface_control.h"
+#include "base/android/android_hardware_buffer_compat.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gl/gl_fence_android_native_fence_sync.h"
@@ -12,16 +13,46 @@
namespace gl {
namespace {
-constexpr char kSurfaceName[] = "ChromeSurface";
+constexpr char kRootSurfaceName[] = "ChromeNativeWindowSurface";
+constexpr char kChildSurfaceName[] = "ChromeChildSurface";
-} // namespace
+gfx::Size GetBufferSize(const AHardwareBuffer* buffer) {
+ AHardwareBuffer_Desc desc;
+ base::AndroidHardwareBufferCompat::GetInstance().Describe(buffer, &desc);
+ return gfx::Size(desc.width, desc.height);
+}
-GLSurfaceEGLSurfaceControl::GLSurfaceEGLSurfaceControl(ANativeWindow* window) {
- surface_composer_ = SurfaceComposer::Create(window);
+struct TransactionAckCtx {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+ base::OnceCallback<void(int64_t)> callback;
+};
+
+// Note that the framework API states that this callback can be dispatched on
+// any thread (in practice it should be the binder thread), so we need to post
+// a task back to the GPU thread.
+void OnTransactionCompletedOnAnyThread(void* ctx, int64_t present_time_ns) {
+ auto* ack_ctx = static_cast<TransactionAckCtx*>(ctx);
+ ack_ctx->task_runner->PostTask(
+ FROM_HERE, base::BindOnce(std::move(ack_ctx->callback), present_time_ns));
+ delete ack_ctx;
}
+} // namespace
+
+GLSurfaceEGLSurfaceControl::GLSurfaceEGLSurfaceControl(
+ ANativeWindow* window,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : root_surface_(window, kRootSurfaceName),
+ gpu_task_runner_(std::move(task_runner)),
+ weak_factory_(this) {}
+
GLSurfaceEGLSurfaceControl::~GLSurfaceEGLSurfaceControl() = default;
+int GLSurfaceEGLSurfaceControl::GetBufferCount() const {
+ // Triple buffering to match framework's BufferQueue.
+ return 3;
+}
+
bool GLSurfaceEGLSurfaceControl::Initialize(GLSurfaceFormat format) {
format_ = format;
return true;
@@ -30,7 +61,7 @@ bool GLSurfaceEGLSurfaceControl::Initialize(GLSurfaceFormat format) {
void GLSurfaceEGLSurfaceControl::Destroy() {
pending_transaction_.reset();
surface_list_.clear();
- surface_composer_.reset();
+ root_surface_ = SurfaceControl::Surface();
}
bool GLSurfaceEGLSurfaceControl::Resize(const gfx::Size& size,
@@ -83,25 +114,25 @@ void GLSurfaceEGLSurfaceControl::CommitPendingTransaction(
current_frame_resources_.swap(pending_frame_resources_);
pending_frame_resources_.clear();
+ // Set up the callback to be notified when the frame is presented by the
+ // framework. Note that it is assumed that all GPU/display work for this frame
+ // is finished when the callback is dispatched, and all resources from the
+ // previous frame can be reused.
+ TransactionAckCtx* ack_ctx = new TransactionAckCtx;
+ ack_ctx->task_runner = gpu_task_runner_;
+ ack_ctx->callback =
+ base::BindOnce(&GLSurfaceEGLSurfaceControl::OnTransactionAckOnGpuThread,
+ weak_factory_.GetWeakPtr(), completion_callback,
+ present_callback, std::move(resources_to_release));
+ pending_transaction_->SetCompletedFunc(&OnTransactionCompletedOnAnyThread,
+ ack_ctx);
+
pending_transaction_->Apply();
pending_transaction_.reset();
DCHECK_GE(surface_list_.size(), pending_surfaces_count_);
surface_list_.resize(pending_surfaces_count_);
pending_surfaces_count_ = 0u;
-
- // TODO(khushalsagar): Send the legit timestamp when hooking up transaction
- // acks.
- constexpr int64_t kRefreshIntervalInMicroseconds =
- base::Time::kMicrosecondsPerSecond / 60;
- gfx::PresentationFeedback feedback(
- base::TimeTicks::Now(),
- base::TimeDelta::FromMicroseconds(kRefreshIntervalInMicroseconds),
- 0 /* flags */);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(OnTransactionAck, feedback, present_callback,
- completion_callback, std::move(resources_to_release)));
}
gfx::Size GLSurfaceEGLSurfaceControl::GetSize() {
@@ -120,13 +151,15 @@ bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane(
const gfx::RectF& crop_rect,
bool enable_blend,
std::unique_ptr<gfx::GpuFence> gpu_fence) {
+ DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE);
+
if (!pending_transaction_)
pending_transaction_.emplace();
bool uninitialized = false;
if (pending_surfaces_count_ == surface_list_.size()) {
uninitialized = true;
- surface_list_.emplace_back(surface_composer_.get());
+ surface_list_.emplace_back(root_surface_);
}
pending_surfaces_count_++;
auto& surface_state = surface_list_.at(pending_surfaces_count_ - 1);
@@ -136,11 +169,6 @@ bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane(
pending_transaction_->SetZOrder(surface_state.surface, z_order);
}
- if (uninitialized || surface_state.transform != transform) {
- surface_state.transform = transform;
- // TODO(khushalsagar): Forward the transform once the NDK API is in place.
- }
-
AHardwareBuffer* hardware_buffer = nullptr;
base::ScopedFD fence_fd;
auto scoped_hardware_buffer = image->GetAHardwareBuffer();
@@ -167,21 +195,24 @@ bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane(
if (uninitialized || surface_state.bounds_rect != bounds_rect) {
surface_state.bounds_rect = bounds_rect;
- pending_transaction_->SetPosition(surface_state.surface, bounds_rect.x(),
- bounds_rect.y());
- pending_transaction_->SetSize(surface_state.surface, bounds_rect.width(),
- bounds_rect.height());
+ pending_transaction_->SetDisplayFrame(surface_state.surface, bounds_rect);
}
- // TODO(khushalsagar): Currently the framework refuses to the draw the buffer
- // if the crop rect doesn't exactly match the buffer size. Update when fixed.
- /*gfx::Rect enclosed_crop_rect = gfx::ToEnclosedRect(crop_rect);
- if (uninitialized || surface_state.crop_rect != enclosed_crop_rect) {
- surface_state.crop_rect = enclosed_crop_rect;
- pending_transaction_->SetCropRect(
- surface_state.surface, enclosed_crop_rect.x(), enclosed_crop_rect.y(),
- enclosed_crop_rect.right(), enclosed_crop_rect.bottom());
- }*/
+ gfx::Rect enclosed_crop_rect;
+ if (hardware_buffer) {
+ gfx::Size buffer_size = GetBufferSize(hardware_buffer);
+ gfx::RectF scaled_rect =
+ gfx::RectF(crop_rect.x() * buffer_size.width(),
+ crop_rect.y() * buffer_size.height(),
+ crop_rect.width() * buffer_size.width(),
+ crop_rect.height() * buffer_size.height());
+ enclosed_crop_rect = gfx::ToEnclosedRect(scaled_rect);
+ if (uninitialized || surface_state.crop_rect != enclosed_crop_rect) {
+ surface_state.crop_rect = enclosed_crop_rect;
+ pending_transaction_->SetCropRect(surface_state.surface,
+ enclosed_crop_rect);
+ }
+ }
bool opaque = !enable_blend;
if (uninitialized || surface_state.opaque != opaque) {
@@ -221,22 +252,25 @@ bool GLSurfaceEGLSurfaceControl::SupportsCommitOverlayPlanes() {
return true;
}
-// static
-void GLSurfaceEGLSurfaceControl::OnTransactionAck(
- const gfx::PresentationFeedback& feedback,
- const PresentationCallback& present_callback,
- const SwapCompletionCallback& completion_callback,
- ResourceRefs resources) {
+void GLSurfaceEGLSurfaceControl::OnTransactionAckOnGpuThread(
+ SwapCompletionCallback completion_callback,
+ PresentationCallback presentation_callback,
+ ResourceRefs released_resources,
+ int64_t present_time_ns) {
+ DCHECK(gpu_task_runner_->BelongsToCurrentThread());
+
+ // The presentation feedback callback must run after swap completion.
completion_callback.Run(gfx::SwapResult::SWAP_ACK, nullptr);
- present_callback.Run(feedback);
- resources.clear();
+ gfx::PresentationFeedback feedback(
+ base::TimeTicks::FromInternalValue(present_time_ns), base::TimeDelta(),
+ 0 /* flags */);
+ presentation_callback.Run(feedback);
+ released_resources.clear();
}
GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState(
- SurfaceComposer* composer)
- : surface(composer,
- SurfaceComposer::SurfaceContentType::kAHardwareBuffer,
- kSurfaceName) {}
+ const SurfaceControl::Surface& parent)
+ : surface(parent, kChildSurfaceName) {}
GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState() = default;
GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState(SurfaceState&& other) =
diff --git a/chromium/ui/gl/gl_surface_egl_surface_control.h b/chromium/ui/gl/gl_surface_egl_surface_control.h
index dcfea68b7e7..7c73fb35326 100644
--- a/chromium/ui/gl/gl_surface_egl_surface_control.h
+++ b/chromium/ui/gl/gl_surface_egl_surface_control.h
@@ -10,17 +10,24 @@
#include "base/android/scoped_hardware_buffer_handle.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "ui/gl/android/android_surface_composer_compat.h"
+#include "ui/gl/android/android_surface_control_compat.h"
#include "ui/gl/gl_export.h"
#include "ui/gl/gl_surface_egl.h"
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
namespace gl {
class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
public:
- explicit GLSurfaceEGLSurfaceControl(ANativeWindow* window);
+ explicit GLSurfaceEGLSurfaceControl(
+ ANativeWindow* window,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// GLSurface implementation.
+ int GetBufferCount() const override;
bool Initialize(gl::GLSurfaceFormat format) override;
void Destroy() override;
bool Resize(const gfx::Size& size,
@@ -60,20 +67,19 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
struct SurfaceState {
SurfaceState();
- explicit SurfaceState(gl::SurfaceComposer* composer);
+ explicit SurfaceState(const SurfaceControl::Surface& parent);
~SurfaceState();
SurfaceState(SurfaceState&& other);
SurfaceState& operator=(SurfaceState&& other);
int z_order = 0;
- gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_INVALID;
AHardwareBuffer* hardware_buffer = nullptr;
gfx::Rect bounds_rect;
gfx::Rect crop_rect;
bool opaque = true;
- gl::SurfaceComposer::Surface surface;
+ gl::SurfaceControl::Surface surface;
};
using ResourceRefs =
@@ -83,14 +89,15 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
const SwapCompletionCallback& completion_callback,
const PresentationCallback& callback);
- static void OnTransactionAck(
- const gfx::PresentationFeedback& feedback,
- const PresentationCallback& present_callback,
- const SwapCompletionCallback& completion_callback,
- ResourceRefs resources);
+ // Called on the |gpu_task_runner_| when a transaction is acked by the
+ // framework.
+ void OnTransactionAckOnGpuThread(SwapCompletionCallback completion_callback,
+ PresentationCallback presentation_callback,
+ ResourceRefs released_resources,
+ int64_t present_time_ns);
// Holds the surface state changes made since the last call to SwapBuffers.
- base::Optional<gl::SurfaceComposer::Transaction> pending_transaction_;
+ base::Optional<gl::SurfaceControl::Transaction> pending_transaction_;
// The list of Surfaces and the corresponding state. The initial
// |pending_surfaces_count_| surfaces in this list are surfaces with state
@@ -113,7 +120,12 @@ class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
// frame update.
ResourceRefs current_frame_resources_;
- std::unique_ptr<gl::SurfaceComposer> surface_composer_;
+ // The root surface tied to the ANativeWindow that places the content of this
+ // GLSurface in the java view tree.
+ gl::SurfaceControl::Surface root_surface_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
+ base::WeakPtrFactory<GLSurfaceEGLSurfaceControl> weak_factory_;
};
} // namespace gl
diff --git a/chromium/ui/gl/gl_switches.cc b/chromium/ui/gl/gl_switches.cc
index b45bb33322c..9626f9bf189 100644
--- a/chromium/ui/gl/gl_switches.cc
+++ b/chromium/ui/gl/gl_switches.cc
@@ -73,9 +73,6 @@ const char kUseGL[] = "use-gl";
// context will never be lost in any situations, say, a GPU reset.
const char kGpuNoContextLost[] = "gpu-no-context-lost";
-// Disables the use of DirectComposition to draw to the screen.
-const char kDisableDirectComposition[] = "disable-direct-composition";
-
// Flag used for Linux tests: for desktop GL bindings, try to load this GL
// library first, but fall back to regular library if loading fails.
const char kTestGLLib[] = "test-gl-lib";
@@ -101,6 +98,9 @@ const char kDisableGLExtensions[] = "disable-gl-extensions";
// Enables SwapBuffersWithBounds if it is supported.
const char kEnableSwapBuffersWithBounds[] = "enable-swap-buffers-with-bounds";
+// Disables DirectComposition surface.
+const char kDisableDirectComposition[] = "disable-direct-composition";
+
// Enables using DirectComposition layers, even if hardware overlays aren't
// supported.
const char kEnableDirectCompositionLayers[] =
@@ -114,7 +114,6 @@ const char kDisableDirectCompositionLayers[] =
// GpuProcessHost to the GPU Process. Add your switch to this list if you need
// to read it in the GPU process, else don't add it.
const char* const kGLSwitchesCopiedFromGpuProcessHost[] = {
- kDisableDirectComposition,
kDisableGpuVsync,
kDisableD3D11,
kDisableES3GLContext,
@@ -126,6 +125,7 @@ const char* const kGLSwitchesCopiedFromGpuProcessHost[] = {
kOverrideUseSoftwareGLForTests,
kUseANGLE,
kEnableSwapBuffersWithBounds,
+ kDisableDirectComposition,
kEnableDirectCompositionLayers,
kDisableDirectCompositionLayers,
};
diff --git a/chromium/ui/gl/gl_switches.h b/chromium/ui/gl/gl_switches.h
index 3dab7a1d4ce..2772ec87e08 100644
--- a/chromium/ui/gl/gl_switches.h
+++ b/chromium/ui/gl/gl_switches.h
@@ -46,7 +46,6 @@ GL_EXPORT extern const char kDisableGpuVsync[];
GL_EXPORT extern const char kEnableGPUServiceLogging[];
GL_EXPORT extern const char kEnableGPUServiceTracing[];
GL_EXPORT extern const char kGpuNoContextLost[];
-GL_EXPORT extern const char kDisableDirectComposition[];
GL_EXPORT extern const char kUseANGLE[];
GL_EXPORT extern const char kUseGL[];
@@ -55,6 +54,7 @@ GL_EXPORT extern const char kUseGpuInTests[];
GL_EXPORT extern const char kEnableSgiVideoSync[];
GL_EXPORT extern const char kDisableGLExtensions[];
GL_EXPORT extern const char kEnableSwapBuffersWithBounds[];
+GL_EXPORT extern const char kDisableDirectComposition[];
GL_EXPORT extern const char kEnableDirectCompositionLayers[];
GL_EXPORT extern const char kDisableDirectCompositionLayers[];
diff --git a/chromium/ui/gl/gl_version_info.h b/chromium/ui/gl/gl_version_info.h
index 19dce397c8e..a84f55d656b 100644
--- a/chromium/ui/gl/gl_version_info.h
+++ b/chromium/ui/gl/gl_version_info.h
@@ -42,6 +42,12 @@ struct GL_EXPORT GLVersionInfo {
return is_es || IsAtLeastGL(4, 1);
}
+ // We need to emulate GL_ALPHA and GL_LUMINANCE and GL_LUMINANCE_ALPHA
+ // texture formats on core profile and ES3, except for ANGLE and Swiftshader.
+ bool NeedsLuminanceAlphaEmulation() const {
+ return !is_angle && !is_swiftshader && (is_es3 || is_desktop_core_profile);
+ }
+
bool is_es;
bool is_angle;
bool is_d3d;
diff --git a/chromium/ui/gl/init/create_gr_gl_interface.cc b/chromium/ui/gl/init/create_gr_gl_interface.cc
index 598b98cdfd9..69512fb9cb6 100644
--- a/chromium/ui/gl/init/create_gr_gl_interface.cc
+++ b/chromium/ui/gl/init/create_gr_gl_interface.cc
@@ -125,6 +125,7 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fBindFragDataLocation = gl->glBindFragDataLocationFn;
functions->fBindUniformLocation = gl->glBindUniformLocationCHROMIUMFn;
functions->fBeginQuery = gl->glBeginQueryFn;
+ functions->fBindSampler = gl->glBindSamplerFn;
functions->fBindTexture = gl->glBindTextureFn;
functions->fBlendBarrier = gl->glBlendBarrierKHRFn;
@@ -159,6 +160,7 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fDeleteProgram =
bind_slow(gl->glDeleteProgramFn, progress_reporter);
functions->fDeleteQueries = gl->glDeleteQueriesFn;
+ functions->fDeleteSamplers = gl->glDeleteSamplersFn;
functions->fDeleteShader = bind_slow(gl->glDeleteShaderFn, progress_reporter);
functions->fDeleteTextures = gl->glDeleteTexturesFn;
functions->fDepthMask = gl->glDepthMaskFn;
@@ -205,6 +207,7 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fGetShaderPrecisionFormat = gl->glGetShaderPrecisionFormatFn;
functions->fGetTexLevelParameteriv = gl->glGetTexLevelParameterivFn;
functions->fGenQueries = gl->glGenQueriesFn;
+ functions->fGenSamplers = gl->glGenSamplersFn;
functions->fGenTextures = gl->glGenTexturesFn;
functions->fGetUniformLocation = gl->glGetUniformLocationFn;
functions->fIsTexture = gl->glIsTextureFn;
@@ -226,6 +229,8 @@ sk_sp<GrGLInterface> CreateGrGLInterface(
functions->fReadBuffer = gl->glReadBufferFn;
functions->fReadPixels = gl->glReadPixelsFn;
+ functions->fSamplerParameteri = gl->glSamplerParameteriFn;
+ functions->fSamplerParameteriv = gl->glSamplerParameterivFn;
functions->fScissor = gl->glScissorFn;
functions->fShaderSource = gl->glShaderSourceFn;
functions->fStencilFunc = gl->glStencilFuncFn;
diff --git a/chromium/ui/gl/trace_util.cc b/chromium/ui/gl/trace_util.cc
index 45a8dfafd52..fc41b0412f8 100644
--- a/chromium/ui/gl/trace_util.cc
+++ b/chromium/ui/gl/trace_util.cc
@@ -18,9 +18,9 @@ base::trace_event::MemoryAllocatorDumpGuid GetGLTextureClientGUIDForTracing(
}
base::trace_event::MemoryAllocatorDumpGuid GetGLTextureServiceGUIDForTracing(
- uint32_t texture_id) {
- return base::trace_event::MemoryAllocatorDumpGuid(
- base::StringPrintf("gl-texture-service-x-process/%d", texture_id));
+ uint64_t texture_tracing_id) {
+ return base::trace_event::MemoryAllocatorDumpGuid(base::StringPrintf(
+ "gl-texture-service-x-process/%" PRIx64, texture_tracing_id));
}
base::trace_event::MemoryAllocatorDumpGuid GetGLBufferGUIDForTracing(
diff --git a/chromium/ui/gl/trace_util.h b/chromium/ui/gl/trace_util.h
index 2284c6153b2..e20a04785b6 100644
--- a/chromium/ui/gl/trace_util.h
+++ b/chromium/ui/gl/trace_util.h
@@ -21,7 +21,7 @@ GetGLRenderbufferGUIDForTracing(uint64_t context_group_tracing_id,
uint32_t renderbuffer_id);
GL_EXPORT base::trace_event::MemoryAllocatorDumpGuid
-GetGLTextureServiceGUIDForTracing(uint32_t texture_service_id);
+GetGLTextureServiceGUIDForTracing(uint64_t texture_tracing_id);
GL_EXPORT base::trace_event::MemoryAllocatorDumpGuid GetGLBufferGUIDForTracing(
uint64_t context_group_tracing_id,
diff --git a/chromium/ui/keyboard/BUILD.gn b/chromium/ui/keyboard/BUILD.gn
index f478b0b0910..e35899dce89 100644
--- a/chromium/ui/keyboard/BUILD.gn
+++ b/chromium/ui/keyboard/BUILD.gn
@@ -13,6 +13,7 @@ assert(is_chromeos)
jumbo_component("keyboard") {
sources = [
+ "container_behavior.cc",
"container_behavior.h",
"container_floating_behavior.cc",
"container_floating_behavior.h",
@@ -32,10 +33,6 @@ jumbo_component("keyboard") {
"keyboard_layout_delegate.h",
"keyboard_layout_manager.cc",
"keyboard_layout_manager.h",
- "keyboard_resource_util.cc",
- "keyboard_resource_util.h",
- "keyboard_switches.cc",
- "keyboard_switches.h",
"keyboard_ui.cc",
"keyboard_ui.h",
"keyboard_ukm_recorder.cc",
@@ -44,10 +41,14 @@ jumbo_component("keyboard") {
"keyboard_util.h",
"notification_manager.cc",
"notification_manager.h",
+ "public/keyboard_switches.cc",
+ "public/keyboard_switches.h",
"queued_container_type.cc",
"queued_container_type.h",
"queued_display_change.cc",
"queued_display_change.h",
+ "resources/keyboard_resource_util.cc",
+ "resources/keyboard_resource_util.h",
"shaped_window_targeter.cc",
"shaped_window_targeter.h",
]
@@ -93,6 +94,7 @@ static_library("test_support") {
"//ui/aura",
"//ui/aura:test_support",
"//ui/base:test_support",
+ "//ui/display",
]
}
@@ -133,15 +135,13 @@ copy("resources") {
build_closure("inputview") {
sources = inputview_sources
target = "$target_gen_dir/resources/inputview.js"
- json_file = "//third_party/google_input_tools/inputview.gypi"
- sources += [ json_file ]
- json_sources = "variables.inputview_sources"
path = rebase_path("//third_party/google_input_tools")
}
mojom("mojom") {
sources = [
"public/keyboard_config.mojom",
+ "public/keyboard_controller_types.mojom",
]
}
diff --git a/chromium/ui/keyboard/OWNERS b/chromium/ui/keyboard/OWNERS
index 0bbe8d1ba2f..f0bcea4da1d 100644
--- a/chromium/ui/keyboard/OWNERS
+++ b/chromium/ui/keyboard/OWNERS
@@ -1,4 +1,4 @@
-blakeo@chromium.org
+googleo@chromium.org
shend@chromium.org
shuchen@chromium.org
wuyingbing@chromium.org
diff --git a/chromium/ui/keyboard/container_behavior.cc b/chromium/ui/keyboard/container_behavior.cc
new file mode 100644
index 00000000000..e5ad95f75e2
--- /dev/null
+++ b/chromium/ui/keyboard/container_behavior.cc
@@ -0,0 +1,14 @@
+// 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/keyboard/container_behavior.h"
+
+namespace keyboard {
+
+ContainerBehavior::ContainerBehavior(Delegate* delegate)
+ : delegate_(delegate) {}
+
+ContainerBehavior::~ContainerBehavior() = default;
+
+} // namespace keyboard
diff --git a/chromium/ui/keyboard/container_behavior.h b/chromium/ui/keyboard/container_behavior.h
index 3d5eee9e320..41b2ffd3c30 100644
--- a/chromium/ui/keyboard/container_behavior.h
+++ b/chromium/ui/keyboard/container_behavior.h
@@ -5,12 +5,24 @@
#ifndef UI_KEYBOARD_CONTAINER_BEHAVIOR_H_
#define UI_KEYBOARD_CONTAINER_BEHAVIOR_H_
-#include "ui/aura/window.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
-#include "ui/keyboard/container_type.h"
+#include "ui/display/display.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
#include "ui/keyboard/keyboard_export.h"
-#include "ui/wm/core/window_animations.h"
+#include "ui/keyboard/public/keyboard_controller_types.mojom.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+class LocatedEvent;
+class ScopedLayerAnimationSettings;
+} // namespace ui
+
+namespace wm {
+class ScopedHidingAnimationSettings;
+}
namespace keyboard {
@@ -18,7 +30,18 @@ namespace keyboard {
// within the workspace window.
class KEYBOARD_EXPORT ContainerBehavior {
public:
- virtual ~ContainerBehavior() {}
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ virtual gfx::Rect GetBoundsInScreen() const = 0;
+ virtual bool IsKeyboardLocked() const = 0;
+ virtual void MoveKeyboardWindow(const gfx::Rect& new_bounds) = 0;
+ virtual void MoveKeyboardWindowToDisplay(const display::Display& display,
+ const gfx::Rect& new_bounds) = 0;
+ };
+
+ explicit ContainerBehavior(Delegate* delegate);
+ virtual ~ContainerBehavior();
// Apply changes to the animation settings to animate the keyboard container
// showing.
@@ -30,7 +53,7 @@ class KEYBOARD_EXPORT ContainerBehavior {
// hiding.
virtual void DoHidingAnimation(
aura::Window* window,
- ::wm::ScopedHidingAnimationSettings* animation_settings) = 0;
+ wm::ScopedHidingAnimationSettings* animation_settings) = 0;
// Initialize the starting state of the keyboard container for the showing
// animation.
@@ -67,7 +90,7 @@ class KEYBOARD_EXPORT ContainerBehavior {
virtual bool HandlePointerEvent(const ui::LocatedEvent& event,
const display::Display& current_display) = 0;
- virtual ContainerType GetType() const = 0;
+ virtual mojom::ContainerType GetType() const = 0;
// Removing focus from a text field should cause the keyboard to be dismissed.
virtual bool TextBlurHidesKeyboard() const = 0;
@@ -92,9 +115,11 @@ class KEYBOARD_EXPORT ContainerBehavior {
virtual bool OccludedBoundsAffectWorkspaceLayout() const = 0;
// Sets floating keyboard drggable rect.
- virtual bool SetDraggableArea(const gfx::Rect& rect) = 0;
+ virtual void SetDraggableArea(const gfx::Rect& rect) = 0;
protected:
+ Delegate* delegate_;
+
// The opacity of virtual keyboard container when show animation
// starts or hide animation finishes. This cannot be zero because we
// call Show() on the keyboard window before setting the opacity
diff --git a/chromium/ui/keyboard/container_floating_behavior.cc b/chromium/ui/keyboard/container_floating_behavior.cc
index 91815b86655..a3b5e5b087d 100644
--- a/chromium/ui/keyboard/container_floating_behavior.cc
+++ b/chromium/ui/keyboard/container_floating_behavior.cc
@@ -4,14 +4,15 @@
#include "ui/keyboard/container_floating_behavior.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/display/display.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/keyboard/container_type.h"
+#include "ui/keyboard/display_util.h"
#include "ui/keyboard/drag_descriptor.h"
-#include "ui/keyboard/keyboard_controller.h"
-#include "ui/keyboard/keyboard_ui.h"
+#include "ui/wm/core/window_animations.h"
namespace keyboard {
@@ -21,14 +22,13 @@ constexpr int kAnimationDurationMs = 200;
// Distance the keyboard moves during the animation
constexpr int kAnimationDistance = 30;
-ContainerFloatingBehavior::ContainerFloatingBehavior(
- KeyboardController* controller) {
- controller_ = controller;
-}
-ContainerFloatingBehavior::~ContainerFloatingBehavior() {}
+ContainerFloatingBehavior::ContainerFloatingBehavior(Delegate* delegate)
+ : ContainerBehavior(delegate) {}
+
+ContainerFloatingBehavior::~ContainerFloatingBehavior() = default;
-ContainerType ContainerFloatingBehavior::GetType() const {
- return ContainerType::FLOATING;
+mojom::ContainerType ContainerFloatingBehavior::GetType() const {
+ return mojom::ContainerType::kFloating;
}
void ContainerFloatingBehavior::DoHidingAnimation(
@@ -186,13 +186,9 @@ bool ContainerFloatingBehavior::IsDragHandle(
bool ContainerFloatingBehavior::HandlePointerEvent(
const ui::LocatedEvent& event,
const display::Display& current_display) {
- // Cannot call UI-backed operations without a KeyboardController
- DCHECK(controller_);
auto kb_offset = gfx::Vector2d(event.x(), event.y());
- aura::Window* contents = controller_->GetKeyboardWindow();
-
- const gfx::Rect& keyboard_bounds_in_screen = contents->GetBoundsInScreen();
+ const gfx::Rect& keyboard_bounds_in_screen = delegate_->GetBoundsInScreen();
// Don't handle events if this runs in a partially initialized state.
if (keyboard_bounds_in_screen.height() <= 0)
@@ -257,7 +253,7 @@ bool ContainerFloatingBehavior::HandlePointerEvent(
current_display, current_drag_location);
if (current_display.id() == new_display.id()) {
- controller_->MoveKeyboard(new_bounds_in_local);
+ delegate_->MoveKeyboardWindow(new_bounds_in_local);
} else {
// Since the keyboard has jumped across screens, cancel the current
// drag descriptor as though the user has lifted their finger.
@@ -274,10 +270,10 @@ bool ContainerFloatingBehavior::HandlePointerEvent(
new_bounds_in_local =
contained_new_bounds_in_screen -
new_display.bounds().origin().OffsetFromOrigin();
- controller_->MoveToDisplayWithTransition(new_display,
- new_bounds_in_local);
+ delegate_->MoveKeyboardWindowToDisplay(new_display,
+ new_bounds_in_local);
}
- SavePosition(contents->GetBoundsInScreen(), new_display.size());
+ SavePosition(delegate_->GetBoundsInScreen(), new_display.size());
return true;
}
break;
@@ -313,9 +309,8 @@ bool ContainerFloatingBehavior::OccludedBoundsAffectWorkspaceLayout() const {
return false;
}
-bool ContainerFloatingBehavior::SetDraggableArea(const gfx::Rect& rect) {
+void ContainerFloatingBehavior::SetDraggableArea(const gfx::Rect& rect) {
draggable_area_ = rect;
- return true;
}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/container_floating_behavior.h b/chromium/ui/keyboard/container_floating_behavior.h
index ada21722bab..41a11d36ffb 100644
--- a/chromium/ui/keyboard/container_floating_behavior.h
+++ b/chromium/ui/keyboard/container_floating_behavior.h
@@ -5,16 +5,11 @@
#ifndef UI_KEYBOARD_CONTAINER_FLOATING_BEHAVIOR_H_
#define UI_KEYBOARD_CONTAINER_FLOATING_BEHAVIOR_H_
-#include "ui/aura/window.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/keyboard/container_behavior.h"
-#include "ui/keyboard/container_type.h"
#include "ui/keyboard/drag_descriptor.h"
-#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_export.h"
-#include "ui/wm/core/window_animations.h"
namespace keyboard {
@@ -23,14 +18,9 @@ namespace keyboard {
constexpr int kDefaultDistanceFromScreenBottom = 20;
constexpr int kDefaultDistanceFromScreenRight = 20;
-struct KeyboardPosition {
- double left_padding_allotment_ratio;
- double top_padding_allotment_ratio;
-};
-
class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
public:
- ContainerFloatingBehavior(KeyboardController* controller);
+ explicit ContainerFloatingBehavior(Delegate* delegate);
~ContainerFloatingBehavior() override;
// ContainerBehavior overrides
@@ -53,12 +43,12 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
const display::Display& current_display) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
- ContainerType GetType() const override;
+ mojom::ContainerType GetType() const override;
bool TextBlurHidesKeyboard() const override;
gfx::Rect GetOccludedBounds(
const gfx::Rect& visual_bounds_in_screen) const override;
bool OccludedBoundsAffectWorkspaceLayout() const override;
- bool SetDraggableArea(const gfx::Rect& rect) override;
+ void SetDraggableArea(const gfx::Rect& rect) override;
// Calculate the position of the keyboard for when it is being shown.
gfx::Point GetPositionForShowingKeyboard(
@@ -66,6 +56,11 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
const gfx::Rect& display_bounds) const;
private:
+ struct KeyboardPosition {
+ double left_padding_allotment_ratio;
+ double top_padding_allotment_ratio;
+ };
+
// Ensures that the keyboard is neither off the screen nor overlapping an
// edge.
gfx::Rect ContainKeyboardToScreenBounds(
@@ -75,15 +70,12 @@ class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
// Saves the current keyboard location for use the next time it is displayed.
void UpdateLastPoint(const gfx::Point& position);
- KeyboardController* controller_;
-
// TODO(blakeo): cache the default_position_ on a per-display basis.
- std::unique_ptr<struct keyboard::KeyboardPosition>
- default_position_in_screen_ = nullptr;
+ std::unique_ptr<KeyboardPosition> default_position_in_screen_;
// Current state of a cursor drag to move the keyboard, if one exists.
// Otherwise nullptr.
- std::unique_ptr<const DragDescriptor> drag_descriptor_ = nullptr;
+ std::unique_ptr<const DragDescriptor> drag_descriptor_;
gfx::Rect draggable_area_ = gfx::Rect();
};
diff --git a/chromium/ui/keyboard/container_full_width_behavior.cc b/chromium/ui/keyboard/container_full_width_behavior.cc
index 63e42bf74c4..2e117a6321a 100644
--- a/chromium/ui/keyboard/container_full_width_behavior.cc
+++ b/chromium/ui/keyboard/container_full_width_behavior.cc
@@ -6,8 +6,7 @@
#include "ui/aura/window.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/keyboard/container_type.h"
-#include "ui/keyboard/keyboard_controller.h"
+#include "ui/gfx/transform.h"
#include "ui/wm/core/window_animations.h"
namespace keyboard {
@@ -15,14 +14,13 @@ namespace keyboard {
// The virtual keyboard show/hide animation duration.
constexpr int kFullWidthKeyboardAnimationDurationMs = 100;
-ContainerFullWidthBehavior::ContainerFullWidthBehavior(
- KeyboardController* controller) {
- controller_ = controller;
-}
+ContainerFullWidthBehavior::ContainerFullWidthBehavior(Delegate* delegate)
+ : ContainerBehavior(delegate) {}
+
ContainerFullWidthBehavior::~ContainerFullWidthBehavior() {}
-ContainerType ContainerFullWidthBehavior::GetType() const {
- return ContainerType::FULL_WIDTH;
+mojom::ContainerType ContainerFullWidthBehavior::GetType() const {
+ return mojom::ContainerType::kFullWidth;
}
void ContainerFullWidthBehavior::DoHidingAnimation(
@@ -79,7 +77,7 @@ gfx::Rect ContainerFullWidthBehavior::AdjustSetBoundsRequest(
bool ContainerFullWidthBehavior::IsOverscrollAllowed() const {
// TODO(blakeo): The locked keyboard is essentially its own behavior type and
// should be refactored as such. Then this will simply return 'true'.
- return controller_ && !controller_->keyboard_locked();
+ return delegate_ && !delegate_->IsKeyboardLocked();
}
void ContainerFullWidthBehavior::SavePosition(const gfx::Rect& keyboard_bounds,
@@ -109,7 +107,7 @@ void ContainerFullWidthBehavior::SetCanonicalBounds(
}
bool ContainerFullWidthBehavior::TextBlurHidesKeyboard() const {
- return !controller_->keyboard_locked();
+ return !delegate_->IsKeyboardLocked();
}
void ContainerFullWidthBehavior::SetOccludedBounds(
@@ -125,14 +123,11 @@ gfx::Rect ContainerFullWidthBehavior::GetOccludedBounds(
}
bool ContainerFullWidthBehavior::OccludedBoundsAffectWorkspaceLayout() const {
- return controller_->keyboard_locked();
+ return delegate_->IsKeyboardLocked();
}
-bool ContainerFullWidthBehavior::SetDraggableArea(const gfx::Rect& rect) {
+void ContainerFullWidthBehavior::SetDraggableArea(const gfx::Rect& rect) {
// Allow extension to call this function but does nothing here.
- // To avoid unnecessary exception when VK calls this function to
- // clear draggable area in full width mode.
- return true;
}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/container_full_width_behavior.h b/chromium/ui/keyboard/container_full_width_behavior.h
index b11e487f7b9..8e82a5032d3 100644
--- a/chromium/ui/keyboard/container_full_width_behavior.h
+++ b/chromium/ui/keyboard/container_full_width_behavior.h
@@ -5,14 +5,8 @@
#ifndef UI_KEYBOARD_CONTAINER_FULL_WIDTH_BEHAVIOR_H_
#define UI_KEYBOARD_CONTAINER_FULL_WIDTH_BEHAVIOR_H_
-#include "ui/aura/window.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/keyboard/container_behavior.h"
-#include "ui/keyboard/container_type.h"
-#include "ui/keyboard/keyboard_controller.h"
-#include "ui/keyboard/keyboard_export.h"
-#include "ui/wm/core/window_animations.h"
namespace keyboard {
@@ -22,7 +16,7 @@ constexpr int kFullWidthKeyboardAnimationDistance = 30;
class KEYBOARD_EXPORT ContainerFullWidthBehavior : public ContainerBehavior {
public:
- ContainerFullWidthBehavior(KeyboardController* controller);
+ explicit ContainerFullWidthBehavior(Delegate* delegate);
~ContainerFullWidthBehavior() override;
// ContainerBehavior overrides
@@ -45,17 +39,16 @@ class KEYBOARD_EXPORT ContainerFullWidthBehavior : public ContainerBehavior {
const display::Display& current_display) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
- ContainerType GetType() const override;
+ mojom::ContainerType GetType() const override;
bool TextBlurHidesKeyboard() const override;
void SetOccludedBounds(const gfx::Rect& occluded_bounds_in_window) override;
gfx::Rect GetOccludedBounds(
const gfx::Rect& visual_bounds_in_screen) const override;
bool OccludedBoundsAffectWorkspaceLayout() const override;
- bool SetDraggableArea(const gfx::Rect& rect) override;
+ void SetDraggableArea(const gfx::Rect& rect) override;
private:
gfx::Rect occluded_bounds_in_window_;
- KeyboardController* controller_;
};
} // namespace keyboard
diff --git a/chromium/ui/keyboard/container_fullscreen_behavior.cc b/chromium/ui/keyboard/container_fullscreen_behavior.cc
index 339355155d2..78344132fd6 100644
--- a/chromium/ui/keyboard/container_fullscreen_behavior.cc
+++ b/chromium/ui/keyboard/container_fullscreen_behavior.cc
@@ -4,11 +4,12 @@
#include "ui/keyboard/container_fullscreen_behavior.h"
+#include "ui/aura/window.h"
+
namespace keyboard {
-ContainerFullscreenBehavior::ContainerFullscreenBehavior(
- KeyboardController* controller)
- : ContainerFullWidthBehavior(controller) {}
+ContainerFullscreenBehavior::ContainerFullscreenBehavior(Delegate* delegate)
+ : ContainerFullWidthBehavior(delegate) {}
ContainerFullscreenBehavior::~ContainerFullscreenBehavior() {}
@@ -29,8 +30,8 @@ gfx::Rect ContainerFullscreenBehavior::GetOccludedBounds(
return occluded_bounds_;
}
-ContainerType ContainerFullscreenBehavior::GetType() const {
- return ContainerType::FULLSCREEN;
+mojom::ContainerType ContainerFullscreenBehavior::GetType() const {
+ return mojom::ContainerType::kFullscreen;
}
void ContainerFullscreenBehavior::SetOccludedBounds(
diff --git a/chromium/ui/keyboard/container_fullscreen_behavior.h b/chromium/ui/keyboard/container_fullscreen_behavior.h
index 7383043e366..51b4fedfb82 100644
--- a/chromium/ui/keyboard/container_fullscreen_behavior.h
+++ b/chromium/ui/keyboard/container_fullscreen_behavior.h
@@ -5,9 +5,7 @@
#ifndef UI_KEYBOARD_CONTAINER_FULLSCREEN_BEHAVIOR_H_
#define UI_KEYBOARD_CONTAINER_FULLSCREEN_BEHAVIOR_H_
-#include "ui/aura/window.h"
#include "ui/keyboard/container_full_width_behavior.h"
-#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_export.h"
namespace keyboard {
@@ -15,7 +13,7 @@ namespace keyboard {
class KEYBOARD_EXPORT ContainerFullscreenBehavior
: public ContainerFullWidthBehavior {
public:
- ContainerFullscreenBehavior(KeyboardController* controller);
+ explicit ContainerFullscreenBehavior(Delegate* controller);
~ContainerFullscreenBehavior() override;
// ContainerFullWidthBehavior overrides
@@ -24,7 +22,7 @@ class KEYBOARD_EXPORT ContainerFullscreenBehavior
const gfx::Rect& requested_bounds_in_screen_coords) override;
void SetCanonicalBounds(aura::Window* container,
const gfx::Rect& display_bounds) override;
- ContainerType GetType() const override;
+ mojom::ContainerType GetType() const override;
void SetOccludedBounds(const gfx::Rect& occluded_bounds_in_window) override;
gfx::Rect GetOccludedBounds(
const gfx::Rect& visual_bounds_in_screen) const override;
diff --git a/chromium/ui/keyboard/container_type.h b/chromium/ui/keyboard/container_type.h
deleted file mode 100644
index ff3462ddfd4..00000000000
--- a/chromium/ui/keyboard/container_type.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2017 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_KEYBOARD_CONTAINER_TYPE_H_
-#define UI_KEYBOARD_CONTAINER_TYPE_H_
-
-namespace keyboard {
-
-// Enum corresponding to the various container behaviors.
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class ContainerType {
-
- // Corresponds to a ContainerFullWidthBehavior.
- FULL_WIDTH = 0,
-
- // Corresponds to a ContainerFloatingBehavior.
- FLOATING = 1,
-
- // Corresponds to a ContainerFullscreenBehavior.
- FULLSCREEN = 2,
-
- COUNT,
-};
-
-} // namespace keyboard
-
-#endif // UI_KEYBOARD_CONTAINER_TYPE_H_
diff --git a/chromium/ui/keyboard/keyboard_controller.cc b/chromium/ui/keyboard/keyboard_controller.cc
index a2adfbf40c9..b0fe24186ac 100644
--- a/chromium/ui/keyboard/keyboard_controller.cc
+++ b/chromium/ui/keyboard/keyboard_controller.cc
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "ui/aura/client/aura_constants.h"
@@ -33,14 +34,13 @@
#include "ui/keyboard/container_floating_behavior.h"
#include "ui/keyboard/container_full_width_behavior.h"
#include "ui/keyboard/container_fullscreen_behavior.h"
-#include "ui/keyboard/container_type.h"
#include "ui/keyboard/display_util.h"
#include "ui/keyboard/keyboard_controller_observer.h"
#include "ui/keyboard/keyboard_layout_manager.h"
-#include "ui/keyboard/keyboard_switches.h"
#include "ui/keyboard/keyboard_ui.h"
#include "ui/keyboard/keyboard_util.h"
#include "ui/keyboard/notification_manager.h"
+#include "ui/keyboard/public/keyboard_switches.h"
#include "ui/keyboard/queued_container_type.h"
#include "ui/keyboard/queued_display_change.h"
#include "ui/keyboard/shaped_window_targeter.h"
@@ -149,6 +149,47 @@ void LogKeyboardControlEvent(KeyboardControlEvent event) {
KEYBOARD_CONTROL_MAX);
}
+class InputMethodKeyboardController : public ui::InputMethodKeyboardController {
+ public:
+ explicit InputMethodKeyboardController(
+ KeyboardController* keyboard_controller)
+ : keyboard_controller_(keyboard_controller) {}
+
+ ~InputMethodKeyboardController() override = default;
+
+ // ui::InputMethodKeyboardController
+ bool DisplayVirtualKeyboard() override {
+ // Calling |ShowKeyboardInternal| may move the keyboard to another display.
+ if (keyboard_controller_->IsKeyboardEnableRequested() &&
+ !keyboard_controller_->keyboard_locked()) {
+ keyboard_controller_->ShowKeyboard(false /* locked */);
+ return true;
+ }
+ return false;
+ }
+
+ void DismissVirtualKeyboard() override {
+ keyboard_controller_->HideKeyboardByUser();
+ }
+
+ void AddObserver(
+ ui::InputMethodKeyboardControllerObserver* observer) override {
+ // TODO: Implement.
+ }
+
+ void RemoveObserver(
+ ui::InputMethodKeyboardControllerObserver* observer) override {
+ // TODO: Implement.
+ }
+
+ bool IsKeyboardVisible() override {
+ return keyboard_controller_->IsKeyboardVisible();
+ }
+
+ private:
+ KeyboardController* keyboard_controller_;
+};
+
} // namespace
// Observer for both keyboard show and hide animations. It should be owned by
@@ -178,7 +219,9 @@ class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
};
KeyboardController::KeyboardController()
- : ime_observer_(this),
+ : input_method_keyboard_controller_(
+ std::make_unique<InputMethodKeyboardController>(this)),
+ ime_observer_(this),
weak_factory_report_lingering_state_(this),
weak_factory_will_hide_(this) {
DCHECK_EQ(g_keyboard_controller, nullptr);
@@ -216,11 +259,14 @@ void KeyboardController::EnableKeyboard(std::unique_ptr<KeyboardUI> ui,
keyboard_locked_ = false;
state_ = KeyboardControllerState::UNKNOWN;
ui_->SetController(this);
- SetContainerBehaviorInternal(ContainerType::FULL_WIDTH);
+ SetContainerBehaviorInternal(mojom::ContainerType::kFullWidth);
ChangeState(KeyboardControllerState::INITIAL);
visual_bounds_in_screen_ = gfx::Rect();
time_of_last_blur_ = base::Time::UnixEpoch();
UpdateInputMethodObserver();
+
+ for (KeyboardControllerObserver& observer : observer_list_)
+ observer.OnKeyboardEnabledChanged(true);
}
void KeyboardController::DisableKeyboard() {
@@ -230,6 +276,10 @@ void KeyboardController::DisableKeyboard() {
if (parent_container_)
DeactivateKeyboard();
+ aura::Window* keyboard_window = GetKeyboardWindow();
+ if (keyboard_window)
+ keyboard_window->RemoveObserver(this);
+
// Return to the INITIAL state to ensure that transitions entering a state
// is equal to transitions leaving the state.
if (state_ != KeyboardControllerState::INITIAL)
@@ -244,7 +294,7 @@ void KeyboardController::DisableKeyboard() {
ime_observer_.RemoveAll();
for (KeyboardControllerObserver& observer : observer_list_)
- observer.OnKeyboardDisabled();
+ observer.OnKeyboardEnabledChanged(false);
ui_->SetController(nullptr);
ui_.reset();
}
@@ -270,16 +320,20 @@ void KeyboardController::DeactivateKeyboard() {
// Ensure the keyboard is not visible before deactivating it.
HideKeyboardExplicitlyBySystem();
- if (GetKeyboardWindow() && GetKeyboardWindow()->parent()) {
- DCHECK_EQ(parent_container_, GetKeyboardWindow()->parent());
- parent_container_->RemoveChild(GetKeyboardWindow());
+ aura::Window* keyboard_window = GetKeyboardWindow();
+ if (keyboard_window) {
+ keyboard_window->RemovePreTargetHandler(&event_filter_);
+ if (keyboard_window->parent()) {
+ DCHECK_EQ(parent_container_, keyboard_window->parent());
+ parent_container_->RemoveChild(keyboard_window);
+ }
}
parent_container_->GetRootWindow()->RemoveObserver(this);
parent_container_ = nullptr;
}
aura::Window* KeyboardController::GetKeyboardWindow() const {
- return ui_ && ui_->HasKeyboardWindow() ? ui_->GetKeyboardWindow() : nullptr;
+ return ui_ ? ui_->GetKeyboardWindow() : nullptr;
}
aura::Window* KeyboardController::GetRootWindow() {
@@ -296,11 +350,6 @@ void KeyboardController::NotifyKeyboardBoundsChanging(
notification_manager_.SendNotifications(
container_behavior_->OccludedBoundsAffectWorkspaceLayout(), new_bounds,
occluded_bounds_in_screen, observer_list_);
-
- if (IsKeyboardOverscrollEnabled())
- ui_->InitInsets(occluded_bounds_in_screen);
- else
- ui_->ResetInsets();
} else {
visual_bounds_in_screen_ = gfx::Rect();
}
@@ -308,11 +357,6 @@ void KeyboardController::NotifyKeyboardBoundsChanging(
EnsureCaretInWorkArea(GetWorkspaceOccludedBounds());
}
-void KeyboardController::MoveKeyboard(const gfx::Rect& new_bounds) {
- DCHECK(IsKeyboardVisible());
- SetKeyboardWindowBounds(new_bounds);
-}
-
void KeyboardController::SetKeyboardWindowBounds(const gfx::Rect& new_bounds) {
ui::LayerAnimator* animator = GetKeyboardWindow()->layer()->GetAnimator();
// Stops previous animation if a window resize is requested during animation.
@@ -330,7 +374,7 @@ void KeyboardController::NotifyKeyboardWindowLoaded() {
// The window height is set to 0 initially or before switch to an IME in a
// different extension. Virtual keyboard window may wait for this bounds
// change to correctly animate in.
- if (keyboard_locked()) {
+ if (keyboard_locked_) {
// Do not move the keyboard to another display after switch to an IME in
// a different extension.
ShowKeyboardInDisplay(
@@ -364,27 +408,6 @@ void KeyboardController::RemoveObserver(KeyboardControllerObserver* observer) {
observer_list_.RemoveObserver(observer);
}
-ui::TextInputClient* KeyboardController::GetTextInputClient() {
- return ui_->GetInputMethod()->GetTextInputClient();
-}
-
-bool KeyboardController::InsertText(const base::string16& text) {
- if (!ui_)
- return false;
-
- ui::InputMethod* input_method = ui_->GetInputMethod();
- if (!input_method)
- return false;
-
- ui::TextInputClient* tic = input_method->GetTextInputClient();
- if (!tic || tic->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
- return false;
-
- tic->InsertText(text);
-
- return true;
-}
-
bool KeyboardController::UpdateKeyboardConfig(
const mojom::KeyboardConfig& config) {
if (config.Equals(keyboard_config_))
@@ -395,8 +418,75 @@ bool KeyboardController::UpdateKeyboardConfig(
return true;
}
+void KeyboardController::SetEnableFlag(mojom::KeyboardEnableFlag flag) {
+ if (!base::ContainsKey(keyboard_enable_flags_, flag))
+ keyboard_enable_flags_.insert(flag);
+
+ // If there is a flag that is mutually exclusive with |flag|, clear it.
+ using mojom::KeyboardEnableFlag;
+ switch (flag) {
+ case KeyboardEnableFlag::kPolicyEnabled:
+ keyboard_enable_flags_.erase(KeyboardEnableFlag::kPolicyDisabled);
+ break;
+ case KeyboardEnableFlag::kPolicyDisabled:
+ keyboard_enable_flags_.erase(KeyboardEnableFlag::kPolicyEnabled);
+ break;
+ case KeyboardEnableFlag::kExtensionEnabled:
+ keyboard_enable_flags_.erase(KeyboardEnableFlag::kExtensionDisabled);
+ break;
+ case KeyboardEnableFlag::kExtensionDisabled:
+ keyboard_enable_flags_.erase(KeyboardEnableFlag::kExtensionEnabled);
+ break;
+ default:
+ break;
+ }
+ for (KeyboardControllerObserver& observer : observer_list_)
+ observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
+}
+
+void KeyboardController::ClearEnableFlag(mojom::KeyboardEnableFlag flag) {
+ keyboard_enable_flags_.erase(flag);
+ for (KeyboardControllerObserver& observer : observer_list_)
+ observer.OnKeyboardEnableFlagsChanged(keyboard_enable_flags_);
+}
+
+bool KeyboardController::IsEnableFlagSet(mojom::KeyboardEnableFlag flag) const {
+ return base::ContainsKey(keyboard_enable_flags_, flag);
+}
+
+bool KeyboardController::IsKeyboardEnableRequested() const {
+ using mojom::KeyboardEnableFlag;
+ // Accessibility setting prioritized over policy/arc overrides.
+ if (IsEnableFlagSet(KeyboardEnableFlag::kAccessibilityEnabled))
+ return true;
+
+ // Keyboard can be enabled temporarily by the shelf.
+ if (IsEnableFlagSet(KeyboardEnableFlag::kShelfEnabled))
+ return true;
+
+ if (IsEnableFlagSet(KeyboardEnableFlag::kAndroidDisabled) ||
+ IsEnableFlagSet(KeyboardEnableFlag::kPolicyDisabled)) {
+ return false;
+ }
+ if (IsEnableFlagSet(KeyboardEnableFlag::kPolicyEnabled))
+ return true;
+
+ // Command line overrides extension and touch enabled flags.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableVirtualKeyboard)) {
+ return true;
+ }
+
+ if (IsEnableFlagSet(KeyboardEnableFlag::kExtensionDisabled))
+ return false;
+
+ return IsEnableFlagSet(KeyboardEnableFlag::kExtensionEnabled) ||
+ IsEnableFlagSet(KeyboardEnableFlag::kTouchEnabled) ||
+ IsEnableFlagSet(KeyboardEnableFlag::kTemporarilyEnabled);
+}
+
bool KeyboardController::IsKeyboardOverscrollEnabled() const {
- if (!keyboard::IsKeyboardEnabled())
+ if (!IsKeyboardEnableRequested())
return false;
// Users of the sticky accessibility on-screen keyboard are likely to be using
@@ -416,14 +506,6 @@ bool KeyboardController::IsKeyboardOverscrollEnabled() const {
switches::kDisableVirtualKeyboardOverscroll);
}
-void KeyboardController::MoveToDisplayWithTransition(
- display::Display display,
- gfx::Rect new_bounds_in_local) {
- queued_display_change_ =
- std::make_unique<QueuedDisplayChange>(display, new_bounds_in_local);
- HideKeyboardTemporarilyForTransition();
-}
-
// private
void KeyboardController::HideKeyboard(HideReason reason) {
TRACE_EVENT0("vk", "HideKeyboard");
@@ -492,6 +574,10 @@ void KeyboardController::HideKeyboard(HideReason reason) {
ui_->HideKeyboardWindow();
ChangeState(KeyboardControllerState::HIDDEN);
+ // Clear the temporary enabled flag when the keyboard is hidden.
+ // Note: This does not actually disable the keyboard.
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kTemporarilyEnabled);
+
for (KeyboardControllerObserver& observer : observer_list_)
observer.OnKeyboardHidden(reason == HIDE_REASON_SYSTEM_TEMPORARY);
@@ -507,7 +593,7 @@ void KeyboardController::HideKeyboardByUser() {
}
void KeyboardController::HideKeyboardImplicitlyByUser() {
- if (!keyboard_locked())
+ if (!keyboard_locked_)
HideKeyboard(HIDE_REASON_USER_IMPLICIT);
}
@@ -520,7 +606,7 @@ void KeyboardController::HideKeyboardExplicitlyBySystem() {
}
void KeyboardController::HideKeyboardImplicitlyBySystem() {
- if (state_ != KeyboardControllerState::SHOWN || keyboard_locked())
+ if (state_ != KeyboardControllerState::SHOWN || keyboard_locked_)
return;
ChangeState(KeyboardControllerState::WILL_HIDE);
@@ -533,10 +619,6 @@ void KeyboardController::HideKeyboardImplicitlyBySystem() {
base::TimeDelta::FromMilliseconds(kHideKeyboardDelayMs));
}
-void KeyboardController::DismissVirtualKeyboard() {
- HideKeyboardByUser();
-}
-
// private
void KeyboardController::HideAnimationFinished() {
if (state_ == KeyboardControllerState::HIDDEN) {
@@ -570,20 +652,20 @@ void KeyboardController::ShowAnimationFinished() {
// private
void KeyboardController::SetContainerBehaviorInternal(
- const ContainerType type) {
+ mojom::ContainerType type) {
// Reset the hit test event targeter because the hit test bounds will
// be wrong when container type changes and may cause the UI to be unusable.
if (GetKeyboardWindow())
GetKeyboardWindow()->SetEventTargeter(nullptr);
switch (type) {
- case ContainerType::FULL_WIDTH:
+ case mojom::ContainerType::kFullWidth:
container_behavior_ = std::make_unique<ContainerFullWidthBehavior>(this);
break;
- case ContainerType::FLOATING:
+ case mojom::ContainerType::kFloating:
container_behavior_ = std::make_unique<ContainerFloatingBehavior>(this);
break;
- case ContainerType::FULLSCREEN:
+ case mojom::ContainerType::kFullscreen:
container_behavior_ = std::make_unique<ContainerFullscreenBehavior>(this);
break;
default:
@@ -592,12 +674,14 @@ void KeyboardController::SetContainerBehaviorInternal(
}
void KeyboardController::ShowKeyboard(bool lock) {
+ DVLOG(1) << "ShowKeyboard";
set_keyboard_locked(lock);
ShowKeyboardInternal(display::Display());
}
void KeyboardController::ShowKeyboardInDisplay(
const display::Display& display) {
+ DVLOG(1) << "ShowKeyboardInDisplay: " << display.id();
set_keyboard_locked(true);
ShowKeyboardInternal(display);
}
@@ -612,6 +696,40 @@ void KeyboardController::LoadKeyboardWindowInBackground() {
PopulateKeyboardContent(display::Display(), false);
}
+ui::InputMethod* KeyboardController::GetInputMethodForTest() {
+ return ui_->GetInputMethod();
+}
+
+void KeyboardController::EnsureCaretInWorkAreaForTest(
+ const gfx::Rect& occluded_bounds) {
+ EnsureCaretInWorkArea(occluded_bounds);
+}
+
+// ContainerBehavior::Delegate overrides
+
+bool KeyboardController::IsKeyboardLocked() const {
+ return keyboard_locked_;
+}
+
+gfx::Rect KeyboardController::GetBoundsInScreen() const {
+ return GetKeyboardWindow()->GetBoundsInScreen();
+}
+
+void KeyboardController::MoveKeyboardWindow(const gfx::Rect& new_bounds) {
+ DCHECK(IsKeyboardVisible());
+ SetKeyboardWindowBounds(new_bounds);
+}
+
+void KeyboardController::MoveKeyboardWindowToDisplay(
+ const display::Display& display,
+ const gfx::Rect& new_bounds) {
+ queued_display_change_ =
+ std::make_unique<QueuedDisplayChange>(display, new_bounds);
+ HideKeyboardTemporarilyForTransition();
+}
+
+// aura::WindowObserver overrides
+
void KeyboardController::OnWindowAddedToRootWindow(aura::Window* window) {
container_behavior_->SetCanonicalBounds(GetKeyboardWindow(),
GetRootWindow()->bounds());
@@ -633,6 +751,8 @@ void KeyboardController::OnWindowBoundsChanged(
NotifyKeyboardBoundsChanging(new_bounds);
}
+// InputMethodObserver overrides
+
void KeyboardController::OnInputMethodDestroyed(
const ui::InputMethod* input_method) {
ime_observer_.RemoveAll();
@@ -693,8 +813,9 @@ void KeyboardController::ShowKeyboardIfWithinTransientBlurThreshold() {
}
void KeyboardController::OnShowVirtualKeyboardIfEnabled() {
+ DVLOG(1) << "OnShowVirtualKeyboardIfEnabled: " << IsKeyboardEnableRequested();
// Calling |ShowKeyboardInternal| may move the keyboard to another display.
- if (keyboard::IsKeyboardEnabled() && !keyboard_locked())
+ if (IsKeyboardEnableRequested() && !keyboard_locked_)
ShowKeyboardInternal(display::Display());
}
@@ -709,14 +830,19 @@ void KeyboardController::PopulateKeyboardContent(
bool show_keyboard) {
DCHECK(show_keyboard || state_ == KeyboardControllerState::INITIAL);
+ DVLOG(1) << "PopulateKeyboardContent: " << StateToStr(state_);
TRACE_EVENT0("vk", "PopulateKeyboardContent");
if (parent_container_->children().empty()) {
DCHECK_EQ(state_, KeyboardControllerState::INITIAL);
- // TODO(https://crbug.com/845780): This call will create and load the
- // virtual keyboard window. Redesign the KeyboardUI interface so that
- // loading is explicit.
- aura::Window* keyboard_window = ui_->GetKeyboardWindow();
+ // For now, using Unretained is safe here because the |ui_| is owned by
+ // |this| and the callback does not outlive |ui_|.
+ // TODO(https://crbug.com/845780): Use a weak ptr here in case this
+ // assumption changes.
+ DVLOG(1) << "LoadKeyboardWindow";
+ aura::Window* keyboard_window = ui_->LoadKeyboardWindow(
+ base::BindOnce(&KeyboardController::NotifyKeyboardWindowLoaded,
+ base::Unretained(this)));
keyboard_window->AddPreTargetHandler(&event_filter_);
keyboard_window->AddObserver(this);
parent_container_->AddChild(keyboard_window);
@@ -749,7 +875,7 @@ void KeyboardController::PopulateKeyboardContent(
switch (state_) {
case KeyboardControllerState::INITIAL:
- DCHECK_EQ(keyboard_window->bounds().height(), 0);
+ DCHECK(!IsKeyboardVisible());
show_on_keyboard_window_load_ = show_keyboard;
ChangeState(KeyboardControllerState::LOADING_EXTENSION);
return;
@@ -791,7 +917,8 @@ void KeyboardController::PopulateKeyboardContent(
ChangeState(KeyboardControllerState::SHOWN);
UMA_HISTOGRAM_ENUMERATION("InputMethod.VirtualKeyboard.ContainerBehavior",
- GetActiveContainerType(), ContainerType::COUNT);
+ GetActiveContainerType(),
+ mojom::ContainerType::kMaxValue);
}
bool KeyboardController::WillHideKeyboard() const {
@@ -837,8 +964,6 @@ void KeyboardController::ChangeState(KeyboardControllerState state) {
weak_factory_will_hide_.InvalidateWeakPtrs();
if (state != KeyboardControllerState::LOADING_EXTENSION)
show_on_keyboard_window_load_ = false;
- for (KeyboardControllerObserver& observer : observer_list_)
- observer.OnStateChanged(state);
weak_factory_report_lingering_state_.InvalidateWeakPtrs();
switch (state_) {
@@ -878,8 +1003,8 @@ gfx::Rect KeyboardController::GetKeyboardLockScreenOffsetBounds() const {
// temporarily overridden by a static field in certain lock screen contexts.
// Furthermore, floating keyboard should never affect layout.
if (!IsKeyboardOverscrollEnabled() &&
- container_behavior_->GetType() != ContainerType::FLOATING &&
- container_behavior_->GetType() != ContainerType::FULLSCREEN) {
+ container_behavior_->GetType() != mojom::ContainerType::kFloating &&
+ container_behavior_->GetType() != mojom::ContainerType::kFullscreen) {
return visual_bounds_in_screen_;
}
return gfx::Rect();
@@ -920,8 +1045,8 @@ bool KeyboardController::HandlePointerEvent(const ui::LocatedEvent& event) {
}
void KeyboardController::SetContainerType(
- const ContainerType type,
- base::Optional<gfx::Rect> target_bounds,
+ mojom::ContainerType type,
+ const base::Optional<gfx::Rect>& target_bounds,
base::OnceCallback<void(bool)> callback) {
if (container_behavior_->GetType() == type) {
std::move(callback).Run(false);
@@ -945,15 +1070,6 @@ void KeyboardController::SetContainerType(
}
}
-ui::InputMethod* KeyboardController::GetInputMethodForTest() {
- return ui_->GetInputMethod();
-}
-
-void KeyboardController::EnsureCaretInWorkAreaForTest(
- const gfx::Rect& occluded_bounds) {
- EnsureCaretInWorkArea(occluded_bounds);
-}
-
void KeyboardController::RecordUkmKeyboardShown() {
ui::TextInputClient* text_input_client = GetTextInputClient();
if (!text_input_client)
@@ -964,26 +1080,8 @@ void KeyboardController::RecordUkmKeyboardShown() {
text_input_client->GetTextInputType());
}
-bool KeyboardController::SetDraggableArea(const gfx::Rect& rect) {
- return container_behavior_->SetDraggableArea(rect);
-}
-
-bool KeyboardController::DisplayVirtualKeyboard() {
- // Calling |ShowKeyboardInternal| may move the keyboard to another display.
- if (keyboard::IsKeyboardEnabled() && !keyboard_locked()) {
- ShowKeyboardInternal(display::Display());
- return true;
- }
- return false;
-}
-void KeyboardController::AddObserver(
- ui::InputMethodKeyboardControllerObserver* observer) {
- // TODO: Implement me
-}
-
-void KeyboardController::RemoveObserver(
- ui::InputMethodKeyboardControllerObserver* observer) {
- // TODO: Implement me
+void KeyboardController::SetDraggableArea(const gfx::Rect& rect) {
+ container_behavior_->SetDraggableArea(rect);
}
bool KeyboardController::IsKeyboardVisible() {
@@ -994,6 +1092,10 @@ bool KeyboardController::IsKeyboardVisible() {
return false;
}
+ui::TextInputClient* KeyboardController::GetTextInputClient() {
+ return ui_->GetInputMethod()->GetTextInputClient();
+}
+
void KeyboardController::UpdateInputMethodObserver() {
ui::InputMethod* ime = ui_->GetInputMethod();
@@ -1009,8 +1111,10 @@ void KeyboardController::UpdateInputMethodObserver() {
ime_observer_.RemoveAll();
ime_observer_.Add(ime);
- // TODO(https://crbug.com/845780): Investigate whether this does anything.
- OnTextInputStateChanged(ime->GetTextInputClient());
+ // Note: We used to call OnTextInputStateChanged(ime->GetTextInputClient())
+ // here, but that can trigger HideKeyboardImplicitlyBySystem() from a call to
+ // ShowKeyboard() when using mojo APIs in Chrome (SingleProcessMash) if
+ // ime->GetTextInputClient() isn't focused.
}
void KeyboardController::EnsureCaretInWorkArea(
diff --git a/chromium/ui/keyboard/keyboard_controller.h b/chromium/ui/keyboard/keyboard_controller.h
index 94e0b6c85dc..1214f328eee 100644
--- a/chromium/ui/keyboard/keyboard_controller.h
+++ b/chromium/ui/keyboard/keyboard_controller.h
@@ -6,6 +6,8 @@
#define UI_KEYBOARD_KEYBOARD_CONTROLLER_H_
#include <memory>
+#include <set>
+#include <vector>
#include "base/macros.h"
#include "base/observer_list.h"
@@ -19,7 +21,6 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/keyboard/container_behavior.h"
-#include "ui/keyboard/container_type.h"
#include "ui/keyboard/display_util.h"
#include "ui/keyboard/keyboard_event_filter.h"
#include "ui/keyboard/keyboard_export.h"
@@ -27,6 +28,7 @@
#include "ui/keyboard/keyboard_ukm_recorder.h"
#include "ui/keyboard/notification_manager.h"
#include "ui/keyboard/public/keyboard_config.mojom.h"
+#include "ui/keyboard/public/keyboard_controller_types.mojom.h"
#include "ui/keyboard/queued_container_type.h"
#include "ui/keyboard/queued_display_change.h"
@@ -67,10 +69,9 @@ enum class KeyboardControllerState {
// Provides control of the virtual keyboard, including enabling/disabling the
// keyboard and controlling its visibility.
-class KEYBOARD_EXPORT KeyboardController
- : public ui::InputMethodObserver,
- public aura::WindowObserver,
- public ui::InputMethodKeyboardController {
+class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
+ public aura::WindowObserver,
+ public ContainerBehavior::Delegate {
public:
KeyboardController();
~KeyboardController() override;
@@ -113,16 +114,9 @@ class KEYBOARD_EXPORT KeyboardController
// null if the keyboard has not been attached to any root window.
aura::Window* GetRootWindow();
- // Moves an already loaded keyboard.
- void MoveKeyboard(const gfx::Rect& new_bounds);
-
// Sets the bounds of the keyboard window.
void SetKeyboardWindowBounds(const gfx::Rect& new_bounds);
- // Called by KeyboardUI when the keyboard window has loaded. Shows
- // the keyboard if show_on_keyboard_window_load_ is true.
- void NotifyKeyboardWindowLoaded();
-
// Reloads the content of the keyboard. No-op if the keyboard content is not
// loaded yet.
void Reload();
@@ -132,27 +126,27 @@ class KEYBOARD_EXPORT KeyboardController
bool HasObserver(KeyboardControllerObserver* observer) const;
void RemoveObserver(KeyboardControllerObserver* observer);
- // Gets the currently focused text input client.
- ui::TextInputClient* GetTextInputClient();
-
- // Insert |text| into the active TextInputClient if there is one. Returns true
- // if |text| was successfully inserted.
- bool InsertText(const base::string16& text);
-
// Updates |keyboard_config_| with |config|. Returns |false| if there is no
- // change, otherwise returns true and notifies observers if this is enabled().
+ // change, otherwise returns true and notifies observers if this is enabled.
bool UpdateKeyboardConfig(const mojom::KeyboardConfig& config);
const mojom::KeyboardConfig& keyboard_config() { return keyboard_config_; }
- // Returns true if keyboard overscroll is enabled.
- bool IsKeyboardOverscrollEnabled() const;
-
- void set_keyboard_locked(bool lock) { keyboard_locked_ = lock; }
+ // Sets and clears |keyboard_enable_flags_| entries.
+ void SetEnableFlag(mojom::KeyboardEnableFlag flag);
+ void ClearEnableFlag(mojom::KeyboardEnableFlag flag);
+ bool IsEnableFlagSet(mojom::KeyboardEnableFlag flag) const;
+ const std::set<mojom::KeyboardEnableFlag>& keyboard_enable_flags() const {
+ return keyboard_enable_flags_;
+ }
- bool keyboard_locked() const { return keyboard_locked_; }
+ // Returns true if the keyboard should be enabled, i.e. the current result
+ // of Set/ClearEnableFlag should cause the keyboard to be enabled.
+ // TODO(stevenjb/shend): Consider removing this and have all calls to
+ // Set/ClearEnableFlag always enable or disable the keyboard directly.
+ bool IsKeyboardEnableRequested() const;
- void MoveToDisplayWithTransition(display::Display display,
- gfx::Rect new_bounds_in_local);
+ // Returns true if keyboard overscroll is enabled.
+ bool IsKeyboardOverscrollEnabled() const;
// Hide the keyboard because the user has chosen to specifically hide the
// keyboard, such as pressing the dismiss button.
@@ -215,7 +209,7 @@ class KEYBOARD_EXPORT KeyboardController
// Does not do anything if there is no keyboard window.
void SetHitTestBounds(const std::vector<gfx::Rect>& bounds);
- ContainerType GetActiveContainerType() const {
+ mojom::ContainerType GetActiveContainerType() const {
return container_behavior_->GetType();
}
@@ -237,22 +231,26 @@ class KEYBOARD_EXPORT KeyboardController
// Sets the active container type. If the keyboard is currently shown, this
// will trigger a hide animation and a subsequent show animation. Otherwise
// the ContainerBehavior change is synchronous.
- void SetContainerType(ContainerType type,
- base::Optional<gfx::Rect> target_bounds,
+ void SetContainerType(mojom::ContainerType type,
+ const base::Optional<gfx::Rect>& target_bounds,
base::OnceCallback<void(bool)> callback);
// Sets floating keyboard draggable rect.
- bool SetDraggableArea(const gfx::Rect& rect);
+ void SetDraggableArea(const gfx::Rect& rect);
+
+ bool IsKeyboardVisible();
- // InputMethodKeyboardController overrides.
- bool DisplayVirtualKeyboard() override;
- void DismissVirtualKeyboard() override;
- void AddObserver(
- ui::InputMethodKeyboardControllerObserver* observer) override;
- void RemoveObserver(
- ui::InputMethodKeyboardControllerObserver* observer) override;
- bool IsKeyboardVisible() override;
+ ui::InputMethodKeyboardController* input_method_keyboard_controller() {
+ return input_method_keyboard_controller_.get();
+ }
+ bool keyboard_locked() const { return keyboard_locked_; }
+ void set_keyboard_locked(bool lock) { keyboard_locked_ = lock; }
+
+ void set_container_behavior_for_test(
+ std::unique_ptr<ContainerBehavior> container_behavior) {
+ container_behavior_ = std::move(container_behavior);
+ }
KeyboardControllerState GetStateForTest() const { return state_; }
ui::InputMethod* GetInputMethodForTest();
void EnsureCaretInWorkAreaForTest(const gfx::Rect& occluded_bounds);
@@ -291,6 +289,13 @@ class KEYBOARD_EXPORT KeyboardController
HIDE_REASON_USER_IMPLICIT,
};
+ // ContainerBehavior::Delegate overrides
+ bool IsKeyboardLocked() const override;
+ gfx::Rect GetBoundsInScreen() const override;
+ void MoveKeyboardWindow(const gfx::Rect& new_bounds) override;
+ void MoveKeyboardWindowToDisplay(const display::Display& display,
+ const gfx::Rect& new_bounds) override;
+
// aura::WindowObserver overrides
void OnWindowAddedToRootWindow(aura::Window* window) override;
void OnWindowBoundsChanged(aura::Window* window,
@@ -332,6 +337,10 @@ class KEYBOARD_EXPORT KeyboardController
// window are changing.
void NotifyKeyboardBoundsChanging(const gfx::Rect& new_bounds);
+ // Called when the keyboard window has loaded. Shows the keyboard if
+ // |show_on_keyboard_window_load_| is true.
+ void NotifyKeyboardWindowLoaded();
+
// Validates the state transition. Called from ChangeState.
void CheckStateTransition(KeyboardControllerState prev,
KeyboardControllerState next);
@@ -346,11 +355,14 @@ class KEYBOARD_EXPORT KeyboardController
// time ago.
void ShowKeyboardIfWithinTransientBlurThreshold();
- void SetContainerBehaviorInternal(ContainerType type);
+ void SetContainerBehaviorInternal(mojom::ContainerType type);
// Records that keyboard was shown on the currently focused UKM source.
void RecordUkmKeyboardShown();
+ // Gets the currently focused text input client.
+ ui::TextInputClient* GetTextInputClient();
+
// Ensures that the current IME is observed if it is changed.
void UpdateInputMethodObserver();
@@ -368,6 +380,8 @@ class KEYBOARD_EXPORT KeyboardController
void MarkKeyboardLoadFinished();
std::unique_ptr<KeyboardUI> ui_;
+ std::unique_ptr<ui::InputMethodKeyboardController>
+ input_method_keyboard_controller_;
KeyboardLayoutDelegate* layout_delegate_ = nullptr;
ScopedObserver<ui::InputMethod, ui::InputMethodObserver> ime_observer_;
@@ -403,6 +417,10 @@ class KEYBOARD_EXPORT KeyboardController
// Keyboard configuration associated with the controller.
mojom::KeyboardConfig keyboard_config_;
+ // Set of active enabled request flags. Used to determine whether the keyboard
+ // should be enabled.
+ std::set<mojom::KeyboardEnableFlag> keyboard_enable_flags_;
+
NotificationManager notification_manager_;
base::Time time_of_last_blur_ = base::Time::UnixEpoch();
diff --git a/chromium/ui/keyboard/keyboard_controller_observer.h b/chromium/ui/keyboard/keyboard_controller_observer.h
index f3ffe74a35d..39ea95c32d0 100644
--- a/chromium/ui/keyboard/keyboard_controller_observer.h
+++ b/chromium/ui/keyboard/keyboard_controller_observer.h
@@ -67,20 +67,21 @@ class KEYBOARD_EXPORT KeyboardControllerObserver {
virtual void OnKeyboardAppearanceChanged(
const KeyboardStateDescriptor& state) {}
- // Called when the keyboard is effectively disabled (i.e. when the UI / window
- // is destroyed, not when keyboard::IsKeyboardEnabled() changes), e.g. when
- // user switches convertible to laptop mode or the active user changes.
- virtual void OnKeyboardDisabled() {}
+ // Called when an enable flag affecting the requested enabled state changes.
+ virtual void OnKeyboardEnableFlagsChanged(
+ std::set<mojom::KeyboardEnableFlag>& keyboard_enable_flags) {}
+
+ // Called when the keyboard is enabled or disabled. NOTE: This is called
+ // when Enabled() or Disabled() is called, not when the requested enabled
+ // state (IsEnableRequested) changes.
+ virtual void OnKeyboardEnabledChanged(bool is_enabled) {}
// Called when the keyboard has been hidden and the hiding animation finished
- // successfully. This is same as |state| == HIDDEN on OnStateChanged.
+ // successfully.
// When |is_temporary_hide| is true, this hide is immediately followed by a
// show (e.g. when changing to floating keyboard)
virtual void OnKeyboardHidden(bool is_temporary_hide) {}
- // Called when the state changed.
- virtual void OnStateChanged(KeyboardControllerState state) {}
-
// Called when the virtual keyboard IME config changed.
virtual void OnKeyboardConfigChanged() {}
};
diff --git a/chromium/ui/keyboard/keyboard_controller_unittest.cc b/chromium/ui/keyboard/keyboard_controller_unittest.cc
index afcc0822f8d..aed5e65c34f 100644
--- a/chromium/ui/keyboard/keyboard_controller_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_controller_unittest.cc
@@ -44,8 +44,6 @@
namespace keyboard {
namespace {
-const int kDefaultVirtualKeyboardHeight = 100;
-
// Steps a layer animation until it is completed. Animations must be enabled.
void RunAnimationForLayer(ui::Layer* layer) {
// Animations must be enabled for stepping to work.
@@ -215,7 +213,9 @@ class KeyboardControllerTest : public aura::test::AuraTestBase,
is_visible_ = is_visible;
is_visible_number_of_calls_++;
}
- void OnKeyboardDisabled() override { keyboard_disabled_ = true; }
+ void OnKeyboardEnabledChanged(bool is_enabled) override {
+ keyboard_disabled_ = !is_enabled;
+ }
void ClearKeyboardDisabled() { keyboard_disabled_ = false; }
int visible_bounds_number_of_calls() const {
@@ -247,14 +247,7 @@ class KeyboardControllerTest : public aura::test::AuraTestBase,
if (client && client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE &&
client->GetTextInputMode() != ui::TEXT_INPUT_MODE_NONE) {
input_method->ShowVirtualKeyboardIfEnabled();
- if (controller().GetKeyboardWindow()->bounds().height() == 0) {
- // Set initial bounds for test keyboard window.
- controller().GetKeyboardWindow()->SetBounds(
- KeyboardBoundsFromRootBounds(root_window()->bounds(),
- kDefaultVirtualKeyboardHeight));
- // Simulate the keyboard contents finish loading
- controller_.NotifyKeyboardWindowLoaded();
- }
+ ASSERT_TRUE(keyboard::WaitUntilShown());
}
}
@@ -301,14 +294,11 @@ TEST_F(KeyboardControllerTest, KeyboardSize) {
controller().LoadKeyboardWindowInBackground();
+ // The keyboard window should not be visible.
aura::Window* keyboard_window = controller().GetKeyboardWindow();
+ EXPECT_FALSE(keyboard_window->IsVisible());
- // The container should be positioned at the bottom of screen and has 0
- // height.
const gfx::Rect screen_bounds = root_window()->bounds();
- const gfx::Rect initial_keyboard_bounds = keyboard_window->bounds();
- EXPECT_EQ(0, initial_keyboard_bounds.height());
- EXPECT_EQ(screen_bounds.height(), initial_keyboard_bounds.y());
// Attempt to change window width or move window up from the bottom are
// ignored. Changing window height is supported.
@@ -531,8 +521,8 @@ TEST_F(KeyboardControllerTest, SetOccludedBoundsChangesFullscreenBounds) {
controller().LoadKeyboardWindowInBackground();
// Keyboard is hidden, so SetContainerType should be synchronous.
- controller().SetContainerType(ContainerType::FULLSCREEN, base::nullopt,
- base::DoNothing());
+ controller().SetContainerType(mojom::ContainerType::kFullscreen,
+ base::nullopt, base::DoNothing());
// KeyboardController only notifies occluded bound changes when the keyboard
// is visible.
@@ -569,7 +559,8 @@ class KeyboardControllerAnimationTest : public KeyboardControllerTest {
// Preload the keyboard contents so that we can set its bounds.
controller().LoadKeyboardWindowInBackground();
- controller().NotifyKeyboardWindowLoaded();
+ // Wait for the keyboard contents to load.
+ base::RunLoop().RunUntilIdle();
keyboard_window()->SetBounds(root_window()->bounds());
}
@@ -634,7 +625,7 @@ TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
EXPECT_FALSE(notified_is_visible());
SetModeCallbackInvocationCounter invocation_counter;
- controller().SetContainerType(ContainerType::FLOATING, base::nullopt,
+ controller().SetContainerType(mojom::ContainerType::kFloating, base::nullopt,
invocation_counter.GetInvocationCallback());
EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true));
EXPECT_EQ(0, invocation_counter.invocation_count_for_status(false));
@@ -650,7 +641,7 @@ TEST_F(KeyboardControllerAnimationTest, ContainerAnimation) {
// callback should do nothing when container mode is set to the current active
// container type. An unnecessary call gets registered synchronously as a
// failure status to the callback.
- controller().SetContainerType(ContainerType::FLOATING, base::nullopt,
+ controller().SetContainerType(mojom::ContainerType::kFloating, base::nullopt,
invocation_counter.GetInvocationCallback());
EXPECT_EQ(1, invocation_counter.invocation_count_for_status(true));
EXPECT_EQ(1, invocation_counter.invocation_count_for_status(false));
@@ -662,12 +653,13 @@ TEST_F(KeyboardControllerAnimationTest, ChangeContainerModeWithBounds) {
ui::Layer* layer = keyboard_window()->layer();
ShowKeyboard();
RunAnimationForLayer(layer);
- EXPECT_EQ(ContainerType::FULL_WIDTH, controller().GetActiveContainerType());
+ EXPECT_EQ(mojom::ContainerType::kFullWidth,
+ controller().GetActiveContainerType());
EXPECT_TRUE(keyboard_window()->IsVisible());
// Changing the mode to another mode invokes hiding + showing.
const gfx::Rect target_bounds(0, 0, 1200, 600);
- controller().SetContainerType(ContainerType::FLOATING,
+ controller().SetContainerType(mojom::ContainerType::kFloating,
base::make_optional(target_bounds),
invocation_counter.GetInvocationCallback());
// The container window shouldn't be resized until it's hidden even if the
@@ -781,9 +773,9 @@ TEST_F(KeyboardControllerAnimationTest, FloatingKeyboardEnsureCaretInWorkArea) {
MockTextInputClient mock_input_client;
EXPECT_CALL(mock_input_client, EnsureCaretNotInRect(gfx::Rect())).Times(1);
- controller().SetContainerType(keyboard::ContainerType::FLOATING,
- base::nullopt, base::DoNothing());
- ASSERT_EQ(keyboard::ContainerType::FLOATING,
+ controller().SetContainerType(mojom::ContainerType::kFloating, base::nullopt,
+ base::DoNothing());
+ ASSERT_EQ(mojom::ContainerType::kFloating,
controller().GetActiveContainerType());
// Ensure keyboard ui is populated
diff --git a/chromium/ui/keyboard/keyboard_layout_manager.cc b/chromium/ui/keyboard/keyboard_layout_manager.cc
index 59af679b08f..7cd0ad6d6c0 100644
--- a/chromium/ui/keyboard/keyboard_layout_manager.cc
+++ b/chromium/ui/keyboard/keyboard_layout_manager.cc
@@ -21,7 +21,7 @@ KeyboardLayoutManager::~KeyboardLayoutManager() = default;
void KeyboardLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
// Reset the keyboard window bounds when it gets added to the keyboard
// container to ensure that its bounds are valid.
- SetChildBounds(child, gfx::Rect());
+ SetChildBounds(child, child->GetBoundsInRootWindow());
}
void KeyboardLayoutManager::SetChildBounds(aura::Window* child,
diff --git a/chromium/ui/keyboard/keyboard_ui.cc b/chromium/ui/keyboard/keyboard_ui.cc
index 16d24e63da9..207f9c0c5a7 100644
--- a/chromium/ui/keyboard/keyboard_ui.cc
+++ b/chromium/ui/keyboard/keyboard_ui.cc
@@ -18,15 +18,19 @@ KeyboardUI::KeyboardUI() = default;
KeyboardUI::~KeyboardUI() = default;
void KeyboardUI::ShowKeyboardWindow() {
- if (HasKeyboardWindow()) {
+ DVLOG(1) << "ShowKeyboardWindow";
+ aura::Window* window = GetKeyboardWindow();
+ if (window) {
TRACE_EVENT0("vk", "ShowKeyboardWindow");
- GetKeyboardWindow()->Show();
+ window->Show();
}
}
void KeyboardUI::HideKeyboardWindow() {
- if (HasKeyboardWindow())
- GetKeyboardWindow()->Hide();
+ DVLOG(1) << "HideKeyboardWindow";
+ aura::Window* window = GetKeyboardWindow();
+ if (window)
+ window->Hide();
}
void KeyboardUI::SetController(KeyboardController* controller) {
diff --git a/chromium/ui/keyboard/keyboard_ui.h b/chromium/ui/keyboard/keyboard_ui.h
index a96fc780c49..2fe04dbc982 100644
--- a/chromium/ui/keyboard/keyboard_ui.h
+++ b/chromium/ui/keyboard/keyboard_ui.h
@@ -5,6 +5,7 @@
#ifndef UI_KEYBOARD_KEYBOARD_UI_H_
#define UI_KEYBOARD_KEYBOARD_UI_H_
+#include "base/callback_forward.h"
#include "base/macros.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/keyboard/keyboard_export.h"
@@ -12,9 +13,6 @@
namespace aura {
class Window;
}
-namespace gfx {
-class Rect;
-}
namespace ui {
class InputMethod;
}
@@ -26,17 +24,22 @@ class KeyboardController;
// Interface representing a window containing virtual keyboard UI.
class KEYBOARD_EXPORT KeyboardUI {
public:
+ using LoadCallback = base::OnceCallback<void()>;
+
KeyboardUI();
virtual ~KeyboardUI();
- // Gets the virtual keyboard window i.e. the WebContents window where
- // keyboard extensions are loaded. May return null if the window has not yet
- // been created.
- // This class owns the window.
- virtual aura::Window* GetKeyboardWindow() = 0;
+ // Begin loading the virtual keyboard window asynchronously.
+ // Returns a window immediately, but the UI within the window is not
+ // guaranteed to be fully loaded until |callback| is called.
+ // |callback| must be called after this function returns.
+ // This function can only be called once.
+ virtual aura::Window* LoadKeyboardWindow(LoadCallback callback) = 0;
- // Whether the keyboard window has been created.
- virtual bool HasKeyboardWindow() const = 0;
+ // Gets the virtual keyboard window i.e. the WebContents window where
+ // keyboard extensions are loaded. Returns null if the window has not started
+ // loading.
+ virtual aura::Window* GetKeyboardWindow() const = 0;
// Gets the InputMethod that will provide notifications about changes in the
// text input context.
@@ -61,15 +64,9 @@ class KEYBOARD_EXPORT KeyboardUI {
// other input fields, the virtual keyboard should switch back to the IME
// provided keyboard, or keep using the system virtual keyboard if IME doesn't
// provide one.
+ // TODO(https://crbug.com/845780): Change this to accept a callback.
virtual void ReloadKeyboardIfNeeded() = 0;
- // When the embedder changes the keyboard bounds, asks the keyboard to adjust
- // insets for windows affected by this.
- virtual void InitInsets(const gfx::Rect& keyboard_bounds) = 0;
-
- // Resets insets for affected windows.
- virtual void ResetInsets() = 0;
-
// |controller| may be null when KeyboardController is being destroyed.
void SetController(KeyboardController* controller);
diff --git a/chromium/ui/keyboard/keyboard_util.cc b/chromium/ui/keyboard/keyboard_util.cc
index 3e3020fcaab..4aba3ff665a 100644
--- a/chromium/ui/keyboard/keyboard_util.cc
+++ b/chromium/ui/keyboard/keyboard_util.cc
@@ -8,180 +8,63 @@
#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/ime/constants.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/events/event_sink.h"
-#include "ui/events/event_utils.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/keycodes/dom/dom_key.h"
-#include "ui/events/keycodes/dom/keycode_converter.h"
-#include "ui/events/keycodes/keyboard_code_conversion.h"
-#include "ui/keyboard/keyboard_switches.h"
+#include "ui/keyboard/keyboard_controller.h"
+#include "ui/keyboard/public/keyboard_switches.h"
namespace keyboard {
namespace {
-const char kKeyDown[] ="keydown";
-const char kKeyUp[] = "keyup";
-
-void SendProcessKeyEvent(ui::EventType type,
- aura::WindowTreeHost* host) {
- ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::DomCode::NONE,
- ui::EF_IS_SYNTHESIZED, ui::DomKey::PROCESS,
- ui::EventTimeForNow());
- ui::EventDispatchDetails details =
- host->event_sink()->OnEventFromSource(&event);
- CHECK(!details.dispatcher_destroyed);
-}
-
-bool g_accessibility_keyboard_enabled = false;
-
-bool g_keyboard_enabled_from_shelf = false;
-
-bool g_touch_keyboard_enabled = false;
+// Until src/chrome is fully transitioned to use ChromeKeyboardControllerClient
+// we need to test whether KeyboardController exists; it is null in OopMash.
+// TODO(stevenjb): Remove remaining calls from src/chrome.
+// https://crbug.com/84332.
-KeyboardState g_requested_keyboard_state = KEYBOARD_STATE_AUTO;
+bool GetFlag(mojom::KeyboardEnableFlag flag) {
+ return KeyboardController::HasInstance()
+ ? KeyboardController::Get()->IsEnableFlagSet(flag)
+ : false;
+}
-KeyboardShowOverride g_keyboard_show_override = KEYBOARD_SHOW_OVERRIDE_NONE;
+void SetOrClearEnableFlag(mojom::KeyboardEnableFlag flag, bool enabled) {
+ auto* controller = KeyboardController::Get();
+ if (!controller)
+ return;
+ if (enabled)
+ controller->SetEnableFlag(flag);
+ else
+ controller->ClearEnableFlag(flag);
+}
} // namespace
void SetAccessibilityKeyboardEnabled(bool enabled) {
- g_accessibility_keyboard_enabled = enabled;
+ SetOrClearEnableFlag(mojom::KeyboardEnableFlag::kAccessibilityEnabled,
+ enabled);
}
bool GetAccessibilityKeyboardEnabled() {
- return g_accessibility_keyboard_enabled;
+ return GetFlag(mojom::KeyboardEnableFlag::kAccessibilityEnabled);
}
void SetKeyboardEnabledFromShelf(bool enabled) {
- g_keyboard_enabled_from_shelf = enabled;
+ SetOrClearEnableFlag(mojom::KeyboardEnableFlag::kShelfEnabled, enabled);
}
bool GetKeyboardEnabledFromShelf() {
- return g_keyboard_enabled_from_shelf;
+ return GetFlag(mojom::KeyboardEnableFlag::kShelfEnabled);
}
void SetTouchKeyboardEnabled(bool enabled) {
- g_touch_keyboard_enabled = enabled;
+ SetOrClearEnableFlag(mojom::KeyboardEnableFlag::kTouchEnabled, enabled);
}
bool GetTouchKeyboardEnabled() {
- return g_touch_keyboard_enabled;
-}
-
-void SetRequestedKeyboardState(KeyboardState state) {
- g_requested_keyboard_state = state;
-}
-
-std::string GetKeyboardLayout() {
- // TODO(bshe): layout string is currently hard coded. We should use more
- // standard keyboard layouts.
- return GetAccessibilityKeyboardEnabled() ? "system-qwerty" : "qwerty";
+ return GetFlag(mojom::KeyboardEnableFlag::kTouchEnabled);
}
bool IsKeyboardEnabled() {
- // Accessibility setting prioritized over policy setting.
- if (g_accessibility_keyboard_enabled)
- return true;
- // Keyboard can be enabled temporarily by the shelf.
- if (g_keyboard_enabled_from_shelf)
- return true;
- // Policy strictly disables showing a virtual keyboard.
- if (g_keyboard_show_override == KEYBOARD_SHOW_OVERRIDE_DISABLED)
- return false;
- // Policy strictly enables the keyboard.
- if (g_keyboard_show_override == KEYBOARD_SHOW_OVERRIDE_ENABLED)
- return true;
- // Run-time flag to enable keyboard has been included.
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableVirtualKeyboard))
- return true;
- // Requested state from the application layer.
- if (g_requested_keyboard_state == KEYBOARD_STATE_DISABLED)
- return false;
- // Check if any of the other flags are enabled.
- return g_touch_keyboard_enabled ||
- g_requested_keyboard_state == KEYBOARD_STATE_ENABLED;
-}
-
-void SetKeyboardShowOverride(KeyboardShowOverride show_override) {
- g_keyboard_show_override = show_override;
-}
-
-bool SendKeyEvent(const std::string type,
- int key_value,
- int key_code,
- std::string key_name,
- int modifiers,
- aura::WindowTreeHost* host) {
- ui::EventType event_type = ui::ET_UNKNOWN;
- if (type == kKeyDown)
- event_type = ui::ET_KEY_PRESSED;
- else if (type == kKeyUp)
- event_type = ui::ET_KEY_RELEASED;
- if (event_type == ui::ET_UNKNOWN)
- return false;
-
- ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
-
- ui::InputMethod* input_method = host->GetInputMethod();
- if (code == ui::VKEY_UNKNOWN) {
- // Handling of special printable characters (e.g. accented characters) for
- // which there is no key code.
- if (event_type == ui::ET_KEY_RELEASED) {
- if (!input_method)
- return false;
-
- // This can be null if no text input field is not focused.
- ui::TextInputClient* tic = input_method->GetTextInputClient();
-
- SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
-
- ui::KeyEvent char_event(key_value, code, ui::DomCode::NONE, ui::EF_NONE);
- if (tic)
- tic->InsertChar(char_event);
- SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
- }
- } else {
- if (event_type == ui::ET_KEY_RELEASED) {
- // The number of key press events seen since the last backspace.
- static int keys_seen = 0;
- if (code == ui::VKEY_BACK) {
- // Log the rough lengths of characters typed between backspaces. This
- // metric will be used to determine the error rate for the keyboard.
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "VirtualKeyboard.KeystrokesBetweenBackspaces",
- keys_seen, 1, 1000, 50);
- keys_seen = 0;
- } else {
- ++keys_seen;
- }
- }
-
- ui::DomCode dom_code = ui::KeycodeConverter::CodeStringToDomCode(key_name);
- if (dom_code == ui::DomCode::NONE)
- dom_code = ui::UsLayoutKeyboardCodeToDomCode(code);
- CHECK(dom_code != ui::DomCode::NONE);
- ui::KeyEvent event(
- event_type,
- code,
- dom_code,
- modifiers);
-
- // Marks the simulated key event is from the Virtual Keyboard.
- ui::Event::Properties properties;
- properties[ui::kPropertyFromVK] = std::vector<uint8_t>();
- event.SetProperties(properties);
-
- ui::EventDispatchDetails details =
- host->event_sink()->OnEventFromSource(&event);
- CHECK(!details.dispatcher_destroyed);
- }
- return true;
+ return KeyboardController::Get()->IsKeyboardEnableRequested();
}
} // namespace keyboard
diff --git a/chromium/ui/keyboard/keyboard_util.h b/chromium/ui/keyboard/keyboard_util.h
index 740259d2967..5a82250a63b 100644
--- a/chromium/ui/keyboard/keyboard_util.h
+++ b/chromium/ui/keyboard/keyboard_util.h
@@ -14,41 +14,14 @@
// TODO(stevenjb/shuchen/shend): Many of these are accessed from both Chrome
// and Ash. We need to remove any Chrome dependencies. htpps://crbug.com/843332
-namespace aura {
-class WindowTreeHost;
-}
-
namespace keyboard {
-// An enumeration of keyboard policy settings.
-enum KeyboardShowOverride {
- KEYBOARD_SHOW_OVERRIDE_DISABLED = 0,
- KEYBOARD_SHOW_OVERRIDE_ENABLED,
- KEYBOARD_SHOW_OVERRIDE_NONE,
-};
-
-// An enumeration of keyboard states.
-enum KeyboardState {
- // Default state. System decides whether to show the keyboard or not.
- KEYBOARD_STATE_AUTO = 0,
- // Request virtual keyboard be deployed.
- KEYBOARD_STATE_ENABLED,
- // Request virtual keyboard be suppressed.
- KEYBOARD_STATE_DISABLED,
-};
-
// Sets the state of the a11y onscreen keyboard.
KEYBOARD_EXPORT void SetAccessibilityKeyboardEnabled(bool enabled);
// Gets the state of the a11y onscreen keyboard.
KEYBOARD_EXPORT bool GetAccessibilityKeyboardEnabled();
-// Sets the state of the hotrod onscreen keyboard.
-KEYBOARD_EXPORT void SetHotrodKeyboardEnabled(bool enabled);
-
-// Gets the state of the hotrod onscreen keyboard.
-KEYBOARD_EXPORT bool GetHotrodKeyboardEnabled();
-
// Sets whether the keyboard is enabled from the shelf.
KEYBOARD_EXPORT void SetKeyboardEnabledFromShelf(bool enabled);
@@ -61,42 +34,9 @@ KEYBOARD_EXPORT void SetTouchKeyboardEnabled(bool enabled);
// Gets the state of the touch onscreen keyboard.
KEYBOARD_EXPORT bool GetTouchKeyboardEnabled();
-// Sets the requested state of the keyboard.
-KEYBOARD_EXPORT void SetRequestedKeyboardState(KeyboardState state);
-
-// Gets the requested state of the keyboard.
-KEYBOARD_EXPORT int GetRequestedKeyboardState();
-
-// Gets the default keyboard layout.
-KEYBOARD_EXPORT std::string GetKeyboardLayout();
-
// Returns true if the virtual keyboard is enabled.
KEYBOARD_EXPORT bool IsKeyboardEnabled();
-// Sets policy override on whether to show the keyboard.
-KEYBOARD_EXPORT void SetKeyboardShowOverride(
- KeyboardShowOverride show_override);
-
-// Sets whehther the keyboards is in restricted state - state where advanced
-// virtual keyboard features are disabled.
-KEYBOARD_EXPORT void SetKeyboardRestricted(bool restricted);
-
-// Returns whether the keyboard is in restricted state.
-KEYBOARD_EXPORT bool GetKeyboardRestricted();
-
-// Sends a fabricated key event, where |type| is the event type, |key_value|
-// is the unicode value of the character, |key_code| is the legacy key code
-// value, |key_name| is the name of the key as defined in the DOM3 key event
-// specification, and |modifier| indicates if any modifier keys are being
-// virtually pressed. The event is dispatched to the active TextInputClient
-// associated with |root_window|. The type may be "keydown" or "keyup".
-KEYBOARD_EXPORT bool SendKeyEvent(std::string type,
- int key_value,
- int key_code,
- std::string key_name,
- int modifiers,
- aura::WindowTreeHost* host);
-
} // namespace keyboard
#endif // UI_KEYBOARD_KEYBOARD_UTIL_H_
diff --git a/chromium/ui/keyboard/keyboard_util_unittest.cc b/chromium/ui/keyboard/keyboard_util_unittest.cc
index 5361b06259b..b2165256295 100644
--- a/chromium/ui/keyboard/keyboard_util_unittest.cc
+++ b/chromium/ui/keyboard/keyboard_util_unittest.cc
@@ -6,6 +6,7 @@
#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/dummy_input_method.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_ui.h"
#include "ui/keyboard/keyboard_util.h"
@@ -22,34 +23,45 @@ class KeyboardUtilTest : public testing::Test {
// Sets all flags controlling whether the keyboard should be shown to
// their disabled state.
void DisableAllFlags() {
+ ResetAllFlags();
keyboard::SetAccessibilityKeyboardEnabled(false);
keyboard::SetTouchKeyboardEnabled(false);
- keyboard::SetKeyboardShowOverride(
- keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED);
- keyboard::SetRequestedKeyboardState(keyboard::KEYBOARD_STATE_DISABLED);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kPolicyDisabled);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kExtensionDisabled);
}
// Sets all flags controlling whether the keyboard should be shown to
- // their enabled state.
+ // their enabled flag.
void EnableAllFlags() {
+ ResetAllFlags();
keyboard::SetAccessibilityKeyboardEnabled(true);
keyboard::SetTouchKeyboardEnabled(true);
- keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED);
- keyboard::SetRequestedKeyboardState(keyboard::KEYBOARD_STATE_ENABLED);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kPolicyEnabled);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kExtensionEnabled);
}
// Sets all flags controlling whether the keyboard should be shown to
- // their neutral state.
+ // their neutral flag.
void ResetAllFlags() {
keyboard::SetAccessibilityKeyboardEnabled(false);
keyboard::SetTouchKeyboardEnabled(false);
- keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_NONE);
- keyboard::SetRequestedKeyboardState(keyboard::KEYBOARD_STATE_AUTO);
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kPolicyDisabled);
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kExtensionDisabled);
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kPolicyEnabled);
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kExtensionEnabled);
}
void SetUp() override { ResetAllFlags(); }
protected:
+ void SetEnableFlag(mojom::KeyboardEnableFlag flag) {
+ keyboard_controller_.SetEnableFlag(flag);
+ }
+
+ void ClearEnableFlag(mojom::KeyboardEnableFlag flag) {
+ keyboard_controller_.ClearEnableFlag(flag);
+ }
+
// Used indirectly by keyboard utils.
KeyboardController keyboard_controller_;
@@ -74,7 +86,7 @@ TEST_F(KeyboardUtilTest, AlwaysShowIfPolicyEnabled) {
EXPECT_FALSE(keyboard::IsKeyboardEnabled());
// If policy is enabled, should ignore other flag values.
DisableAllFlags();
- keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kPolicyEnabled);
EXPECT_TRUE(keyboard::IsKeyboardEnabled());
}
@@ -86,32 +98,32 @@ TEST_F(KeyboardUtilTest, HidesIfPolicyDisabled) {
keyboard::SetAccessibilityKeyboardEnabled(false);
EXPECT_TRUE(keyboard::IsKeyboardEnabled());
// Disable policy. Keyboard should be disabled.
- keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kPolicyDisabled);
EXPECT_FALSE(keyboard::IsKeyboardEnabled());
}
-// Tests that the keyboard shows when requested state provided higher priority
+// Tests that the keyboard shows when requested flag provided higher priority
// flags have not been set.
TEST_F(KeyboardUtilTest, ShowKeyboardWhenRequested) {
DisableAllFlags();
// Remove device policy, which has higher precedence than us.
- keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_NONE);
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kPolicyDisabled);
EXPECT_FALSE(keyboard::IsKeyboardEnabled());
// Requested should have higher precedence than all the remaining flags.
- keyboard::SetRequestedKeyboardState(keyboard::KEYBOARD_STATE_ENABLED);
+ SetEnableFlag(mojom::KeyboardEnableFlag::kExtensionEnabled);
EXPECT_TRUE(keyboard::IsKeyboardEnabled());
}
-// Tests that the touch keyboard is hidden when requested state is disabled and
+// Tests that the touch keyboard is hidden when requested flag is disabled and
// higher priority flags have not been set.
TEST_F(KeyboardUtilTest, HideKeyboardWhenRequested) {
EnableAllFlags();
// Remove higher precedence flags.
- keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_NONE);
+ ClearEnableFlag(mojom::KeyboardEnableFlag::kPolicyEnabled);
keyboard::SetAccessibilityKeyboardEnabled(false);
EXPECT_TRUE(keyboard::IsKeyboardEnabled());
- // Set requested state to disable. Keyboard should disable.
- keyboard::SetRequestedKeyboardState(keyboard::KEYBOARD_STATE_DISABLED);
+ // Set requested flag to disable. Keyboard should disable.
+ SetEnableFlag(mojom::KeyboardEnableFlag::kExtensionDisabled);
EXPECT_FALSE(keyboard::IsKeyboardEnabled());
}
@@ -126,7 +138,7 @@ TEST_F(KeyboardUtilTest, HideKeyboardWhenTouchEnabled) {
TEST_F(KeyboardUtilTest, UpdateKeyboardConfig) {
ResetAllFlags();
- auto config = keyboard_controller_.keyboard_config();
+ mojom::KeyboardConfig config = keyboard_controller_.keyboard_config();
EXPECT_TRUE(config.spell_check);
EXPECT_FALSE(keyboard_controller_.UpdateKeyboardConfig(config));
@@ -147,16 +159,16 @@ TEST_F(KeyboardUtilTest, IsOverscrollEnabled) {
keyboard::SetTouchKeyboardEnabled(true);
EXPECT_TRUE(keyboard_controller_.IsKeyboardOverscrollEnabled());
- // Set overscroll enabled state.
- auto config = keyboard::KeyboardController::Get()->keyboard_config();
+ // Set overscroll enabled flag.
+ mojom::KeyboardConfig config = keyboard_controller_.keyboard_config();
config.overscroll_behavior =
keyboard::mojom::KeyboardOverscrollBehavior::kDisabled;
- keyboard::KeyboardController::Get()->UpdateKeyboardConfig(config);
+ keyboard_controller_.UpdateKeyboardConfig(config);
EXPECT_FALSE(keyboard_controller_.IsKeyboardOverscrollEnabled());
config.overscroll_behavior =
keyboard::mojom::KeyboardOverscrollBehavior::kDefault;
- keyboard::KeyboardController::Get()->UpdateKeyboardConfig(config);
+ keyboard_controller_.UpdateKeyboardConfig(config);
EXPECT_TRUE(keyboard_controller_.IsKeyboardOverscrollEnabled());
// Set keyboard_locked() to true.
diff --git a/chromium/ui/keyboard/public/keyboard_config.mojom b/chromium/ui/keyboard/public/keyboard_config.mojom
index 1c37f572c43..737671d8a48 100644
--- a/chromium/ui/keyboard/public/keyboard_config.mojom
+++ b/chromium/ui/keyboard/public/keyboard_config.mojom
@@ -4,7 +4,7 @@
module keyboard.mojom;
-// Determines how the keyboard overscroll enabled state is set,
+// Determines how the keyboard overscroll enabled state is set.
enum KeyboardOverscrollBehavior {
// Use the default behavior.
kDefault,
diff --git a/chromium/ui/keyboard/public/keyboard_controller_types.mojom b/chromium/ui/keyboard/public/keyboard_controller_types.mojom
new file mode 100644
index 00000000000..95f2f0a685c
--- /dev/null
+++ b/chromium/ui/keyboard/public/keyboard_controller_types.mojom
@@ -0,0 +1,51 @@
+// 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.
+
+module keyboard.mojom;
+
+// Flags that affect whether or not the virtual keyboard should be enabled.
+// Enabled/Disabled flag pairs are mutually exclusive, but flags from multiple
+// sources may be set. Precedence is determined by the implementation in
+// KeyboardController::IsKeyboardEnableRequested.
+enum KeyboardEnableFlag {
+ // Enabled by policy.
+ kPolicyEnabled,
+
+ // Disabled by policy.
+ kPolicyDisabled,
+
+ // Disabled by the Android keyboard.
+ kAndroidDisabled,
+
+ // Enabled by a first-party extension.
+ kExtensionEnabled,
+
+ // Disabled by a first-party extension.
+ kExtensionDisabled,
+
+ // Enabled by an a11y controller.
+ kAccessibilityEnabled,
+
+ // Enabled by the shelf/launcher controller.
+ kShelfEnabled,
+
+ // Enabled by the touch controller.
+ kTouchEnabled,
+
+ // Temporarily enable the keyboard; cleared once the keyboard is shown.
+ kTemporarilyEnabled,
+};
+
+// Container types used to set and identify contaner behavior. Used in UMA
+// stats gathering, so values should never be changed or reused.
+enum ContainerType {
+ // Corresponds to a ContainerFullWidthBehavior.
+ kFullWidth = 0,
+
+ // Corresponds to a ContainerFloatingBehavior.
+ kFloating = 1,
+
+ // Corresponds to a ContainerFullscreenBehavior.
+ kFullscreen = 2,
+};
diff --git a/chromium/ui/keyboard/keyboard_switches.cc b/chromium/ui/keyboard/public/keyboard_switches.cc
index 224cb1c35b1..f99e8e95870 100644
--- a/chromium/ui/keyboard/keyboard_switches.cc
+++ b/chromium/ui/keyboard/public/keyboard_switches.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/keyboard/keyboard_switches.h"
+#include "ui/keyboard/public/keyboard_switches.h"
namespace keyboard {
namespace switches {
diff --git a/chromium/ui/keyboard/keyboard_switches.h b/chromium/ui/keyboard/public/keyboard_switches.h
index bde216b0a3a..ae172d5eae2 100644
--- a/chromium/ui/keyboard/keyboard_switches.h
+++ b/chromium/ui/keyboard/public/keyboard_switches.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_KEYBOARD_KEYBOARD_SWITCHES_H_
-#define UI_KEYBOARD_KEYBOARD_SWITCHES_H_
+#ifndef UI_KEYBOARD_PUBLIC_KEYBOARD_SWITCHES_H_
+#define UI_KEYBOARD_PUBLIC_KEYBOARD_SWITCHES_H_
#include "ui/keyboard/keyboard_export.h"
@@ -27,12 +27,6 @@ KEYBOARD_EXPORT extern const char kDisableGestureEditing[];
// Enables the virtual keyboard.
KEYBOARD_EXPORT extern const char kEnableVirtualKeyboard[];
-// Floating virtual keyboard flag.
-KEYBOARD_EXPORT extern const char kEnableFloatingVirtualKeyboard[];
-
-// Virtual keyboard material design UI flag.
-KEYBOARD_EXPORT extern const char kEnableVirtualKeyboardMdUi[];
-
// Disabled overscrolling of web content when the virtual keyboard is displayed.
// If disabled, the work area is resized to restrict windows from overlapping
// with the keybaord area.
@@ -41,4 +35,4 @@ KEYBOARD_EXPORT extern const char kDisableVirtualKeyboardOverscroll[];
} // namespace switches
} // namespace keyboard
-#endif // UI_KEYBOARD_KEYBOARD_SWITCHES_H_
+#endif // UI_KEYBOARD_PUBLIC_KEYBOARD_SWITCHES_H_
diff --git a/chromium/ui/keyboard/queued_container_type.cc b/chromium/ui/keyboard/queued_container_type.cc
index d876b45c1ab..e2bcfdf3516 100644
--- a/chromium/ui/keyboard/queued_container_type.cc
+++ b/chromium/ui/keyboard/queued_container_type.cc
@@ -9,7 +9,7 @@ namespace keyboard {
QueuedContainerType::QueuedContainerType(
KeyboardController* controller,
- ContainerType container_type,
+ mojom::ContainerType container_type,
base::Optional<gfx::Rect> bounds,
base::OnceCallback<void(bool success)> callback)
: controller_(controller),
diff --git a/chromium/ui/keyboard/queued_container_type.h b/chromium/ui/keyboard/queued_container_type.h
index aa678cd9ec6..ada271900e7 100644
--- a/chromium/ui/keyboard/queued_container_type.h
+++ b/chromium/ui/keyboard/queued_container_type.h
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/optional.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/keyboard/container_type.h"
+#include "ui/keyboard/public/keyboard_controller_types.mojom.h"
namespace keyboard {
@@ -23,16 +23,16 @@ class KeyboardController;
class QueuedContainerType {
public:
QueuedContainerType(KeyboardController* controller,
- ContainerType container_type,
+ mojom::ContainerType container_type,
base::Optional<gfx::Rect> bounds,
base::OnceCallback<void(bool success)> callback);
~QueuedContainerType();
- ContainerType container_type() { return container_type_; }
+ mojom::ContainerType container_type() { return container_type_; }
base::Optional<gfx::Rect> target_bounds() { return bounds_; }
private:
KeyboardController* controller_;
- ContainerType container_type_;
+ mojom::ContainerType container_type_;
base::Optional<gfx::Rect> bounds_;
base::OnceCallback<void(bool success)> callback_;
};
diff --git a/chromium/ui/keyboard/queued_display_change.h b/chromium/ui/keyboard/queued_display_change.h
index 730072116ff..3d2a0c68e55 100644
--- a/chromium/ui/keyboard/queued_display_change.h
+++ b/chromium/ui/keyboard/queued_display_change.h
@@ -9,7 +9,6 @@
#include "base/optional.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/keyboard/container_type.h"
namespace keyboard {
diff --git a/chromium/ui/keyboard/resources/inputview_adapter.js b/chromium/ui/keyboard/resources/inputview_adapter.js
index d030a6154da..4675d31eb10 100644
--- a/chromium/ui/keyboard/resources/inputview_adapter.js
+++ b/chromium/ui/keyboard/resources/inputview_adapter.js
@@ -180,6 +180,7 @@ function registerInputviewApi() {
Quote: 0xBF,
Semicolon: 0xBA,
Slash: 0xBF,
+ Space: 0x20,
Tab: 0x09
};
diff --git a/chromium/ui/keyboard/keyboard_resource_util.cc b/chromium/ui/keyboard/resources/keyboard_resource_util.cc
index b3bb8b8273a..73aa3fcd74d 100644
--- a/chromium/ui/keyboard/keyboard_resource_util.cc
+++ b/chromium/ui/keyboard/resources/keyboard_resource_util.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/keyboard/keyboard_resource_util.h"
+#include "ui/keyboard/resources/keyboard_resource_util.h"
#include "base/files/file_path.h"
#include "base/macros.h"
diff --git a/chromium/ui/keyboard/keyboard_resource_util.h b/chromium/ui/keyboard/resources/keyboard_resource_util.h
index b10dcc575fe..b353e137c1e 100644
--- a/chromium/ui/keyboard/keyboard_resource_util.h
+++ b/chromium/ui/keyboard/resources/keyboard_resource_util.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_KEYBOARD_KEYBOARD_RESOURCE_UTIL_H_
-#define UI_KEYBOARD_KEYBOARD_RESOURCE_UTIL_H_
+#ifndef UI_KEYBOARD_RESOURCES_KEYBOARD_RESOURCE_UTIL_H_
+#define UI_KEYBOARD_RESOURCES_KEYBOARD_RESOURCE_UTIL_H_
#include <stddef.h>
@@ -31,4 +31,4 @@ KEYBOARD_EXPORT void InitializeKeyboardResources();
} // namespace keyboard
-#endif // UI_KEYBOARD_KEYBOARD_RESOURCE_UTIL_H_
+#endif // UI_KEYBOARD_RESOURCES_KEYBOARD_RESOURCE_UTIL_H_
diff --git a/chromium/ui/latency/frame_metrics.cc b/chromium/ui/latency/frame_metrics.cc
index 27f26b9de71..9cd0c257300 100644
--- a/chromium/ui/latency/frame_metrics.cc
+++ b/chromium/ui/latency/frame_metrics.cc
@@ -10,7 +10,7 @@
#include "base/bit_cast.h"
#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
namespace ui {
@@ -100,7 +100,7 @@ constexpr std::initializer_list<uint32_t> kLatencyAccelerationThresholds = {
RatioThreshold(0), RatioThreshold(1), RatioThreshold(2), RatioThreshold(4),
};
-const char kTraceCategories[] = "gpu,benchmark";
+constexpr const char kTraceCategories[] = "gpu,benchmark";
// uint32_t should be plenty of range for real world values, but clip individual
// entries to make sure no single value dominates and also to avoid overflow
@@ -425,36 +425,44 @@ class FrameMetricsTraceData
FrameMetricsTraceData() = default;
~FrameMetricsTraceData() override = default;
- void AppendAsTraceFormat(std::string* out) const override {
- base::trace_event::TracedValue state;
-
- state.BeginDictionary("Source");
- settings.AsValueInto(&state);
- state.EndDictionary();
+ void ToTracedValue(base::trace_event::TracedValue* state) const {
+ state->BeginDictionary("Source");
+ settings.AsValueInto(state);
+ state->EndDictionary();
- state.BeginDictionary("Skips");
- skips.AsValueInto(&state);
- state.EndDictionary();
+ state->BeginDictionary("Skips");
+ skips.AsValueInto(state);
+ state->EndDictionary();
- state.BeginDictionary("Latency");
- latency.AsValueInto(&state);
- state.EndDictionary();
+ state->BeginDictionary("Latency");
+ latency.AsValueInto(state);
+ state->EndDictionary();
if (settings.is_frame_latency_speed_on()) {
- state.BeginDictionary("Speed");
- speed.AsValueInto(&state);
- state.EndDictionary();
+ state->BeginDictionary("Speed");
+ speed.AsValueInto(state);
+ state->EndDictionary();
}
if (settings.is_frame_latency_acceleration_on()) {
- state.BeginDictionary("Acceleration");
- acceleration.AsValueInto(&state);
- state.EndDictionary();
+ state->BeginDictionary("Acceleration");
+ acceleration.AsValueInto(state);
+ state->EndDictionary();
}
+ }
+ void AppendAsTraceFormat(std::string* out) const override {
+ base::trace_event::TracedValue state;
+ ToTracedValue(&state);
state.AppendAsTraceFormat(out);
}
+ bool AppendToProto(ProtoAppender* appender) override {
+ base::trace_event::TracedValue state;
+ ToTracedValue(&state);
+ return state.AppendToProto(appender);
+ }
+
void EstimateTraceMemoryOverhead(
base::trace_event::TraceEventMemoryOverhead* overhead) override {
overhead->Add(base::trace_event::TraceEventMemoryOverhead::kFrameMetrics,
diff --git a/chromium/ui/latency/frame_metrics.h b/chromium/ui/latency/frame_metrics.h
index d0f6f351d6b..147318b50f0 100644
--- a/chromium/ui/latency/frame_metrics.h
+++ b/chromium/ui/latency/frame_metrics.h
@@ -12,7 +12,7 @@
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
#include "ui/latency/skipped_frame_tracker.h"
namespace ui {
diff --git a/chromium/ui/latency/ipc/latency_info_param_traits.cc b/chromium/ui/latency/ipc/latency_info_param_traits.cc
index efe35b7b39d..5aceb85f7ad 100644
--- a/chromium/ui/latency/ipc/latency_info_param_traits.cc
+++ b/chromium/ui/latency/ipc/latency_info_param_traits.cc
@@ -40,6 +40,7 @@ void ParamTraits<ui::LatencyInfo>::Write(base::Pickle* m, const param_type& p) {
WriteParam(m, p.began_);
WriteParam(m, p.terminated_);
WriteParam(m, p.source_event_type_);
+ WriteParam(m, p.scroll_update_delta_);
}
bool ParamTraits<ui::LatencyInfo>::Read(const base::Pickle* m,
@@ -62,6 +63,8 @@ bool ParamTraits<ui::LatencyInfo>::Read(const base::Pickle* m,
return false;
if (!ReadParam(m, iter, &p->source_event_type_))
return false;
+ if (!ReadParam(m, iter, &p->scroll_update_delta_))
+ return false;
return true;
}
@@ -82,6 +85,8 @@ void ParamTraits<ui::LatencyInfo>::Log(const param_type& p, std::string* l) {
LogParam(p.terminated_, l);
l->append(" ");
LogParam(p.source_event_type_, l);
+ l->append(" ");
+ LogParam(p.scroll_update_delta_, l);
}
} // namespace IPC
diff --git a/chromium/ui/latency/ipc/latency_info_param_traits_macros.h b/chromium/ui/latency/ipc/latency_info_param_traits_macros.h
index b70087bdb7d..975d7fce525 100644
--- a/chromium/ui/latency/ipc/latency_info_param_traits_macros.h
+++ b/chromium/ui/latency/ipc/latency_info_param_traits_macros.h
@@ -11,7 +11,6 @@
IPC_ENUM_TRAITS_MAX_VALUE(ui::LatencyComponentType,
ui::LATENCY_COMPONENT_TYPE_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(ui::SourceEventType,
- ui::SourceEventType::SOURCE_EVENT_TYPE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::SourceEventType, ui::SourceEventType::LAST)
#endif // UI_LATENCY_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
diff --git a/chromium/ui/latency/ipc/latency_info_param_traits_unittest.cc b/chromium/ui/latency/ipc/latency_info_param_traits_unittest.cc
index 73afb9b651d..b31706cfe5d 100644
--- a/chromium/ui/latency/ipc/latency_info_param_traits_unittest.cc
+++ b/chromium/ui/latency/ipc/latency_info_param_traits_unittest.cc
@@ -17,6 +17,7 @@ TEST(LatencyInfoParamTraitsTest, Basic) {
LatencyInfo latency;
latency.set_trace_id(5);
latency.set_ukm_source_id(10);
+ latency.set_scroll_update_delta(12.5);
ASSERT_FALSE(latency.terminated());
latency.AddLatencyNumber(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
latency.AddLatencyNumber(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
@@ -35,6 +36,7 @@ TEST(LatencyInfoParamTraitsTest, Basic) {
EXPECT_EQ(latency.trace_id(), output.trace_id());
EXPECT_EQ(latency.ukm_source_id(), output.ukm_source_id());
EXPECT_EQ(latency.terminated(), output.terminated());
+ EXPECT_EQ(latency.scroll_update_delta(), output.scroll_update_delta());
EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
nullptr));
diff --git a/chromium/ui/latency/latency_info.cc b/chromium/ui/latency/latency_info.cc
index aa09366e00f..11b23214f10 100644
--- a/chromium/ui/latency/latency_info.cc
+++ b/chromium/ui/latency/latency_info.cc
@@ -98,7 +98,8 @@ LatencyInfoTracedValue::LatencyInfoTracedValue(base::Value* value)
: value_(value) {
}
-const char kTraceCategoriesForAsyncEvents[] = "benchmark,latencyInfo,rail";
+constexpr const char kTraceCategoriesForAsyncEvents[] =
+ "benchmark,latencyInfo,rail";
struct LatencyInfoEnabledInitializer {
LatencyInfoEnabledInitializer() :
@@ -124,7 +125,8 @@ LatencyInfo::LatencyInfo(SourceEventType type)
coalesced_(false),
began_(false),
terminated_(false),
- source_event_type_(type) {}
+ source_event_type_(type),
+ scroll_update_delta_(0) {}
LatencyInfo::LatencyInfo(const LatencyInfo& other) = default;
@@ -136,7 +138,8 @@ LatencyInfo::LatencyInfo(int64_t trace_id, bool terminated)
coalesced_(false),
began_(false),
terminated_(terminated),
- source_event_type_(SourceEventType::UNKNOWN) {}
+ source_event_type_(SourceEventType::UNKNOWN),
+ scroll_update_delta_(0) {}
bool LatencyInfo::Verify(const std::vector<LatencyInfo>& latency_info,
const char* referring_msg) {
@@ -183,6 +186,7 @@ void LatencyInfo::CopyLatencyFrom(const LatencyInfo& other,
}
coalesced_ = other.coalesced();
+ scroll_update_delta_ = other.scroll_update_delta();
// TODO(tdresser): Ideally we'd copy |began_| here as well, but |began_|
// isn't very intuitive, and we can actually begin multiple times across
// copied events.
@@ -206,6 +210,7 @@ void LatencyInfo::AddNewLatencyFrom(const LatencyInfo& other) {
}
coalesced_ = other.coalesced();
+ scroll_update_delta_ = other.scroll_update_delta();
// TODO(tdresser): Ideally we'd copy |began_| here as well, but |began_| isn't
// very intuitive, and we can actually begin multiple times across copied
// events.
@@ -310,6 +315,18 @@ void LatencyInfo::Terminate() {
TRACE_EVENT_FLAG_FLOW_IN);
}
+void LatencyInfo::CoalesceScrollUpdateWith(const LatencyInfo& other) {
+ base::TimeTicks other_timestamp;
+ if (other.FindLatency(INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT,
+ &other_timestamp)) {
+ latency_components_
+ [INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT] =
+ other_timestamp;
+ }
+
+ scroll_update_delta_ += other.scroll_update_delta();
+}
+
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
LatencyInfo::AsTraceableData() {
std::unique_ptr<base::DictionaryValue> record_data(
diff --git a/chromium/ui/latency/latency_info.h b/chromium/ui/latency/latency_info.h
index eade9fb0b1b..8e242cfcf5c 100644
--- a/chromium/ui/latency/latency_info.h
+++ b/chromium/ui/latency/latency_info.h
@@ -75,6 +75,8 @@ enum LatencyComponentType {
INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT,
// Timestamp when a scroll update is forwarded to the main thread.
INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT,
+ // Original timestamp of the last event that has been coalesced into this one.
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT,
// Timestamp when the event's ack is received by the RWH.
INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
// Timestamp when the frame is swapped in renderer.
@@ -93,7 +95,7 @@ enum LatencyComponentType {
LATENCY_COMPONENT_TYPE_LAST = INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT,
};
-enum SourceEventType {
+enum class SourceEventType {
UNKNOWN,
WHEEL,
MOUSE,
@@ -104,7 +106,7 @@ enum SourceEventType {
TOUCHPAD,
FRAME,
OTHER,
- SOURCE_EVENT_TYPE_LAST = OTHER,
+ LAST = OTHER,
};
class LatencyInfo {
@@ -168,6 +170,10 @@ class LatencyInfo {
void Terminate();
+ // When GestureScrollUpdate events are coalesced, update the aggregated
+ // event's scroll_update_delta and the SCROLL_UPDATE_LAST_EVENT_COMPONENT.
+ void CoalesceScrollUpdateWith(const LatencyInfo& other);
+
const LatencyMap& latency_components() const { return latency_components_; }
const SourceEventType& source_event_type() const {
@@ -186,6 +192,8 @@ class LatencyInfo {
ukm::SourceId ukm_source_id() const { return ukm_source_id_; }
void set_ukm_source_id(ukm::SourceId id) { ukm_source_id_ = id; }
const std::string& trace_name() const { return trace_name_; }
+ void set_scroll_update_delta(float delta) { scroll_update_delta_ = delta; };
+ float scroll_update_delta() const { return scroll_update_delta_; }
private:
void AddLatencyNumberWithTimestampImpl(LatencyComponentType component,
@@ -217,6 +225,8 @@ class LatencyInfo {
// Stores the type of the first source event.
SourceEventType source_event_type_;
+ float scroll_update_delta_;
+
#if !defined(OS_IOS)
friend struct IPC::ParamTraits<ui::LatencyInfo>;
friend struct mojo::StructTraits<ui::mojom::LatencyInfoDataView,
diff --git a/chromium/ui/latency/latency_info_unittest.cc b/chromium/ui/latency/latency_info_unittest.cc
index bd311a12d86..e2269ae8067 100644
--- a/chromium/ui/latency/latency_info_unittest.cc
+++ b/chromium/ui/latency/latency_info_unittest.cc
@@ -40,4 +40,26 @@ TEST(LatencyInfoTest, AddTwoSeparateEvent) {
EXPECT_EQ(timestamp, ToTestTimeTicks(1000));
}
+TEST(LatencyInfoTest, CoalesceTwoGSU) {
+ LatencyInfo info1, info2;
+ info1.set_trace_id(1);
+ info1.AddLatencyNumberWithTimestamp(
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT,
+ ToTestTimeTicks(1234), 1);
+ info1.set_scroll_update_delta(-3);
+
+ info2.set_trace_id(2);
+ info2.AddLatencyNumberWithTimestamp(
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT,
+ ToTestTimeTicks(2345), 1);
+ info2.set_scroll_update_delta(5);
+
+ info1.CoalesceScrollUpdateWith(info2);
+ base::TimeTicks timestamp;
+ EXPECT_TRUE(info1.FindLatency(
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, &timestamp));
+ EXPECT_EQ(timestamp, ToTestTimeTicks(2345));
+ EXPECT_EQ(info1.scroll_update_delta(), 2);
+}
+
} // namespace ui
diff --git a/chromium/ui/latency/latency_tracker.cc b/chromium/ui/latency/latency_tracker.cc
index ef6ce7210cd..415327b5981 100644
--- a/chromium/ui/latency/latency_tracker.cc
+++ b/chromium/ui/latency/latency_tracker.cc
@@ -4,6 +4,7 @@
#include "ui/latency/latency_tracker.h"
+#include <algorithm>
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
@@ -64,16 +65,24 @@ LatencyTracker::LatencyInfoProcessor& GetLatencyInfoProcessor() {
return *processor;
}
+bool LatencyTraceIdCompare(const LatencyInfo& i, const LatencyInfo& j) {
+ return i.trace_id() < j.trace_id();
+}
+
} // namespace
LatencyTracker::LatencyTracker() = default;
+LatencyTracker::~LatencyTracker() = default;
void LatencyTracker::OnGpuSwapBuffersCompleted(
const std::vector<ui::LatencyInfo>& latency_info) {
auto& callback = GetLatencyInfoProcessor();
if (!callback.is_null())
callback.Run(latency_info);
- for (const auto& latency : latency_info)
+ // Sort latency_info as they can be in incorrect order.
+ std::vector<ui::LatencyInfo> latency_infos(latency_info);
+ std::sort(latency_infos.begin(), latency_infos.end(), LatencyTraceIdCompare);
+ for (const auto& latency : latency_infos)
OnGpuSwapBuffersCompleted(latency);
}
@@ -106,10 +115,6 @@ void LatencyTracker::OnGpuSwapBuffersCompleted(const LatencyInfo& latency) {
}
}
-void LatencyTracker::DisableMetricSamplingForTesting() {
- metric_sampling_ = false;
-}
-
void LatencyTracker::ReportUkmScrollLatency(
const InputMetricEvent& metric_event,
base::TimeTicks start_timestamp,
@@ -121,11 +126,6 @@ void LatencyTracker::ReportUkmScrollLatency(
time_to_scroll_update_swap_begin_timestamp)
CONFIRM_EVENT_TIMES_EXIST(start_timestamp, time_to_handled_timestamp)
- // Only report a subset of this metric as the volume is too high.
- if (metric_sampling_ &&
- !sampling_scheme_[static_cast<int>(metric_event)].ShouldReport())
- return;
-
ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
if (ukm_source_id == ukm::kInvalidSourceId || !ukm_recorder)
return;
@@ -245,7 +245,6 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
RecordUmaEventLatencyScrollWheelTimeToScrollUpdateSwapBegin2Histogram(
original_timestamp, gpu_swap_begin_timestamp);
}
-
} else if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
&original_timestamp)) {
if (latency.source_event_type() == SourceEventType::KEY_PRESS) {
@@ -277,6 +276,10 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
// Record scroll latency metrics.
DCHECK(scroll_name == "ScrollBegin" || scroll_name == "ScrollUpdate" ||
(IsInertialScroll(latency) && scroll_name == "ScrollInertial"));
+
+ if (!IsInertialScroll(latency) && input_modality == "Touch")
+ CalculateAverageLag(latency, gpu_swap_begin_timestamp, scroll_name);
+
base::TimeTicks rendering_scheduled_timestamp;
bool rendering_scheduled_on_main = latency.FindLatency(
ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT,
@@ -358,6 +361,132 @@ void LatencyTracker::ComputeEndToEndLatencyHistograms(
gpu_swap_begin_timestamp, gpu_swap_end_timestamp);
}
+void LatencyTracker::CalculateAverageLag(
+ const ui::LatencyInfo& latency,
+ base::TimeTicks gpu_swap_begin_timestamp,
+ const std::string& scroll_name) {
+ base::TimeTicks event_timestamp;
+ bool found_component = latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT,
+ &event_timestamp);
+ DCHECK_AND_RETURN_ON_FAIL(found_component);
+
+ if (scroll_name == "ScrollBegin") {
+ // Clear both lag_reports.
+ ReportAverageLagUma(std::move(pending_finished_lag_report_));
+ if (current_lag_report_)
+ current_lag_report_->report_time = last_frame_time_;
+ ReportAverageLagUma(std::move(current_lag_report_));
+
+ // Create ScrollBegin report, with report time equals to gpu swap time.
+ LagData new_report(scroll_name);
+ pending_finished_lag_report_ = std::make_unique<LagData>(scroll_name);
+ pending_finished_lag_report_->report_time = gpu_swap_begin_timestamp;
+ // For ScrollBegin, we don't have the previous time to calculate the
+ // interpolated area, so the lag is the area between the current event
+ // creation time and gpu swap begin time.
+ pending_finished_lag_report_->lag =
+ (gpu_swap_begin_timestamp - event_timestamp).InMillisecondsF() *
+ latency.scroll_update_delta();
+ // The next report time should be a least 1 second away from current report
+ // time.
+ next_report_time_ = pending_finished_lag_report_->report_time +
+ base::TimeDelta::FromSeconds(1);
+ // Reset last_reported_time to event time.
+ last_reported_time_ = event_timestamp;
+ } else if (scroll_name == "ScrollUpdate" &&
+ !last_event_timestamp_.is_null()) {
+ DCHECK((event_timestamp - last_event_timestamp_).InMilliseconds() >= 0);
+
+ // |pending_finger_move_lag| is the interpolated area between last event to
+ // current event. We assume the finger moved at a constant velocity between
+ // the past two events, so the lag in this duration is calculated by the
+ // average delta(current delta/2).
+ float pending_finger_move_lag =
+ (event_timestamp - last_event_timestamp_).InMillisecondsF() *
+ latency.scroll_update_delta() / 2;
+
+ // |event_dispatch_lag| is the area between the current event creation time
+ // (i.e. last coalesced event of current event creation time) and gpu swap
+ // begin time of this event.
+ float event_dispatch_lag =
+ (gpu_swap_begin_timestamp - event_timestamp).InMillisecondsF() *
+ latency.scroll_update_delta();
+
+ if (pending_finished_lag_report_) {
+ if (event_timestamp >= pending_finished_lag_report_->report_time) {
+ DCHECK_GE(pending_finished_lag_report_->report_time,
+ last_event_timestamp_);
+ // This event is created after this report's report time, so part of
+ // the |pending_finger_move_lag| should be counted in this report, the
+ // rest should be count in the following report. The area of first part
+ // is calculated by similar triangle area.
+ float ratio =
+ (pending_finished_lag_report_->report_time - last_event_timestamp_)
+ .InMillisecondsF() /
+ (event_timestamp - last_event_timestamp_).InMillisecondsF();
+ pending_finished_lag_report_->lag +=
+ pending_finger_move_lag * ratio * ratio;
+ pending_finger_move_lag *= 1 - ratio * ratio;
+ ReportAverageLagUma(std::move(pending_finished_lag_report_));
+ } else { // event_timestamp < pending_finished_lag_report_->report_time
+ DCHECK_LE(pending_finished_lag_report_->report_time,
+ gpu_swap_begin_timestamp);
+ // This event is created before this report's report_time, so
+ // |pending_finger_move_lag|, and also part of |event_dispatch_lag| that
+ // before |report_time| should be counted in this report.
+ float lag_after_report_time =
+ (gpu_swap_begin_timestamp -
+ pending_finished_lag_report_->report_time)
+ .InMillisecondsF() *
+ latency.scroll_update_delta();
+ pending_finished_lag_report_->lag += pending_finger_move_lag +
+ event_dispatch_lag -
+ lag_after_report_time;
+ pending_finger_move_lag = 0;
+ event_dispatch_lag = lag_after_report_time;
+ }
+ }
+
+ // Remaining pending lag should be counted in the |current_lag_report_|.
+ if (pending_finger_move_lag + event_dispatch_lag != 0) {
+ if (!current_lag_report_)
+ current_lag_report_ = std::make_unique<LagData>(scroll_name);
+
+ current_lag_report_->lag += pending_finger_move_lag + event_dispatch_lag;
+
+ // When current gpu_swap_time is larger than the |next_report_time_|,
+ // it means the we reach the 1 second gap, and we can filled in the
+ // timestamp and move it to |pending_finished_lag_report_|. We use
+ // the current|gpu_swap_begin_timestamp| as the report_time, so it can
+ // be align with gpu swaps.
+ if (gpu_swap_begin_timestamp >= next_report_time_) {
+ current_lag_report_->report_time = gpu_swap_begin_timestamp;
+ // The next report time is 1 second away from this report time.
+ next_report_time_ =
+ gpu_swap_begin_timestamp + base::TimeDelta::FromSeconds(1);
+ DCHECK(!pending_finished_lag_report_);
+ pending_finished_lag_report_ = std::move(current_lag_report_);
+ DCHECK(!current_lag_report_);
+ }
+ }
+ }
+ last_event_timestamp_ = event_timestamp;
+ last_frame_time_ = gpu_swap_begin_timestamp;
+}
+
+void LatencyTracker::ReportAverageLagUma(std::unique_ptr<LagData> report) {
+ if (report) {
+ DCHECK(!report->report_time.is_null());
+ base::UmaHistogramCounts1000(
+ "Event.Latency." + report->scroll_name + ".Touch.AverageLag",
+ std::abs(report->lag) /
+ (report->report_time - last_reported_time_).InMillisecondsF());
+
+ last_reported_time_ = report->report_time;
+ }
+}
+
// static
void LatencyTracker::SetLatencyInfoProcessorForTesting(
const LatencyInfoProcessor& processor) {
diff --git a/chromium/ui/latency/latency_tracker.h b/chromium/ui/latency/latency_tracker.h
index 4acae570d12..d7ac971903c 100644
--- a/chromium/ui/latency/latency_tracker.h
+++ b/chromium/ui/latency/latency_tracker.h
@@ -5,6 +5,7 @@
#ifndef UI_LATENCY_LATENCY_TRACKER_H_
#define UI_LATENCY_LATENCY_TRACKER_H_
+#include <deque>
#include "base/macros.h"
#include "ui/latency/latency_info.h"
@@ -15,7 +16,7 @@ namespace ui {
class LatencyTracker {
public:
LatencyTracker();
- ~LatencyTracker() = default;
+ ~LatencyTracker();
// Terminates latency tracking for events that triggered rendering, also
// performing relevant UMA latency reporting.
@@ -23,9 +24,6 @@ class LatencyTracker {
void OnGpuSwapBuffersCompleted(const std::vector<LatencyInfo>& latency_info);
void OnGpuSwapBuffersCompleted(const LatencyInfo& latency);
- // Disables sampling of high volume metrics in unit tests.
- void DisableMetricSamplingForTesting();
-
using LatencyInfoProcessor =
base::RepeatingCallback<void(const std::vector<ui::LatencyInfo>&)>;
static void SetLatencyInfoProcessorForTesting(
@@ -54,37 +52,41 @@ class LatencyTracker {
base::TimeTicks gpu_swap_end_timestamp,
const LatencyInfo& latency);
- typedef struct SamplingScheme {
- SamplingScheme() : interval_(1), last_sample_(0) {}
- SamplingScheme(int interval)
- : interval_(interval), last_sample_(rand() % interval) {}
- bool ShouldReport() {
- last_sample_++;
- last_sample_ %= interval_;
- return last_sample_ == 0;
- }
-
- private:
- int interval_;
- int last_sample_;
- } SamplingScheme;
-
- // Whether the sampling is needed for high volume metrics. This will be off
- // when we are in unit tests. This is a temporary field so we can come up with
- // a more permanent solution for crbug.com/739169.
- bool metric_sampling_ = true;
-
- // The i'th member of this array stores the sampling rate for the i'th
- // input metric event type. Initializing SamplingScheme with number X means
- // that from every X events one will be reported. Note that the first event
- // to report is also randomized.
- SamplingScheme sampling_scheme_
- [static_cast<int>(InputMetricEvent::INPUT_METRIC_EVENT_MAX) + 1] = {
- SamplingScheme(5), // SCROLL_BEGIN_TOUCH
- SamplingScheme(50), // SCROLL_UPDATE_TOUCH
- SamplingScheme(5), // SCROLL_BEGIN_WHEEL
- SamplingScheme(2), // SCROLL_UPDATE_WHEEL
- };
+ void CalculateAverageLag(const ui::LatencyInfo& latency,
+ base::TimeTicks gpu_swap_begin_timestamp,
+ const std::string& scroll_name);
+
+ // Used for reporting AverageLag metrics.
+ typedef struct LagData {
+ LagData(const std::string& name)
+ : report_time(base::TimeTicks()), lag(0), scroll_name(name) {}
+ // Lag report's report_time, align with |gpu_swap_begin_time|. It should has
+ // one second gap between previous report. We do not set the report_time
+ // before the 1 second gap is reached.
+ base::TimeTicks report_time;
+ float lag;
+ const std::string scroll_name;
+ } LagData;
+
+ void ReportAverageLagUma(std::unique_ptr<LagData> report);
+
+ // Last scroll event's timestamp in the sequence, reset on ScrollBegin.
+ base::TimeTicks last_event_timestamp_;
+ // next_report_time is always 1 second after the newest report's report_time.
+ base::TimeTicks next_report_time_;
+ // This keeps track the last report_time when we report to UMA, so we can
+ // calculate the report's duration by current - last. Reset on ScrollBegin.
+ base::TimeTicks last_reported_time_;
+ // Keeps track of last gpu_swap time, so we can end the previous unfinished
+ // report on the new ScrollBegin.
+ base::TimeTicks last_frame_time_;
+ // Lag report that already filled in the report_time, and it will be finished
+ // and report once we have an event whose timestamp is later then the
+ // report_time.
+ std::unique_ptr<LagData> pending_finished_lag_report_;
+ // The current unfinished lag report, which doesn't reach the 1 second length
+ // yet. It's report_time is null and invalid now.
+ std::unique_ptr<LagData> current_lag_report_;
DISALLOW_COPY_AND_ASSIGN(LatencyTracker);
};
diff --git a/chromium/ui/latency/mojo/latency_info.mojom b/chromium/ui/latency/mojo/latency_info.mojom
index ee082c716b5..da021bd0be3 100644
--- a/chromium/ui/latency/mojo/latency_info.mojom
+++ b/chromium/ui/latency/mojo/latency_info.mojom
@@ -42,6 +42,8 @@ enum LatencyComponentType {
INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT,
// Timestamp when a scroll update is forwarded to the main thread.
INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT,
+ // Timestamp for last event that has been coalesced into this one.
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT,
// Timestamp when the event's ack is received by the RWH.
INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
// Timestamp when the frame is swapped in renderer.
@@ -79,4 +81,5 @@ struct LatencyInfo {
bool began;
bool terminated;
SourceEventType source_event_type;
+ float scroll_update_delta;
};
diff --git a/chromium/ui/latency/mojo/latency_info_struct_traits.cc b/chromium/ui/latency/mojo/latency_info_struct_traits.cc
index a1ac873ed10..2ca2451d94c 100644
--- a/chromium/ui/latency/mojo/latency_info_struct_traits.cc
+++ b/chromium/ui/latency/mojo/latency_info_struct_traits.cc
@@ -12,23 +12,23 @@ namespace {
ui::mojom::SourceEventType UISourceEventTypeToMojo(ui::SourceEventType type) {
switch (type) {
- case ui::UNKNOWN:
+ case ui::SourceEventType::UNKNOWN:
return ui::mojom::SourceEventType::UNKNOWN;
- case ui::WHEEL:
+ case ui::SourceEventType::WHEEL:
return ui::mojom::SourceEventType::WHEEL;
- case ui::MOUSE:
+ case ui::SourceEventType::MOUSE:
return ui::mojom::SourceEventType::MOUSE;
- case ui::TOUCH:
+ case ui::SourceEventType::TOUCH:
return ui::mojom::SourceEventType::TOUCH;
- case ui::INERTIAL:
+ case ui::SourceEventType::INERTIAL:
return ui::mojom::SourceEventType::INERTIAL;
- case ui::KEY_PRESS:
+ case ui::SourceEventType::KEY_PRESS:
return ui::mojom::SourceEventType::KEY_PRESS;
- case ui::TOUCHPAD:
+ case ui::SourceEventType::TOUCHPAD:
return ui::mojom::SourceEventType::TOUCHPAD;
- case ui::FRAME:
+ case ui::SourceEventType::FRAME:
return ui::mojom::SourceEventType::FRAME;
- case ui::OTHER:
+ case ui::SourceEventType::OTHER:
return ui::mojom::SourceEventType::OTHER;
}
NOTREACHED();
@@ -38,23 +38,23 @@ ui::mojom::SourceEventType UISourceEventTypeToMojo(ui::SourceEventType type) {
ui::SourceEventType MojoSourceEventTypeToUI(ui::mojom::SourceEventType type) {
switch (type) {
case ui::mojom::SourceEventType::UNKNOWN:
- return ui::UNKNOWN;
+ return ui::SourceEventType::UNKNOWN;
case ui::mojom::SourceEventType::WHEEL:
- return ui::WHEEL;
+ return ui::SourceEventType::WHEEL;
case ui::mojom::SourceEventType::MOUSE:
- return ui::MOUSE;
+ return ui::SourceEventType::MOUSE;
case ui::mojom::SourceEventType::TOUCH:
- return ui::TOUCH;
+ return ui::SourceEventType::TOUCH;
case ui::mojom::SourceEventType::INERTIAL:
- return ui::INERTIAL;
+ return ui::SourceEventType::INERTIAL;
case ui::mojom::SourceEventType::KEY_PRESS:
- return ui::KEY_PRESS;
+ return ui::SourceEventType::KEY_PRESS;
case ui::mojom::SourceEventType::TOUCHPAD:
- return ui::TOUCHPAD;
+ return ui::SourceEventType::TOUCHPAD;
case ui::mojom::SourceEventType::FRAME:
- return ui::FRAME;
+ return ui::SourceEventType::FRAME;
case ui::mojom::SourceEventType::OTHER:
- return ui::OTHER;
+ return ui::SourceEventType::OTHER;
}
NOTREACHED();
return ui::SourceEventType::UNKNOWN;
@@ -115,6 +115,13 @@ StructTraits<ui::mojom::LatencyInfoDataView,
}
// static
+float StructTraits<ui::mojom::LatencyInfoDataView,
+ ui::LatencyInfo>::scroll_update_delta(const ui::LatencyInfo&
+ info) {
+ return info.scroll_update_delta();
+}
+
+// static
bool StructTraits<ui::mojom::LatencyInfoDataView, ui::LatencyInfo>::Read(
ui::mojom::LatencyInfoDataView data,
ui::LatencyInfo* out) {
@@ -128,6 +135,7 @@ bool StructTraits<ui::mojom::LatencyInfoDataView, ui::LatencyInfo>::Read(
out->began_ = data.began();
out->terminated_ = data.terminated();
out->source_event_type_ = MojoSourceEventTypeToUI(data.source_event_type());
+ out->scroll_update_delta_ = data.scroll_update_delta();
return true;
}
@@ -184,6 +192,9 @@ EnumTraits<ui::mojom::LatencyComponentType, ui::LatencyComponentType>::ToMojom(
case ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT:
return ui::mojom::LatencyComponentType::
INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT;
+ case ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT:
+ return ui::mojom::LatencyComponentType::
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT;
case ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT:
return ui::mojom::LatencyComponentType::
INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT;
@@ -289,6 +300,10 @@ bool EnumTraits<ui::mojom::LatencyComponentType, ui::LatencyComponentType>::
INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT:
*output = ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT;
return true;
+ case ui::mojom::LatencyComponentType::
+ INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT:
+ *output = ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT;
+ return true;
}
return false;
}
diff --git a/chromium/ui/latency/mojo/latency_info_struct_traits.h b/chromium/ui/latency/mojo/latency_info_struct_traits.h
index 00ab6f2069f..5844fec11b1 100644
--- a/chromium/ui/latency/mojo/latency_info_struct_traits.h
+++ b/chromium/ui/latency/mojo/latency_info_struct_traits.h
@@ -15,7 +15,7 @@ static_assert(static_cast<int>(ui::mojom::LatencyComponentType::kMaxValue) ==
"Enum size mismatch");
static_assert(static_cast<int>(ui::mojom::SourceEventType::kMaxValue) ==
- static_cast<int>(ui::SOURCE_EVENT_TYPE_LAST),
+ static_cast<int>(ui::SourceEventType::LAST),
"Enum size mismatch");
template <>
@@ -54,6 +54,7 @@ struct StructTraits<ui::mojom::LatencyInfoDataView, ui::LatencyInfo> {
static bool terminated(const ui::LatencyInfo& info);
static ui::mojom::SourceEventType source_event_type(
const ui::LatencyInfo& info);
+ static float scroll_update_delta(const ui::LatencyInfo& info);
static bool Read(ui::mojom::LatencyInfoDataView data, ui::LatencyInfo* out);
};
diff --git a/chromium/ui/latency/mojo/struct_traits_unittest.cc b/chromium/ui/latency/mojo/struct_traits_unittest.cc
index b764b6e5859..4f03eecc22b 100644
--- a/chromium/ui/latency/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/latency/mojo/struct_traits_unittest.cc
@@ -52,7 +52,7 @@ TEST_F(StructTraitsTest, LatencyInfo) {
EXPECT_EQ(10, latency.ukm_source_id());
EXPECT_TRUE(latency.terminated());
- latency.set_source_event_type(ui::TOUCH);
+ latency.set_source_event_type(ui::SourceEventType::TOUCH);
mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
LatencyInfo output;
diff --git a/chromium/ui/latency/skipped_frame_tracker.cc b/chromium/ui/latency/skipped_frame_tracker.cc
index 3eabe52ac4f..fe5fc7a1737 100644
--- a/chromium/ui/latency/skipped_frame_tracker.cc
+++ b/chromium/ui/latency/skipped_frame_tracker.cc
@@ -28,7 +28,6 @@ void SkippedFrameTracker::BeginFrame(base::TimeTicks frame_time,
}
void SkippedFrameTracker::FinishFrame() {
- DCHECK(inside_begin_frame_);
inside_begin_frame_ = false;
// Assume the source is idle if it hasn't attempted to produce for an entire
@@ -93,4 +92,13 @@ void SkippedFrameTracker::DidProduceFrame() {
did_produce_this_frame_ = true;
}
+void SkippedFrameTracker::WillNotProduceFrame() {
+ if (active_state_ != ActiveState::Idle) {
+ inside_begin_frame_ = false;
+ did_produce_this_frame_ = false;
+ will_produce_frame_time_ = base::TimeTicks();
+ active_state_ = ActiveState::Idle;
+ }
+}
+
} // namespace ui
diff --git a/chromium/ui/latency/skipped_frame_tracker.h b/chromium/ui/latency/skipped_frame_tracker.h
index e45eee95af0..1ee0d0d3dc3 100644
--- a/chromium/ui/latency/skipped_frame_tracker.h
+++ b/chromium/ui/latency/skipped_frame_tracker.h
@@ -41,13 +41,15 @@ class SkippedFrameTracker {
// WillProduceFrame should be called when the source knows it wants to
// produce a frame. DidProduceFrame should be called when the source has
- // actually submitted the frame.
+ // actually submitted the frame. WillNotProduceFrame should be called when
+ // the source knows if doesn't need a new frame.
// It is okay for DidProduceFrame to be called without WillProduceFrame,
// which can happen in cases where a frame is "pulled" from later in the
// pipeline rather than pushed from the source. Such calls to DidProduceFrame
// will be ignored.
void WillProduceFrame();
void DidProduceFrame();
+ void WillNotProduceFrame();
protected:
Client* client_;
diff --git a/chromium/ui/latency/skipped_frame_tracker_unittest.cc b/chromium/ui/latency/skipped_frame_tracker_unittest.cc
index 3218b3d500f..06812c5c222 100644
--- a/chromium/ui/latency/skipped_frame_tracker_unittest.cc
+++ b/chromium/ui/latency/skipped_frame_tracker_unittest.cc
@@ -75,6 +75,12 @@ class SkippedFrameTrackerTest : public testing::Test {
return MaybeCallCountFailure(call_count);
}
+ ::testing::AssertionResult WillNotProduceFrame() {
+ int call_count = client_.call_count_;
+ tracker_.WillNotProduceFrame();
+ return MaybeCallCountFailure(call_count);
+ }
+
::testing::AssertionResult WillProduceFrame() {
int call_count = client_.call_count_;
tracker_.WillProduceFrame();
@@ -241,6 +247,47 @@ TEST_F(SkippedFrameTrackerTest, NoSkips_ActiveIdleActive_JumpInIdle) {
EXPECT_TRUE(tracker_.IsActive());
}
+// Active, Set idle after WillProduceFrame, then active again.
+TEST_F(SkippedFrameTrackerTest, WillNotProduceFrame) {
+ EXPECT_TRUE(BeginFrame(100, 10));
+ EXPECT_TRUE(WillProduceFrame());
+ EXPECT_TRUE(DidProduceFrame());
+ VERIFY_ADD_PRODUCED_CALLED(100, 10, 0);
+ EXPECT_TRUE(FinishFrame());
+ EXPECT_TRUE(tracker_.IsActive());
+
+ EXPECT_TRUE(BeginFrame(110, 10));
+ EXPECT_TRUE(WillNotProduceFrame());
+ EXPECT_FALSE(tracker_.IsActive());
+
+ EXPECT_TRUE(WillProduceFrame());
+ EXPECT_TRUE(BeginFrame(200, 10));
+ EXPECT_TRUE(DidProduceFrame());
+ VERIFY_ADD_PRODUCED_CALLED(200, 10, 0);
+ EXPECT_TRUE(FinishFrame());
+ EXPECT_TRUE(tracker_.IsActive());
+}
+
+// Active, idle, then active again.
+TEST_F(SkippedFrameTrackerTest, WillNotProduceFrame2) {
+ EXPECT_TRUE(BeginFrame(100, 10));
+ EXPECT_TRUE(WillProduceFrame());
+ EXPECT_TRUE(DidProduceFrame());
+ VERIFY_ADD_PRODUCED_CALLED(100, 10, 0);
+ EXPECT_TRUE(FinishFrame());
+ EXPECT_TRUE(tracker_.IsActive());
+
+ EXPECT_TRUE(WillNotProduceFrame());
+ EXPECT_FALSE(tracker_.IsActive());
+
+ EXPECT_TRUE(WillProduceFrame());
+ EXPECT_TRUE(BeginFrame(200, 10));
+ EXPECT_TRUE(DidProduceFrame());
+ VERIFY_ADD_PRODUCED_CALLED(200, 10, 0);
+ EXPECT_TRUE(FinishFrame());
+ EXPECT_TRUE(tracker_.IsActive());
+}
+
// If frames are pulled from later in the pipeline when the source hasn't tried
// to create a new frame, it should not be recorded as a frame produced
// by the source.
@@ -347,5 +394,17 @@ TEST_F(SkippedFrameTrackerTest, NoSkips_ActiveIdleActive_FramePulledIsPush) {
EXPECT_FALSE(tracker_.IsActive());
}
+// Simulate that SetNeedsRedraw is called, then the client realized that it
+// doesn't need a new BeginFrame.
+TEST_F(SkippedFrameTrackerTest, NoFrameProduced) {
+ EXPECT_TRUE(WillProduceFrame());
+ EXPECT_TRUE(WillNotProduceFrame());
+
+ // Since no BeginFrame is needed, number of frames produced and the number
+ // of skipped frames should all be 0.
+ EXPECT_EQ(0, client_.amount_produced_);
+ EXPECT_EQ(0, client_.amount_skipped_);
+}
+
} // namespace
} // namespace ui
diff --git a/chromium/ui/latency/stream_analyzer.h b/chromium/ui/latency/stream_analyzer.h
index ac550c80a4f..cd20ff3c343 100644
--- a/chromium/ui/latency/stream_analyzer.h
+++ b/chromium/ui/latency/stream_analyzer.h
@@ -10,7 +10,7 @@
#include <vector>
#include "base/macros.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
#include "ui/latency/fixed_point.h"
#include "ui/latency/histograms.h"
#include "ui/latency/windowed_analyzer.h"
diff --git a/chromium/ui/latency/windowed_analyzer.h b/chromium/ui/latency/windowed_analyzer.h
index 3cc15bb577c..04b08cd4ac2 100644
--- a/chromium/ui/latency/windowed_analyzer.h
+++ b/chromium/ui/latency/windowed_analyzer.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/optional.h"
#include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
#include "ui/latency/fixed_point.h"
namespace ui {
diff --git a/chromium/ui/login/account_picker/md_user_pod_template.html b/chromium/ui/login/account_picker/md_user_pod_template.html
index 965870022f7..2ce17750208 100644
--- a/chromium/ui/login/account_picker/md_user_pod_template.html
+++ b/chromium/ui/login/account_picker/md_user_pod_template.html
@@ -4,7 +4,10 @@
</template>
</dom-module>
-<style is="custom-style" include="user-pod-template-shared-styles"></style>
+<custom-style>
+ <style is="custom-style" include="user-pod-template-shared-styles"></style>
+</custom-style>
+
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<iron-iconset-svg name="user-pod" size="24">
diff --git a/chromium/ui/login/display_manager.js b/chromium/ui/login/display_manager.js
index 53ef9909a6b..c32adf58ec4 100644
--- a/chromium/ui/login/display_manager.js
+++ b/chromium/ui/login/display_manager.js
@@ -75,7 +75,8 @@
SAML_PASSWORD_CONFIRM: 5,
PASSWORD_CHANGED: 6,
ENROLLMENT: 7,
- ERROR: 8
+ ERROR: 8,
+ SYNC_CONSENT: 9,
};
/* Possible UI states of the error screen. */
@@ -502,7 +503,7 @@ cr.define('cr.ui.login', function() {
} else if (name == ACCELERATOR_BOOTSTRAPPING_SLAVE) {
chrome.send('setOobeBootstrappingSlave');
} else if (name == ACCELERATOR_DEMO_MODE) {
- this.showEnableDemoModeDialog_();
+ this.startDemoModeFlow();
} else if (name == ACCELERATOR_SEND_FEEDBACK) {
chrome.send('sendFeedback');
}
@@ -917,7 +918,7 @@ cr.define('cr.ui.login', function() {
initializeDemoModeMultiTapListener: function() {
if (this.displayType_ == DISPLAY_TYPE.OOBE) {
this.demoModeStartListener_ = new MultiTapDetector(
- $('outer-container'), 10, this.showEnableDemoModeDialog_.bind(this));
+ $('outer-container'), 10, this.startDemoModeFlow.bind(this));
}
},
@@ -1013,10 +1014,9 @@ cr.define('cr.ui.login', function() {
},
/**
- * Shows the enable demo mode dialog.
- * @private
+ * Starts demo mode flow. Shows the enable demo mode dialog if needed.
*/
- showEnableDemoModeDialog_: function() {
+ startDemoModeFlow: function() {
var isDemoModeEnabled = loadTimeData.getBoolean('isDemoModeEnabled');
if (!isDemoModeEnabled) {
console.warn('Cannot setup demo mode, because it is disabled.');
@@ -1035,13 +1035,18 @@ cr.define('cr.ui.login', function() {
this.enableDemoModeDialog_.setCancelLabel(
loadTimeData.getString('enableDemoModeDialogCancel'));
}
-
- this.enableDemoModeDialog_.showWithTitle(
- loadTimeData.getString('enableDemoModeDialogTitle'),
- loadTimeData.getString('enableDemoModeDialogText'),
- function() { // onOk
- chrome.send('setupDemoMode');
- });
+ var configuration = Oobe.getInstance().getOobeConfiguration();
+ if (configuration && configuration.enableDemoMode) {
+ // Bypass showing dialog.
+ chrome.send('setupDemoMode');
+ } else {
+ this.enableDemoModeDialog_.showWithTitle(
+ loadTimeData.getString('enableDemoModeDialogTitle'),
+ loadTimeData.getString('enableDemoModeDialogText'),
+ function() { // onOk
+ chrome.send('setupDemoMode');
+ });
+ }
},
/**
diff --git a/chromium/ui/message_center/BUILD.gn b/chromium/ui/message_center/BUILD.gn
index 99243819620..ee5189f31b6 100644
--- a/chromium/ui/message_center/BUILD.gn
+++ b/chromium/ui/message_center/BUILD.gn
@@ -62,14 +62,6 @@ jumbo_component("message_center") {
"//build/config/compiler:no_size_t_to_int_warning",
]
sources = [
- "cocoa/notification_controller.h",
- "cocoa/notification_controller.mm",
- "cocoa/opaque_views.h",
- "cocoa/opaque_views.mm",
- "cocoa/popup_collection.h",
- "cocoa/popup_collection.mm",
- "cocoa/popup_controller.h",
- "cocoa/popup_controller.mm",
"lock_screen/empty_lock_screen_controller.cc",
"lock_screen/empty_lock_screen_controller.h",
"lock_screen/lock_screen_controller.h",
@@ -103,16 +95,7 @@ jumbo_component("message_center") {
]
}
- if (is_mac) {
- libs = [
- "AppKit.framework",
- "Foundation.framework",
- ]
- }
-
- # On Mac, toolkit-views builds still use the Cocoa UI. Keep this in sync
- # with message_center_unittests below.
- if (toolkit_views && !is_mac) {
+ if (toolkit_views) {
sources += [
"views/bounded_label.cc",
"views/bounded_label.h",
@@ -122,6 +105,7 @@ jumbo_component("message_center") {
"views/message_popup_collection.h",
"views/message_popup_view.cc",
"views/message_popup_view.h",
+ "views/message_popup_view_mac.mm",
"views/message_view.cc",
"views/message_view.h",
"views/message_view_factory.cc",
@@ -194,9 +178,6 @@ if (enable_message_center) {
test("message_center_unittests") {
sources = [
- "cocoa/notification_controller_unittest.mm",
- "cocoa/popup_collection_unittest.mm",
- "cocoa/popup_controller_unittest.mm",
"lock_screen/fake_lock_screen_controller.cc",
"lock_screen/fake_lock_screen_controller.h",
"message_center_impl_unittest.cc",
@@ -243,16 +224,13 @@ if (enable_message_center) {
]
}
- if (is_mac) {
- deps += [ "//ui/gfx:test_support" ]
- }
-
- if (toolkit_views && !is_mac) {
+ if (toolkit_views) {
sources += [
"views/bounded_label_unittest.cc",
"views/message_popup_collection_unittest.cc",
"views/notification_view_md_unittest.cc",
"views/notification_view_unittest.cc",
+ "views/slide_out_controller_unittest.cc",
]
if (!is_chromeos) {
sources += [ "views/notification_menu_model_unittest.cc" ]
diff --git a/chromium/ui/message_center/cocoa/notification_controller.h b/chromium/ui/message_center/cocoa/notification_controller.h
deleted file mode 100644
index ef214f1fbcf..00000000000
--- a/chromium/ui/message_center/cocoa/notification_controller.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_MESSAGE_CENTER_COCOA_NOTIFICATION_CONTROLLER_H_
-#define UI_MESSAGE_CENTER_COCOA_NOTIFICATION_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <string>
-
-#import "base/mac/scoped_nsobject.h"
-#include "ui/message_center/message_center_export.h"
-
-namespace message_center {
-class MessageCenter;
-class Notification;
-}
-
-@class HoverImageButton;
-
-namespace message_center {
-// A struct that can hold all the temporary frames
-// created when adjusting a view
-struct NotificationLayoutParams {
- NSRect rootFrame;
- NSRect titleFrame;
- NSRect messageFrame;
- NSRect contextMessageFrame;
- NSRect settingsButtonFrame;
- NSRect listFrame;
- NSRect progressBarFrame;
-};
-}
-
-// The base view controller class for notifications. A notification at minimum
-// has an image, title, body, and close button. This controller can be used as
-// the content for both a popup bubble and a view in the notification tray.
-MESSAGE_CENTER_EXPORT
-@interface MCNotificationController : NSViewController {
- @protected
- // The message object. Weak.
- const message_center::Notification* notification_;
-
- // A copy of the notification ID.
- std::string notificationID_;
-
- // Controller of the notifications, where action messages are forwarded. Weak.
- message_center::MessageCenter* messageCenter_;
-
- // The button that invokes |-close:|, in the upper-right corner.
- base::scoped_nsobject<HoverImageButton> closeButton_;
-
- // The button that invokes |-settingsClicked:|, in the bottom right corner of
- // the context message.
- base::scoped_nsobject<HoverImageButton> settingsButton_;
-
- // The small icon associated with the notification, on the bottom right.
- base::scoped_nsobject<NSImageView> smallImage_;
-
- // The large icon associated with the notification, on the left side.
- base::scoped_nsobject<NSImageView> icon_;
-
- // The title of the message.
- base::scoped_nsobject<NSTextView> title_;
-
- // Body text of the message. Hidden for list notifications.
- base::scoped_nsobject<NSTextView> message_;
-
- // Context-giving text of the message. Alternate font used to distinguish it.
- base::scoped_nsobject<NSTextView> contextMessage_;
-
- // Container for optional list view that contains multiple items.
- base::scoped_nsobject<NSView> listView_;
-
- // Container for optional progress bar view.
- base::scoped_nsobject<NSProgressIndicator> progressBarView_;
-
- // Container for optional items at the bottom of the notification.
- base::scoped_nsobject<NSView> bottomView_;
-}
-
-// Creates a new controller for a given notification.
-- (id)initWithNotification:(const message_center::Notification*)notification
- messageCenter:(message_center::MessageCenter*)messageCenter;
-
-// If the model object changes, this method will update the views to reflect
-// the new model object. Returns the updated frame of the notification.
-- (NSRect)updateNotification:(const message_center::Notification*)notification;
-
-// Action for clicking on the notification's |closeButton_|.
-- (void)close:(id)sender;
-
-// Action for clicking on the notification's |settingsButton_|.
-- (void)settingsClicked:(id)sender;
-
-// Accessor for the notification.
-- (const message_center::Notification*)notification;
-
-// Gets the notification ID. This string is owned by the NotificationController
-// rather than the model object, so it's safe to use after the Notification has
-// been deleted.
-- (const std::string&)notificationID;
-
-// Called when the user clicks within the notification view.
-- (void)notificationClicked;
-
-// Adjust the position and height of all the internal frames by |delta|.
-- (void)adjustFrameHeight:(message_center::NotificationLayoutParams*)frames
- delta:(CGFloat)delta;
-
-@end
-
-@interface MCNotificationController (TestingInterface)
-- (NSImageView*)smallImageView;
-- (NSImageView*)iconView;
-@end
-
-#endif // UI_MESSAGE_CENTER_COCOA_NOTIFICATION_CONTROLLER_H_
diff --git a/chromium/ui/message_center/cocoa/notification_controller.mm b/chromium/ui/message_center/cocoa/notification_controller.mm
deleted file mode 100644
index 38cb370b42b..00000000000
--- a/chromium/ui/message_center/cocoa/notification_controller.mm
+++ /dev/null
@@ -1,995 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/message_center/cocoa/notification_controller.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-
-#include "base/mac/foundation_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/url_formatter/elide_url.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "ui/base/cocoa/hover_image_button.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/text_elider.h"
-#include "ui/gfx/text_utils.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/message_center_style.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
-#include "ui/message_center/public/cpp/notification.h"
-#include "ui/resources/grit/ui_resources.h"
-#include "ui/strings/grit/ui_strings.h"
-#include "url/gurl.h"
-
-@interface MCNotificationProgressBar : NSProgressIndicator
-@end
-
-@implementation MCNotificationProgressBar
-- (void)drawRect:(NSRect)dirtyRect {
- NSRect sliceRect, remainderRect;
- double progressFraction = ([self doubleValue] - [self minValue]) /
- ([self maxValue] - [self minValue]);
- NSDivideRect(dirtyRect, &sliceRect, &remainderRect,
- NSWidth(dirtyRect) * progressFraction, NSMinXEdge);
-
- NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:dirtyRect
- xRadius:message_center::kProgressBarCornerRadius
- yRadius:message_center::kProgressBarCornerRadius];
- [skia::SkColorToCalibratedNSColor(message_center::kProgressBarBackgroundColor)
- set];
- [path fill];
-
- if (progressFraction == 0.0)
- return;
-
- path = [NSBezierPath bezierPathWithRoundedRect:sliceRect
- xRadius:message_center::kProgressBarCornerRadius
- yRadius:message_center::kProgressBarCornerRadius];
- [skia::SkColorToCalibratedNSColor(message_center::kProgressBarSliceColor)
- set];
- [path fill];
-}
-
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- double progressValue = 0.0;
- if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
- progressValue = [self doubleValue];
- } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) {
- progressValue = [self minValue];
- } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) {
- progressValue = [self maxValue];
- } else {
- return [super accessibilityAttributeValue:attribute];
- }
-
- return [NSString stringWithFormat:@"%lf", progressValue];
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-@interface MCNotificationButton : NSButton
-@end
-
-@implementation MCNotificationButton
-// drawRect: needs to fill the button with a background, otherwise we don't get
-// subpixel antialiasing.
-- (void)drawRect:(NSRect)dirtyRect {
- NSColor* color = skia::SkColorToCalibratedNSColor(
- message_center::kNotificationBackgroundColor);
- [color set];
- NSRectFill(dirtyRect);
- [super drawRect:dirtyRect];
-}
-@end
-
-@interface MCNotificationButtonCell : NSButtonCell {
- BOOL hovered_;
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-@implementation MCNotificationButtonCell
-- (BOOL)isOpaque {
- return YES;
-}
-
-- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView {
- // Else mouseEntered: and mouseExited: won't be called and hovered_ won't be
- // valid.
- DCHECK([self showsBorderOnlyWhileMouseInside]);
-
- if (!hovered_)
- return;
- [skia::SkColorToCalibratedNSColor(
- message_center::kHoveredButtonBackgroundColor) set];
- NSRectFill(frame);
-}
-
-- (void)drawImage:(NSImage*)image
- withFrame:(NSRect)frame
- inView:(NSView*)controlView {
- if (!image)
- return;
- NSRect rect = NSMakeRect(message_center::kButtonHorizontalPadding,
- message_center::kButtonIconTopPadding,
- message_center::kNotificationButtonIconSize,
- message_center::kNotificationButtonIconSize);
- [image drawInRect:rect
- fromRect:NSZeroRect
- operation:NSCompositeSourceOver
- fraction:1.0
- respectFlipped:YES
- hints:nil];
-}
-
-- (NSRect)drawTitle:(NSAttributedString*)title
- withFrame:(NSRect)frame
- inView:(NSView*)controlView {
- CGFloat offsetX = message_center::kButtonHorizontalPadding;
- if ([base::mac::ObjCCastStrict<NSButton>(controlView) image]) {
- offsetX += message_center::kNotificationButtonIconSize +
- message_center::kButtonIconToTitlePadding;
- }
- frame.origin.x = offsetX;
- frame.size.width -= offsetX;
-
- NSDictionary* attributes = @{
- NSFontAttributeName :
- [title attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL],
- NSForegroundColorAttributeName :
- skia::SkColorToCalibratedNSColor(message_center::kRegularTextColor),
- };
- [[title string] drawWithRect:frame
- options:(NSStringDrawingUsesLineFragmentOrigin |
- NSStringDrawingTruncatesLastVisibleLine)
- attributes:attributes];
- return frame;
-}
-
-- (void)mouseEntered:(NSEvent*)event {
- hovered_ = YES;
-
- // Else the cell won't be repainted on hover.
- [super mouseEntered:event];
-}
-
-- (void)mouseExited:(NSEvent*)event {
- hovered_ = NO;
- [super mouseExited:event];
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@interface MCNotificationView : NSBox {
- @private
- MCNotificationController* controller_;
-}
-
-- (id)initWithController:(MCNotificationController*)controller
- frame:(NSRect)frame;
-@end
-
-@implementation MCNotificationView
-- (id)initWithController:(MCNotificationController*)controller
- frame:(NSRect)frame {
- if ((self = [super initWithFrame:frame]))
- controller_ = controller;
- return self;
-}
-
-- (void)mouseUp:(NSEvent*)event {
- if (event.type != NSLeftMouseUp) {
- [super mouseUp:event];
- return;
- }
- if (NSPointInRect([self convertPoint:event.locationInWindow fromView:nil],
- self.bounds)) {
- [controller_ notificationClicked];
- }
-}
-
-- (NSView*)hitTest:(NSPoint)point {
- // Route the mouse click events on NSTextView to the container view.
- NSView* hitView = [super hitTest:point];
- if (hitView)
- return [hitView isKindOfClass:[NSTextView class]] ? self : hitView;
- return nil;
-}
-
-- (BOOL)accessibilityIsIgnored {
- return NO;
-}
-
-- (NSArray*)accessibilityActionNames {
- return @[ NSAccessibilityPressAction ];
-}
-
-- (void)accessibilityPerformAction:(NSString*)action {
- if ([action isEqualToString:NSAccessibilityPressAction]) {
- [controller_ notificationClicked];
- return;
- }
- [super accessibilityPerformAction:action];
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@interface AccessibilityIgnoredBox : NSBox
-@end
-
-// Ignore this element, but expose its children to accessibility.
-@implementation AccessibilityIgnoredBox
-- (BOOL)accessibilityIsIgnored {
- return YES;
-}
-
-// Pretend this element has no children.
-// TODO(petewil): Until we have alt text available, we will hide the children of
-// the box also. Remove this override once alt text is set (by using
-// NSAccessibilityDescriptionAttribute).
-- (id)accessibilityAttributeValue:(NSString*)attribute {
- // If we get a request for NSAccessibilityChildrenAttribute, return an empty
- // array to pretend we have no children.
- if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
- return @[];
- else
- return [super accessibilityAttributeValue:attribute];
-}
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@interface MCNotificationController (Private)
-// Configures a NSBox to be borderless, titleless, and otherwise appearance-
-// free.
-- (void)configureCustomBox:(NSBox*)box;
-
-// Initializes the icon_ ivar and returns the view to insert into the hierarchy.
-- (NSView*)createIconView;
-
-// Creates a box that shows a border when the icon is not big enough to fill the
-// space.
-- (NSBox*)createImageBox:(const gfx::Image&)notificationImage;
-
-// Initializes the closeButton_ ivar with the configured button.
-- (void)configureCloseButtonInFrame:(NSRect)rootFrame;
-
-// Initializes the settingsButton_ ivar with the configured button.
-- (void)configureSettingsButtonInFrame:(NSRect)rootFrame;
-
-// Creates the smallImage_ ivar with the appropriate frame.
-- (NSView*)createSmallImageInFrame:(NSRect)rootFrame;
-
-// Initializes title_ in the given frame.
-- (void)configureTitleInFrame:(NSRect)rootFrame;
-
-// Initializes message_ in the given frame.
-- (void)configureBodyInFrame:(NSRect)rootFrame;
-
-// Initializes contextMessage_ in the given frame.
-- (void)configureContextMessageInFrame:(NSRect)rootFrame;
-
-// Creates a NSTextView that the caller owns configured as a label in a
-// notification.
-- (NSTextView*)newLabelWithFrame:(NSRect)frame;
-
-// Gets the rectangle in which notification content should be placed. This
-// rectangle is to the right of the icon and left of the control buttons.
-// This depends on the icon_ and closeButton_ being initialized.
-- (NSRect)currentContentRect;
-
-// Returns the wrapped text that could fit within the content rect with not
-// more than the given number of lines. The wrapped text would be painted using
-// the given font. The Ellipsis could be added at the end of the last line if
-// it is too long. Outputs the number of lines computed in the actualLines
-// parameter.
-- (base::string16)wrapText:(const base::string16&)text
- forFont:(NSFont*)font
- maxNumberOfLines:(size_t)lines
- actualLines:(size_t*)actualLines;
-
-// Same as above without outputting the lines formatted.
-- (base::string16)wrapText:(const base::string16&)text
- forFont:(NSFont*)font
- maxNumberOfLines:(size_t)lines;
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@implementation MCNotificationController
-
-- (id)initWithNotification:(const message_center::Notification*)notification
- messageCenter:(message_center::MessageCenter*)messageCenter {
- if ((self = [super initWithNibName:nil bundle:nil])) {
- notification_ = notification;
- notificationID_ = notification_->id();
- messageCenter_ = messageCenter;
- }
- return self;
-}
-
-- (void)loadView {
- // Create the root view of the notification.
- NSRect rootFrame = NSMakeRect(0, 0,
- message_center::kNotificationPreferredImageWidth,
- message_center::kNotificationIconSize);
- base::scoped_nsobject<MCNotificationView> rootView(
- [[MCNotificationView alloc] initWithController:self frame:rootFrame]);
- [self configureCustomBox:rootView];
- [rootView setFillColor:skia::SkColorToCalibratedNSColor(
- message_center::kNotificationBackgroundColor)];
- [self setView:rootView];
-
- [rootView addSubview:[self createIconView]];
-
- // Create the close button.
- [self configureCloseButtonInFrame:rootFrame];
- [rootView addSubview:closeButton_];
-
- // Create the small image.
- [rootView addSubview:[self createSmallImageInFrame:rootFrame]];
-
- // Create the settings button.
- if (notification_->should_show_settings_button()) {
- [self configureSettingsButtonInFrame:rootFrame];
- [rootView addSubview:settingsButton_];
- }
-
- NSRect contentFrame = [self currentContentRect];
-
- // Create the title.
- [self configureTitleInFrame:contentFrame];
- [rootView addSubview:title_];
-
- // Create the message body.
- [self configureBodyInFrame:contentFrame];
- [rootView addSubview:message_];
-
- // Create the context message body.
- [self configureContextMessageInFrame:contentFrame];
- [rootView addSubview:contextMessage_];
-
- // Populate the data.
- [self updateNotification:notification_];
-}
-
-- (NSRect)updateNotification:(const message_center::Notification*)notification {
- DCHECK_EQ(notification->id(), notificationID_);
- notification_ = notification;
-
- message_center::NotificationLayoutParams layoutParams;
- layoutParams.rootFrame =
- NSMakeRect(0, 0, message_center::kNotificationPreferredImageWidth,
- message_center::kNotificationIconSize);
-
- [smallImage_ setImage:notification_->small_image().AsNSImage()];
-
- // Update the icon.
- [icon_ setImage:notification_->icon().AsNSImage()];
-
- // The message_center:: constants are relative to capHeight at the top and
- // relative to the baseline at the bottom, but NSTextField uses the full line
- // height for its height.
- CGFloat titleTopGap =
- roundf([[title_ font] ascender] - [[title_ font] capHeight]);
- CGFloat titleBottomGap = roundf(fabs([[title_ font] descender]));
- CGFloat titlePadding = message_center::kTextTopPadding - titleTopGap;
-
- CGFloat messageTopGap =
- roundf([[message_ font] ascender] - [[message_ font] capHeight]);
- CGFloat messageBottomGap = roundf(fabs([[message_ font] descender]));
- CGFloat messagePadding =
- message_center::kTextTopPadding - titleBottomGap - messageTopGap;
-
- CGFloat contextMessageTopGap = roundf(
- [[contextMessage_ font] ascender] - [[contextMessage_ font] capHeight]);
- CGFloat contextMessagePadding =
- message_center::kTextTopPadding - messageBottomGap - contextMessageTopGap;
-
- // Set the title and recalculate the frame.
- size_t actualTitleLines = 0;
- [title_ setString:base::SysUTF16ToNSString([self
- wrapText:notification_->title()
- forFont:[title_ font]
- maxNumberOfLines:message_center::kMaxTitleLines
- actualLines:&actualTitleLines])];
- [title_ sizeToFit];
- layoutParams.titleFrame = [title_ frame];
- layoutParams.titleFrame.origin.y = NSMaxY(layoutParams.rootFrame) -
- titlePadding -
- NSHeight(layoutParams.titleFrame);
-
- // The number of message lines depends on the number of context message lines
- // and the lines within the title, and whether an image exists.
- int messageLineLimit = message_center::kMessageExpandedLineLimit;
- if (actualTitleLines > 1)
- messageLineLimit -= (actualTitleLines - 1) * 2;
- if (!notification_->image().IsEmpty()) {
- messageLineLimit /= 2;
-
- if (!notification_->context_message().empty() &&
- !notification_->UseOriginAsContextMessage())
- messageLineLimit -= message_center::kContextMessageLineLimit;
- }
- if (messageLineLimit < 0)
- messageLineLimit = 0;
-
- // Set the message and recalculate the frame.
- [message_ setString:base::SysUTF16ToNSString(
- [self wrapText:notification_->message()
- forFont:[message_ font]
- maxNumberOfLines:messageLineLimit])];
- [message_ sizeToFit];
- layoutParams.messageFrame = [message_ frame];
-
- // If there are list items, then the message_ view should not be displayed.
- const std::vector<message_center::NotificationItem>& items =
- notification->items();
- // If there are list items, don't show the main message. Also if the message
- // is empty, mark it as hidden and set 0 height, so it doesn't take up any
- // space (size to fit leaves it 15 px tall.
- if (items.size() > 0 || notification_->message().empty()) {
- [message_ setHidden:YES];
- layoutParams.messageFrame.origin.y = layoutParams.titleFrame.origin.y;
- layoutParams.messageFrame.size.height = 0;
- } else {
- [message_ setHidden:NO];
- layoutParams.messageFrame.origin.y = NSMinY(layoutParams.titleFrame) -
- messagePadding -
- NSHeight(layoutParams.messageFrame);
- layoutParams.messageFrame.size.height = NSHeight([message_ frame]);
- }
-
- // Set the context message and recalculate the frame.
- base::string16 message;
- if (notification->UseOriginAsContextMessage()) {
- gfx::FontList font_list((gfx::Font([message_ font])));
- message = url_formatter::ElideHost(notification->origin_url(), font_list,
- message_center::kContextMessageViewWidth,
- gfx::Typesetter::NATIVE);
- } else {
- message = notification->context_message();
- }
-
- base::string16 elided =
- [self wrapText:message
- forFont:[contextMessage_ font]
- maxNumberOfLines:message_center::kContextMessageLineLimit];
- [contextMessage_ setString:base::SysUTF16ToNSString(elided)];
- [contextMessage_ sizeToFit];
-
- layoutParams.contextMessageFrame = [contextMessage_ frame];
-
- if (notification->context_message().empty() &&
- !notification->UseOriginAsContextMessage()) {
- [contextMessage_ setHidden:YES];
- layoutParams.contextMessageFrame.origin.y =
- layoutParams.messageFrame.origin.y;
- layoutParams.contextMessageFrame.size.height = 0;
- } else {
- [contextMessage_ setHidden:NO];
-
- // If the context message is used as a domain make sure it's placed at the
- // bottom of the top section.
- CGFloat contextMessageY = NSMinY(layoutParams.messageFrame) -
- contextMessagePadding -
- NSHeight(layoutParams.contextMessageFrame);
- layoutParams.contextMessageFrame.origin.y =
- notification->UseOriginAsContextMessage()
- ? std::min(NSMinY([icon_ frame]) + contextMessagePadding,
- contextMessageY)
- : contextMessageY;
- layoutParams.contextMessageFrame.size.height =
- NSHeight([contextMessage_ frame]);
- }
-
- // Calculate the settings button position. It is dependent on whether the
- // context message aligns or not with the icon.
- layoutParams.settingsButtonFrame = [settingsButton_ frame];
- layoutParams.settingsButtonFrame.origin.y =
- MIN(NSMinY([icon_ frame]) + message_center::kSmallImagePadding,
- NSMinY(layoutParams.contextMessageFrame));
-
- // Create the list item views (up to a maximum).
- [listView_ removeFromSuperview];
- layoutParams.listFrame = NSZeroRect;
- if (items.size() > 0) {
- layoutParams.listFrame = [self currentContentRect];
- layoutParams.listFrame.origin.y = 0;
- layoutParams.listFrame.size.height = 0;
- listView_.reset([[NSView alloc] initWithFrame:layoutParams.listFrame]);
- [listView_ accessibilitySetOverrideValue:NSAccessibilityListRole
- forAttribute:NSAccessibilityRoleAttribute];
- [listView_
- accessibilitySetOverrideValue:NSAccessibilityContentListSubrole
- forAttribute:NSAccessibilitySubroleAttribute];
- CGFloat y = 0;
-
- NSFont* font = [NSFont systemFontOfSize:message_center::kMessageFontSize];
- CGFloat lineHeight = roundf(NSHeight([font boundingRectForFont]));
-
- const int kNumNotifications =
- std::min(items.size(), message_center::kNotificationMaximumItems);
- for (int i = kNumNotifications - 1; i >= 0; --i) {
- NSTextView* itemView = [self
- newLabelWithFrame:NSMakeRect(0, y, NSWidth(layoutParams.listFrame),
- lineHeight)];
- [itemView setFont:font];
-
- // Disable the word-wrap in order to show the text in single line.
- [[itemView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [[itemView textContainer] setWidthTracksTextView:NO];
-
- // Construct the text from the title and message.
- base::string16 text =
- items[i].title + base::UTF8ToUTF16(" ") + items[i].message;
- base::string16 ellidedText =
- [self wrapText:text forFont:font maxNumberOfLines:1];
- [itemView setString:base::SysUTF16ToNSString(ellidedText)];
-
- // Use dim color for the title part.
- NSColor* titleColor =
- skia::SkColorToCalibratedNSColor(message_center::kRegularTextColor);
- NSRange titleRange = NSMakeRange(
- 0,
- std::min(ellidedText.size(), items[i].title.size()));
- [itemView setTextColor:titleColor range:titleRange];
-
- // Use dim color for the message part if it has not been truncated.
- if (ellidedText.size() > items[i].title.size() + 1) {
- NSColor* messageColor =
- skia::SkColorToCalibratedNSColor(message_center::kDimTextColor);
- NSRange messageRange = NSMakeRange(
- items[i].title.size() + 1,
- ellidedText.size() - items[i].title.size() - 1);
- [itemView setTextColor:messageColor range:messageRange];
- }
-
- [listView_ addSubview:itemView];
- y += lineHeight;
- }
- // TODO(thakis): The spacing is not completely right.
- CGFloat listTopPadding =
- message_center::kTextTopPadding - contextMessageTopGap;
- layoutParams.listFrame.size.height = y;
- layoutParams.listFrame.origin.y = NSMinY(layoutParams.contextMessageFrame) -
- listTopPadding -
- NSHeight(layoutParams.listFrame);
- [listView_ setFrame:layoutParams.listFrame];
- [[self view] addSubview:listView_];
- }
-
- // Create the progress bar view if needed.
- [progressBarView_ removeFromSuperview];
- layoutParams.progressBarFrame = NSZeroRect;
- if (notification->type() == message_center::NOTIFICATION_TYPE_PROGRESS) {
- layoutParams.progressBarFrame = [self currentContentRect];
- layoutParams.progressBarFrame.origin.y =
- NSMinY(layoutParams.contextMessageFrame) -
- message_center::kProgressBarTopPadding -
- message_center::kProgressBarThickness;
- layoutParams.progressBarFrame.size.height =
- message_center::kProgressBarThickness;
- progressBarView_.reset([[MCNotificationProgressBar alloc]
- initWithFrame:layoutParams.progressBarFrame]);
- // Setting indeterminate to NO does not work with custom drawRect.
- [progressBarView_ setIndeterminate:YES];
- [progressBarView_ setStyle:NSProgressIndicatorBarStyle];
- [progressBarView_ setDoubleValue:notification->progress()];
- [[self view] addSubview:progressBarView_];
- }
-
- // If the bottom-most element so far is out of the rootView's bounds, resize
- // the view.
- CGFloat minY = NSMinY(layoutParams.contextMessageFrame);
- if (listView_ && NSMinY(layoutParams.listFrame) < minY)
- minY = NSMinY(layoutParams.listFrame);
- if (progressBarView_ && NSMinY(layoutParams.progressBarFrame) < minY)
- minY = NSMinY(layoutParams.progressBarFrame);
- if (minY < messagePadding) {
- CGFloat delta = messagePadding - minY;
- [self adjustFrameHeight:&layoutParams delta:delta];
- }
-
- // Add the bottom container view.
- NSRect frame = layoutParams.rootFrame;
- frame.size.height = 0;
- [bottomView_ removeFromSuperview];
- bottomView_.reset([[NSView alloc] initWithFrame:frame]);
- CGFloat y = 0;
-
- // Create action buttons if appropriate, bottom-up.
- std::vector<message_center::ButtonInfo> buttons = notification->buttons();
- for (int i = buttons.size() - 1; i >= 0; --i) {
- message_center::ButtonInfo buttonInfo = buttons[i];
- NSRect buttonFrame = frame;
- buttonFrame.origin = NSMakePoint(0, y);
- buttonFrame.size.height = message_center::kButtonHeight;
- base::scoped_nsobject<MCNotificationButton> button(
- [[MCNotificationButton alloc] initWithFrame:buttonFrame]);
- base::scoped_nsobject<MCNotificationButtonCell> cell(
- [[MCNotificationButtonCell alloc]
- initTextCell:base::SysUTF16ToNSString(buttonInfo.title)]);
- [cell setShowsBorderOnlyWhileMouseInside:YES];
- [button setCell:cell];
- [button setImage:buttonInfo.icon.AsNSImage()];
- [button setBezelStyle:NSSmallSquareBezelStyle];
- [button setImagePosition:NSImageLeft];
- [button setTag:i];
- [button setTarget:self];
- [button setAction:@selector(buttonClicked:)];
- y += NSHeight(buttonFrame);
- frame.size.height += NSHeight(buttonFrame);
- [bottomView_ addSubview:button];
-
- NSRect separatorFrame = frame;
- separatorFrame.origin = NSMakePoint(0, y);
- separatorFrame.size.height = 1;
- base::scoped_nsobject<NSBox> separator(
- [[AccessibilityIgnoredBox alloc] initWithFrame:separatorFrame]);
- [self configureCustomBox:separator];
- [separator setFillColor:skia::SkColorToCalibratedNSColor(
- message_center::kButtonSeparatorColor)];
- y += NSHeight(separatorFrame);
- frame.size.height += NSHeight(separatorFrame);
- [bottomView_ addSubview:separator];
- }
-
- // Create the image view if appropriate.
- gfx::Image notificationImage = notification->image();
- if (!notificationImage.IsEmpty()) {
- NSBox* imageBox = [self createImageBox:notificationImage];
- NSRect outerFrame = frame;
- outerFrame.origin = NSMakePoint(0, y);
- outerFrame.size = [imageBox frame].size;
- [imageBox setFrame:outerFrame];
-
- y += NSHeight(outerFrame);
- frame.size.height += NSHeight(outerFrame);
-
- [bottomView_ addSubview:imageBox];
- }
-
- [bottomView_ setFrame:frame];
- [[self view] addSubview:bottomView_];
- [self adjustFrameHeight:&layoutParams delta:NSHeight(frame)];
-
- // Make sure that there is a minimum amount of spacing below the icon and
- // the edge of the frame.
- CGFloat bottomDelta =
- NSHeight(layoutParams.rootFrame) - NSHeight([icon_ frame]);
- if (bottomDelta > 0 && bottomDelta < message_center::kIconBottomPadding) {
- CGFloat bottomAdjust = message_center::kIconBottomPadding - bottomDelta;
- [self adjustFrameHeight:&layoutParams delta:bottomAdjust];
- }
-
- [[self view] setFrame:layoutParams.rootFrame];
- [title_ setFrame:layoutParams.titleFrame];
- [message_ setFrame:layoutParams.messageFrame];
- [contextMessage_ setFrame:layoutParams.contextMessageFrame];
- [settingsButton_ setFrame:layoutParams.settingsButtonFrame];
- [listView_ setFrame:layoutParams.listFrame];
- [progressBarView_ setFrame:layoutParams.progressBarFrame];
-
- return layoutParams.rootFrame;
-}
-
-- (void)close:(id)sender {
- [closeButton_ setTarget:nil];
- messageCenter_->RemoveNotification([self notificationID], /*by_user=*/true);
-}
-
-- (void)settingsClicked:(id)sender {
- [NSApp activateIgnoringOtherApps:YES];
- messageCenter_->ClickOnSettingsButton([self notificationID]);
-}
-
-- (void)buttonClicked:(id)button {
- messageCenter_->ClickOnNotificationButton([self notificationID],
- [button tag]);
-}
-
-- (const message_center::Notification*)notification {
- return notification_;
-}
-
-- (const std::string&)notificationID {
- return notificationID_;
-}
-
-- (void)notificationClicked {
- messageCenter_->ClickOnNotification([self notificationID]);
-}
-
-- (void)adjustFrameHeight:(message_center::NotificationLayoutParams*)frames
- delta:(CGFloat)delta {
- frames->rootFrame.size.height += delta;
- frames->titleFrame.origin.y += delta;
- frames->messageFrame.origin.y += delta;
- frames->contextMessageFrame.origin.y += delta;
- frames->settingsButtonFrame.origin.y += delta;
- frames->listFrame.origin.y += delta;
- frames->progressBarFrame.origin.y += delta;
-}
-
-// Private /////////////////////////////////////////////////////////////////////
-
-- (void)configureCustomBox:(NSBox*)box {
- [box setBoxType:NSBoxCustom];
- [box setBorderType:NSNoBorder];
- [box setTitlePosition:NSNoTitle];
- [box setContentViewMargins:NSZeroSize];
-}
-
-- (NSView*)createIconView {
- // Create another box that shows a background color when the icon is not
- // big enough to fill the space.
- NSRect imageFrame = NSMakeRect(0, 0,
- message_center::kNotificationIconSize,
- message_center::kNotificationIconSize);
- base::scoped_nsobject<NSBox> imageBox(
- [[AccessibilityIgnoredBox alloc] initWithFrame:imageFrame]);
- [self configureCustomBox:imageBox];
- [imageBox setAutoresizingMask:NSViewMinYMargin];
-
- // Inside the image box put the actual icon view.
- icon_.reset([[NSImageView alloc] initWithFrame:imageFrame]);
- [imageBox setContentView:icon_];
-
- return imageBox.autorelease();
-}
-
-- (NSBox*)createImageBox:(const gfx::Image&)notificationImage {
- using message_center::kNotificationImageBorderSize;
- using message_center::kNotificationPreferredImageWidth;
- using message_center::kNotificationPreferredImageHeight;
-
- NSRect imageFrame = NSMakeRect(0, 0,
- kNotificationPreferredImageWidth,
- kNotificationPreferredImageHeight);
- base::scoped_nsobject<NSBox> imageBox(
- [[AccessibilityIgnoredBox alloc] initWithFrame:imageFrame]);
- [self configureCustomBox:imageBox];
- [imageBox setFillColor:skia::SkColorToCalibratedNSColor(
- message_center::kImageBackgroundColor)];
-
- // Images with non-preferred aspect ratios get a border on all sides.
- gfx::Size idealSize = gfx::Size(
- kNotificationPreferredImageWidth, kNotificationPreferredImageHeight);
- gfx::Size scaledSize = message_center::GetImageSizeForContainerSize(
- idealSize, notificationImage.Size());
- if (scaledSize != idealSize) {
- NSSize borderSize =
- NSMakeSize(kNotificationImageBorderSize, kNotificationImageBorderSize);
- [imageBox setContentViewMargins:borderSize];
- }
-
- NSImage* image = notificationImage.AsNSImage();
- base::scoped_nsobject<NSImageView> imageView(
- [[NSImageView alloc] initWithFrame:imageFrame]);
- [imageView setImage:image];
- [imageView setImageScaling:NSImageScaleProportionallyUpOrDown];
- [imageBox setContentView:imageView];
-
- return imageBox.autorelease();
-}
-
-- (void)configureCloseButtonInFrame:(NSRect)rootFrame {
- // The close button is configured to be the same size as the small image.
- int closeButtonOriginOffset =
- message_center::kSmallImageSize + message_center::kSmallImagePadding;
- NSRect closeButtonFrame =
- NSMakeRect(NSMaxX(rootFrame) - closeButtonOriginOffset,
- NSMaxY(rootFrame) - closeButtonOriginOffset,
- message_center::kSmallImageSize,
- message_center::kSmallImageSize);
- closeButton_.reset([[HoverImageButton alloc] initWithFrame:closeButtonFrame]);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- [closeButton_ setDefaultImage:
- rb.GetNativeImageNamed(IDR_NOTIFICATION_CLOSE).ToNSImage()];
- [closeButton_ setHoverImage:
- rb.GetNativeImageNamed(IDR_NOTIFICATION_CLOSE_HOVER).ToNSImage()];
- [closeButton_ setPressedImage:
- rb.GetNativeImageNamed(IDR_NOTIFICATION_CLOSE_PRESSED).ToNSImage()];
- [[closeButton_ cell] setHighlightsBy:NSOnState];
- [closeButton_ setTrackingEnabled:YES];
- [closeButton_ setBordered:NO];
- [closeButton_ setAutoresizingMask:NSViewMinYMargin];
- [closeButton_ setTarget:self];
- [closeButton_ setAction:@selector(close:)];
- [closeButton_ setDisableActivationOnClick:YES];
- [[closeButton_ cell]
- accessibilitySetOverrideValue:NSAccessibilityCloseButtonSubrole
- forAttribute:NSAccessibilitySubroleAttribute];
- [[closeButton_ cell]
- accessibilitySetOverrideValue:
- l10n_util::GetNSString(IDS_APP_ACCNAME_CLOSE)
- forAttribute:NSAccessibilityTitleAttribute];
-}
-
-- (void)configureSettingsButtonInFrame:(NSRect)rootFrame {
- // The settings button is configured to be the same size as the small image.
- int settingsButtonOriginOffset =
- message_center::kSmallImageSize + message_center::kSmallImagePadding;
- NSRect settingsButtonFrame = NSMakeRect(
- NSMaxX(rootFrame) - settingsButtonOriginOffset,
- message_center::kSmallImagePadding, message_center::kSmallImageSize,
- message_center::kSmallImageSize);
-
- settingsButton_.reset(
- [[HoverImageButton alloc] initWithFrame:settingsButtonFrame]);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- [settingsButton_ setDefaultImage:rb.GetNativeImageNamed(
- IDR_NOTIFICATION_SETTINGS_BUTTON_ICON)
- .ToNSImage()];
- [settingsButton_
- setHoverImage:rb.GetNativeImageNamed(
- IDR_NOTIFICATION_SETTINGS_BUTTON_ICON_HOVER)
- .ToNSImage()];
- [settingsButton_
- setPressedImage:rb.GetNativeImageNamed(
- IDR_NOTIFICATION_SETTINGS_BUTTON_ICON_PRESSED)
- .ToNSImage()];
- [[settingsButton_ cell] setHighlightsBy:NSOnState];
- [settingsButton_ setTrackingEnabled:YES];
- [settingsButton_ setBordered:NO];
- [settingsButton_ setAutoresizingMask:NSViewMinYMargin];
- [settingsButton_ setTarget:self];
- [settingsButton_ setAction:@selector(settingsClicked:)];
- [[settingsButton_ cell]
- accessibilitySetOverrideValue:
- l10n_util::GetNSString(
- IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME)
- forAttribute:NSAccessibilityTitleAttribute];
-}
-
-- (NSView*)createSmallImageInFrame:(NSRect)rootFrame {
- int smallImageXOffset =
- message_center::kSmallImagePadding + message_center::kSmallImageSize;
- NSRect boxFrame =
- NSMakeRect(NSMaxX(rootFrame) - smallImageXOffset,
- NSMinY(rootFrame) + message_center::kSmallImagePadding,
- message_center::kSmallImageSize,
- message_center::kSmallImageSize);
-
- // Put the smallImage inside another box which can hide it from accessibility
- // until we have some alt text to go with it. Once we have alt text, remove
- // the box, and set NSAccessibilityDescriptionAttribute with it.
- base::scoped_nsobject<NSBox> imageBox(
- [[AccessibilityIgnoredBox alloc] initWithFrame:boxFrame]);
- [self configureCustomBox:imageBox];
- [imageBox setAutoresizingMask:NSViewMinYMargin];
-
- NSRect smallImageFrame =
- NSMakeRect(0,0,
- message_center::kSmallImageSize,
- message_center::kSmallImageSize);
-
- smallImage_.reset([[NSImageView alloc] initWithFrame:smallImageFrame]);
- [smallImage_ setImageScaling:NSImageScaleProportionallyUpOrDown];
- [imageBox setContentView:smallImage_];
-
- return imageBox.autorelease();
-}
-
-- (void)configureTitleInFrame:(NSRect)contentFrame {
- contentFrame.size.height = 0;
- title_.reset([self newLabelWithFrame:contentFrame]);
- [title_ setAutoresizingMask:NSViewMinYMargin];
- [title_ setTextColor:skia::SkColorToCalibratedNSColor(
- message_center::kRegularTextColor)];
- [title_ setFont:[NSFont messageFontOfSize:message_center::kTitleFontSize]];
-}
-
-- (void)configureBodyInFrame:(NSRect)contentFrame {
- contentFrame.size.height = 0;
- message_.reset([self newLabelWithFrame:contentFrame]);
- [message_ setAutoresizingMask:NSViewMinYMargin];
- [message_ setTextColor:skia::SkColorToCalibratedNSColor(
- message_center::kRegularTextColor)];
- [message_ setFont:
- [NSFont messageFontOfSize:message_center::kMessageFontSize]];
-}
-
-- (void)configureContextMessageInFrame:(NSRect)contentFrame {
- contentFrame.size.height = 0;
- contextMessage_.reset([self newLabelWithFrame:contentFrame]);
- [contextMessage_ setAutoresizingMask:NSViewMinYMargin];
- [contextMessage_ setTextColor:skia::SkColorToCalibratedNSColor(
- message_center::kDimTextColor)];
- [contextMessage_ setFont:
- [NSFont messageFontOfSize:message_center::kMessageFontSize]];
-}
-
-- (NSTextView*)newLabelWithFrame:(NSRect)frame {
- NSTextView* label = [[NSTextView alloc] initWithFrame:frame];
-
- // The labels MUST draw their background so that subpixel antialiasing can
- // happen on the text.
- [label setDrawsBackground:YES];
- [label setBackgroundColor:skia::SkColorToCalibratedNSColor(
- message_center::kNotificationBackgroundColor)];
-
- [label setEditable:NO];
- [label setSelectable:NO];
- [label setTextContainerInset:NSMakeSize(0.0f, 0.0f)];
- [[label textContainer] setLineFragmentPadding:0.0f];
- return label;
-}
-
-- (NSRect)currentContentRect {
- DCHECK(icon_);
- DCHECK(closeButton_);
- DCHECK(smallImage_);
-
- NSRect iconFrame, contentFrame;
- NSDivideRect([[self view] bounds], &iconFrame, &contentFrame,
- NSWidth([icon_ frame]) + message_center::kIconToTextPadding,
- NSMinXEdge);
- // The content area is between the icon on the left and the control area
- // on the right.
- int controlAreaWidth =
- std::max(NSWidth([closeButton_ frame]), NSWidth([smallImage_ frame]));
- contentFrame.size.width -=
- 2 * message_center::kSmallImagePadding + controlAreaWidth;
- return contentFrame;
-}
-
-- (base::string16)wrapText:(const base::string16&)text
- forFont:(NSFont*)nsfont
- maxNumberOfLines:(size_t)lines
- actualLines:(size_t*)actualLines {
- *actualLines = 0;
- if (text.empty() || lines == 0)
- return base::string16();
- gfx::FontList font_list((gfx::Font(nsfont)));
- int width = NSWidth([self currentContentRect]);
- int height = (lines + 1) * font_list.GetHeight();
-
- std::vector<base::string16> wrapped;
- gfx::ElideRectangleTextForNativeUi(text, font_list, width, height,
- gfx::WRAP_LONG_WORDS, &wrapped);
-
- // This could be possible when the input text contains only spaces.
- if (wrapped.empty())
- return base::string16();
-
- if (wrapped.size() > lines) {
- // Add an ellipsis to the last line. If this ellipsis makes the last line
- // too wide, that line will be further elided by the gfx::ElideText below.
- base::string16 last =
- wrapped[lines - 1] + base::UTF8ToUTF16(gfx::kEllipsis);
- if (gfx::GetStringWidth(last, font_list, gfx::Typesetter::NATIVE) > width) {
- last = gfx::ElideText(last, font_list, width, gfx::ELIDE_TAIL,
- gfx::Typesetter::NATIVE);
- }
- wrapped.resize(lines - 1);
- wrapped.push_back(last);
- }
-
- *actualLines = wrapped.size();
- return lines == 1 ? wrapped[0]
- : base::JoinString(wrapped, base::ASCIIToUTF16("\n"));
-}
-
-- (base::string16)wrapText:(const base::string16&)text
- forFont:(NSFont*)nsfont
- maxNumberOfLines:(size_t)lines {
- size_t unused;
- return [self wrapText:text
- forFont:nsfont
- maxNumberOfLines:lines
- actualLines:&unused];
-}
-
-@end
diff --git a/chromium/ui/message_center/cocoa/notification_controller_unittest.mm b/chromium/ui/message_center/cocoa/notification_controller_unittest.mm
deleted file mode 100644
index 72c3441def9..00000000000
--- a/chromium/ui/message_center/cocoa/notification_controller_unittest.mm
+++ /dev/null
@@ -1,434 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/message_center/cocoa/notification_controller.h"
-
-#include <memory>
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#import "ui/base/cocoa/hover_image_button.h"
-#import "ui/base/test/cocoa_helper.h"
-#include "ui/message_center/fake_message_center.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
-#include "ui/message_center/public/cpp/notification.h"
-#include "ui/message_center/public/cpp/notification_types.h"
-
-using base::ASCIIToUTF16;
-using base::UTF8ToUTF16;
-
-namespace {
-
-class MockMessageCenter : public message_center::FakeMessageCenter {
- public:
- MockMessageCenter()
- : last_removed_by_user_(false),
- remove_count_(0),
- last_clicked_index_(-1) {}
-
- void RemoveNotification(const std::string& id, bool by_user) override {
- last_removed_id_ = id;
- last_removed_by_user_ = by_user;
- ++remove_count_;
- }
-
- void ClickOnNotificationButton(const std::string& id,
- int button_index) override {
- last_clicked_id_ = id;
- last_clicked_index_ = button_index;
- }
-
- const std::string& last_removed_id() const { return last_removed_id_; }
- bool last_removed_by_user() const { return last_removed_by_user_; }
- int remove_count() const { return remove_count_; }
- const std::string& last_clicked_id() const { return last_clicked_id_; }
- int last_clicked_index() const { return last_clicked_index_; }
-
- private:
- std::string last_removed_id_;
- bool last_removed_by_user_;
- int remove_count_;
-
- std::string last_clicked_id_;
- int last_clicked_index_;
-
- DISALLOW_COPY_AND_ASSIGN(MockMessageCenter);
-};
-
-} // namespace
-
-@implementation MCNotificationController (TestingInterface)
-- (NSButton*)closeButton {
- return closeButton_.get();
-}
-
-- (NSImageView*)smallImageView {
- return smallImage_.get();
-}
-
-- (NSButton*)secondButton {
- // The buttons are in Cocoa-y-order, so the 2nd button is first.
- NSView* view = [[bottomView_ subviews] objectAtIndex:0];
- return base::mac::ObjCCastStrict<NSButton>(view);
-}
-
-- (NSArray*)bottomSubviews {
- return [bottomView_ subviews];
-}
-
-- (NSImageView*)iconView {
- return icon_.get();
-}
-
-- (NSTextView*)titleView {
- return title_.get();
-}
-
-- (NSTextView*)messageView {
- return message_.get();
-}
-
-- (NSTextView*)contextMessageView {
- return contextMessage_.get();
-}
-
-- (HoverImageButton*)settingsButton {
- return settingsButton_.get();
-}
-
-- (NSView*)listView {
- return listView_.get();
-}
-@end
-
-namespace message_center {
-
-class NotificationControllerTest : public ui::CocoaTest {
- public:
- NSImage* TestIcon() {
- return [NSImage imageNamed:NSImageNameUser];
- }
-
- protected:
- message_center::NotifierId DummyNotifierId() {
- return message_center::NotifierId();
- }
-};
-
-TEST_F(NotificationControllerTest, BasicLayout) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "",
- ASCIIToUTF16("Added to circles"),
- ASCIIToUTF16("Jonathan and 5 others"), gfx::Image(), base::string16(),
- GURL(), DummyNotifierId(), message_center::RichNotificationData(),
- NULL));
- gfx::Image testIcon([TestIcon() retain]);
- notification->set_icon(testIcon);
- notification->set_small_image(testIcon);
-
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:NULL]);
- [controller view];
-
- EXPECT_EQ(TestIcon(), [[controller iconView] image]);
- EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
- EXPECT_EQ(base::SysNSStringToUTF16([[controller titleView] string]),
- notification->title());
- EXPECT_EQ(base::SysNSStringToUTF16([[controller messageView] string]),
- notification->message());
- EXPECT_EQ(controller.get(), [[controller closeButton] target]);
-}
-
-TEST_F(NotificationControllerTest, NotificationSetttingsButtonLayout) {
- message_center::RichNotificationData data;
- data.settings_button_handler = SettingsButtonHandler::INLINE;
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "",
- ASCIIToUTF16("Added to circles"),
- ASCIIToUTF16("Jonathan and 5 others"), gfx::Image(), base::string16(),
- GURL("https://plus.com"), DummyNotifierId(), data, NULL));
-
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:nullptr]);
- [controller view];
- EXPECT_EQ(controller.get(), [[controller settingsButton] target]);
-}
-
-TEST_F(NotificationControllerTest, ContextMessageAsDomainNotificationLayout) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "",
- ASCIIToUTF16("Added to circles"),
- ASCIIToUTF16("Jonathan and 5 others"), gfx::Image(), base::string16(),
- GURL("https://plus.com"), DummyNotifierId(),
- message_center::RichNotificationData(), new NotificationDelegate()));
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:nullptr]);
- [controller view];
-
- EXPECT_EQ(base::SysNSStringToUTF8([[controller contextMessageView] string]),
- "plus.com");
-}
-
-TEST_F(NotificationControllerTest, OverflowText) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "",
- ASCIIToUTF16("This is a much longer title that should wrap "
- "multiple lines."),
- ASCIIToUTF16("And even the message is long. This sure is a wordy "
- "notification. Are you really going to read this "
- "entire thing?"),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:NULL]);
- [controller view];
-
- EXPECT_GT(NSHeight([[controller view] frame]),
- message_center::kNotificationIconSize);
-}
-
-TEST_F(NotificationControllerTest, Close) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "an_id", base::string16(),
- base::string16(), gfx::Image(), base::string16(), GURL(),
- DummyNotifierId(), message_center::RichNotificationData(), NULL));
- MockMessageCenter message_center;
-
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:&message_center]);
- [controller view];
-
- [[controller closeButton] performClick:nil];
-
- EXPECT_EQ(1, message_center.remove_count());
- EXPECT_EQ("an_id", message_center.last_removed_id());
- EXPECT_TRUE(message_center.last_removed_by_user());
-}
-
-TEST_F(NotificationControllerTest, Update) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "",
- ASCIIToUTF16("A simple title"),
- ASCIIToUTF16("This message isn't too long and should fit in the"
- "default bounds."),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:NULL]);
-
- // Set up the default layout.
- [controller view];
- EXPECT_EQ(NSHeight([[controller view] frame]),
- message_center::kNotificationIconSize);
- EXPECT_FALSE([[controller iconView] image]);
- EXPECT_FALSE([[controller smallImageView] image]);
-
- // Update the icon.
- gfx::Image testIcon([TestIcon() retain]);
- notification->set_icon(testIcon);
- notification->set_small_image(testIcon);
- [controller updateNotification:notification.get()];
- EXPECT_EQ(TestIcon(), [[controller iconView] image]);
- EXPECT_EQ(TestIcon(), [[controller smallImageView] image]);
- EXPECT_EQ(NSHeight([[controller view] frame]),
- message_center::kNotificationIconSize);
-}
-
-TEST_F(NotificationControllerTest, Buttons) {
- message_center::RichNotificationData optional;
- message_center::ButtonInfo button1(UTF8ToUTF16("button1"));
- optional.buttons.push_back(button1);
- message_center::ButtonInfo button2(UTF8ToUTF16("button2"));
- optional.buttons.push_back(button2);
-
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
- base::string16(), base::string16(), gfx::Image(), base::string16(),
- GURL(), DummyNotifierId(), optional, NULL));
- MockMessageCenter message_center;
-
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:&message_center]);
- [controller view];
-
- [[controller secondButton] performClick:nil];
-
- EXPECT_EQ("an_id", message_center.last_clicked_id());
- EXPECT_EQ(1, message_center.last_clicked_index());
-}
-
-TEST_F(NotificationControllerTest, Image) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
- base::string16(), base::string16(), gfx::Image(), base::string16(),
- GURL(), DummyNotifierId(), message_center::RichNotificationData(),
- NULL));
- NSImage* image = [NSImage imageNamed:NSImageNameFolder];
- notification->set_image(gfx::Image([image retain]));
-
- MockMessageCenter message_center;
-
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:&message_center]);
- [controller view];
-
- ASSERT_EQ(1u, [[controller bottomSubviews] count]);
- ASSERT_TRUE([[[[controller bottomSubviews] lastObject] contentView]
- isKindOfClass:[NSImageView class]]);
- EXPECT_EQ(image,
- [[[[controller bottomSubviews] lastObject] contentView] image]);
-}
-
-TEST_F(NotificationControllerTest, List) {
- message_center::RichNotificationData optional;
- message_center::NotificationItem item1{UTF8ToUTF16("First title"),
- UTF8ToUTF16("first message")};
- optional.items.push_back(item1);
- message_center::NotificationItem item2{
- UTF8ToUTF16("Second title"),
- UTF8ToUTF16("second slightly longer message")};
- optional.items.push_back(item2);
- message_center::NotificationItem item3{
- UTF8ToUTF16(""), // Test for empty string.
- UTF8ToUTF16(" ")}; // Test for string containing only spaces.
- optional.items.push_back(item3);
- optional.context_message = UTF8ToUTF16("Context Message");
-
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
- UTF8ToUTF16("Notification Title"),
- UTF8ToUTF16("Notification Message - should be hidden"), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(), optional, NULL));
-
- MockMessageCenter message_center;
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:&message_center]);
- [controller view];
-
- EXPECT_FALSE([[controller titleView] isHidden]);
- EXPECT_TRUE([[controller messageView] isHidden]);
- EXPECT_FALSE([[controller contextMessageView] isHidden]);
-
- EXPECT_EQ(3u, [[[controller listView] subviews] count]);
- EXPECT_LT(NSMaxY([[controller listView] frame]),
- NSMinY([[controller titleView] frame]));
-}
-
-TEST_F(NotificationControllerTest, NoMessage) {
- message_center::RichNotificationData optional;
- optional.context_message = UTF8ToUTF16("Context Message");
-
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_BASE_FORMAT, "an_id",
- UTF8ToUTF16("Notification Title"), UTF8ToUTF16(""), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(), optional, NULL));
-
- MockMessageCenter message_center;
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:&message_center]);
- [controller view];
-
- EXPECT_FALSE([[controller titleView] isHidden]);
- EXPECT_TRUE([[controller messageView] isHidden]);
- EXPECT_FALSE([[controller contextMessageView] isHidden]);
-}
-
-TEST_F(NotificationControllerTest, MessageSize) {
- message_center::RichNotificationData data;
- std::string id("id");
- NotifierId notifier_id(NotifierId::APPLICATION, "notifier");
- std::unique_ptr<Notification> notification(new Notification(
- NOTIFICATION_TYPE_BASE_FORMAT, id, base::UTF8ToUTF16(""),
- ASCIIToUTF16("And\neven\nthe\nmessage is long.\nThis sure is wordy"),
- gfx::Image(), base::string16() /* display_source */, GURL(), notifier_id,
- data, NULL /* delegate */));
-
- base::scoped_nsobject<MCNotificationController> controller(
- [[MCNotificationController alloc] initWithNotification:notification.get()
- messageCenter:NULL]);
-
- // Set up the default layout.
- [controller view];
-
- auto compute_message_lines = ^{
- NSString* string = [[[controller messageView] textStorage] string];
- unsigned numberOfLines, index, stringLength = [string length];
- for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
- index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);
-
- return numberOfLines;
- };
-
- // Message and no title: 5 lines.
- EXPECT_EQ(5u, compute_message_lines());
-
- // Message and one line title: 5 lines.
- notification->set_title(ASCIIToUTF16("one line"));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(5u, compute_message_lines());
-
- // Message and two line title: 3 lines.
- notification->set_title(ASCIIToUTF16("two\nlines"));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(3u, compute_message_lines());
-
- // Message, image and no title: 2 lines.
- SkBitmap bitmap;
- bitmap.allocN32Pixels(2, 2);
- bitmap.eraseColor(SK_ColorGREEN);
- notification->set_title(ASCIIToUTF16(""));
- notification->set_image(gfx::Image::CreateFrom1xBitmap(bitmap));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(2u, compute_message_lines());
-
- // Message, image and one line title: 2 lines.
- notification->set_title(ASCIIToUTF16("one line"));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(2u, compute_message_lines());
-
- // Message, image and two line title: 1 lines.
- notification->set_title(ASCIIToUTF16("two\nlines"));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(1u, compute_message_lines());
-
- // Same as above, but context message takes away from message lines.
- notification->set_context_message(UTF8ToUTF16("foo"));
- notification->set_title(ASCIIToUTF16(""));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(1u, compute_message_lines());
-
- notification->set_title(ASCIIToUTF16("one line"));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(1u, compute_message_lines());
-
- notification->set_title(ASCIIToUTF16("two\nlines"));
- [controller updateNotification:notification.get()];
- EXPECT_EQ(0u, compute_message_lines());
-}
-
-} // namespace message_center
diff --git a/chromium/ui/message_center/cocoa/opaque_views.h b/chromium/ui/message_center/cocoa/opaque_views.h
deleted file mode 100644
index 1a2f3b02354..00000000000
--- a/chromium/ui/message_center/cocoa/opaque_views.h
+++ /dev/null
@@ -1,36 +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_MESSAGE_CENTER_COCOA_OPAQUE_VIEWS_H_
-#define UI_MESSAGE_CENTER_COCOA_OPAQUE_VIEWS_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-// MCDropDown is the same as an NSPopupButton except that it fills its
-// background with a settable color.
-@interface MCDropDown : NSPopUpButton {
- @private
- base::scoped_nsobject<NSColor> backgroundColor_;
-}
-
-// Gets and sets the bubble's background color.
-- (NSColor*)backgroundColor;
-- (void)setBackgroundColor:(NSColor*)backgroundColor;
-@end
-
-// MCTextField fills its background with an opaque color. It also configures
-// the view to have a plan appearance, without bezel, border, editing, etc.
-@interface MCTextField : NSTextField {
- @private
- base::scoped_nsobject<NSColor> backgroundColor_;
-}
-
-// Use this method to create the text field. The color is required so it
-// can correctly subpixel antialias.
-- (id)initWithFrame:(NSRect)frameRect backgroundColor:(NSColor*)color;
-@end
-
-#endif // UI_MESSAGE_CENTER_COCOA_OPAQUE_VIEWS_H_
diff --git a/chromium/ui/message_center/cocoa/opaque_views.mm b/chromium/ui/message_center/cocoa/opaque_views.mm
deleted file mode 100644
index b6e054f519a..00000000000
--- a/chromium/ui/message_center/cocoa/opaque_views.mm
+++ /dev/null
@@ -1,63 +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/message_center/cocoa/opaque_views.h"
-
-@implementation MCDropDown
-// The view must be opaque to render subpixel antialiasing.
-- (BOOL)isOpaque {
- return YES;
-}
-
-// The view must also fill its background to render subpixel antialiasing.
-- (void)drawRect:(NSRect)dirtyRect {
- [backgroundColor_ set];
- NSRectFill(dirtyRect);
- [super drawRect:dirtyRect];
-}
-
-- (NSColor*)backgroundColor {
- return backgroundColor_;
-}
-
-- (void)setBackgroundColor:(NSColor*)backgroundColor {
- backgroundColor_.reset([backgroundColor retain]);
-}
-@end
-
-@implementation MCTextField
-- (id)initWithFrame:(NSRect)frameRect backgroundColor:(NSColor*)color {
- self = [self initWithFrame:frameRect];
- if (self) {
- [self setBackgroundColor:color];
- backgroundColor_.reset([color retain]);
- }
- return self;
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
- self = [super initWithFrame:frameRect];
- if (self) {
- [self setAutoresizingMask:NSViewMinYMargin];
- [self setBezeled:NO];
- [self setBordered:NO];
- [self setEditable:NO];
- [self setSelectable:NO];
- [self setDrawsBackground:YES];
- }
- return self;
-}
-
-// The view must be opaque to render subpixel antialiasing.
-- (BOOL)isOpaque {
- return YES;
-}
-
-// The view must also fill its background to render subpixel antialiasing.
-- (void)drawRect:(NSRect)dirtyRect {
- [backgroundColor_ set];
- NSRectFill(dirtyRect);
- [super drawRect:dirtyRect];
-}
-@end
diff --git a/chromium/ui/message_center/cocoa/popup_collection.h b/chromium/ui/message_center/cocoa/popup_collection.h
deleted file mode 100644
index 736cdea1447..00000000000
--- a/chromium/ui/message_center/cocoa/popup_collection.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_MESSAGE_CENTER_COCOA_POPUP_COLLECTION_H_
-#define UI_MESSAGE_CENTER_COCOA_POPUP_COLLECTION_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-#include <set>
-
-#include "base/mac/scoped_block.h"
-#import "base/mac/scoped_nsobject.h"
-#include "ui/message_center/message_center_export.h"
-
-namespace message_center {
-class MessageCenter;
-class MessageCenterObserver;
-}
-
-namespace message_center {
-typedef void(^AnimationEndedCallback)();
-}
-
-// A popup collection interfaces with the MessageCenter as an observer. It will
-// arrange notifications on the screen as popups, starting in the upper-right
-// corner, going to the bottom of the screen. This class maintains ownership of
-// the Cocoa controllers and windows of the notifications.
-MESSAGE_CENTER_EXPORT
-@interface MCPopupCollection : NSObject {
- @private
- // The message center that is responsible for the notifications. Weak, global.
- message_center::MessageCenter* messageCenter_;
-
- // MessageCenterObserver implementation.
- std::unique_ptr<message_center::MessageCenterObserver> observer_;
-
- // Array of all on-screen popup notifications.
- base::scoped_nsobject<NSMutableArray> popups_;
-
- // Array of all on-screen popup notifications that are being faded out
- // for removal.
- base::scoped_nsobject<NSMutableArray> popupsBeingRemoved_;
-
- // For testing only. If not a zero rect, this is the screen size to use
- // for laying out popups.
- NSRect testingScreenFrame_;
-
- // The duration of the popup animation, in the number of seconds.
- NSTimeInterval popupAnimationDuration_;
-
- // Set of notification IDs for those popups to be updated when all existing
- // animations end.
- std::set<std::string> pendingUpdateNotificationIDs_;
-
- // Set of notification IDs for those popups to be closed when all existing
- // animations end.
- std::set<std::string> pendingRemoveNotificationIDs_;
-
- // Set of notification IDs for those popups that are being animated due to
- // showing, bounds change or closing.
- std::set<std::string> animatingNotificationIDs_;
-
- // For testing only. If set, the callback will be called when the animation
- // ends.
- base::mac::ScopedBlock<message_center::AnimationEndedCallback>
- testingAnimationEndedCallback_;
-}
-
-// Designated initializer that construct an instance to observe |messageCenter|.
-- (id)initWithMessageCenter:(message_center::MessageCenter*)messageCenter;
-
-// Returns true if an animation is being played.
-- (BOOL)isAnimating;
-
-// Returns the duration of the popup animation.
-- (NSTimeInterval)popupAnimationDuration;
-
-// Called when the animation of a popup ends.
-- (void)onPopupAnimationEnded:(const std::string&)notificationID;
-
-@end
-
-@interface MCPopupCollection (ExposedForTesting)
-- (NSArray*)popups;
-
-// Setter for the testingScreenFrame_.
-- (void)setScreenFrame:(NSRect)frame;
-
-// Setter for changing the animation duration. The testing code could set it
-// to a very small value to expedite the test running.
-- (void)setAnimationDuration:(NSTimeInterval)duration;
-
-// Setter for testingAnimationEndedCallback_. The testing code could set it
-// to get called back when the animation ends.
-- (void)setAnimationEndedCallback:
- (message_center::AnimationEndedCallback)callback;
-@end
-
-#endif // UI_MESSAGE_CENTER_COCOA_POPUP_COLLECTION_H_
diff --git a/chromium/ui/message_center/cocoa/popup_collection.mm b/chromium/ui/message_center/cocoa/popup_collection.mm
deleted file mode 100644
index b4df87a8a11..00000000000
--- a/chromium/ui/message_center/cocoa/popup_collection.mm
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/message_center/cocoa/popup_collection.h"
-
-#import "ui/message_center/cocoa/notification_controller.h"
-#import "ui/message_center/cocoa/popup_controller.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/message_center_observer.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
-
-const float kAnimationDuration = 0.2;
-
-@interface MCPopupCollection (Private)
-// Returns the primary screen's visible frame rectangle.
-- (NSRect)screenFrame;
-
-// Shows a popup, if there is room on-screen, for the given notification.
-// Returns YES if the notification was actually displayed.
-- (BOOL)addNotification:(const message_center::Notification*)notification;
-
-// Updates the contents of the notification with the given ID.
-- (void)updateNotification:(const std::string&)notificationID;
-
-// Removes a popup from the screen and lays out new notifications that can
-// now potentially fit on the screen.
-- (void)removeNotification:(const std::string&)notificationID;
-
-// Closes all the popups.
-- (void)removeAllNotifications;
-
-// Returns the index of the popup showing the notification with the given ID.
-- (NSUInteger)indexOfPopupWithNotificationID:(const std::string&)notificationID;
-
-// Repositions all popup notifications if needed.
-- (void)layoutNotifications;
-
-// Fits as many new notifications as possible on screen.
-- (void)layoutNewNotifications;
-
-// Process notifications pending to remove when no animation is being played.
-- (void)processPendingRemoveNotifications;
-
-// Process notifications pending to update when no animation is being played.
-- (void)processPendingUpdateNotifications;
-@end
-
-namespace {
-
-class PopupCollectionObserver : public message_center::MessageCenterObserver {
- public:
- PopupCollectionObserver(message_center::MessageCenter* message_center,
- MCPopupCollection* popup_collection)
- : message_center_(message_center),
- popup_collection_(popup_collection) {
- message_center_->AddObserver(this);
- }
-
- ~PopupCollectionObserver() override { message_center_->RemoveObserver(this); }
-
- void OnNotificationAdded(const std::string& notification_id) override {
- [popup_collection_ layoutNewNotifications];
- }
-
- void OnNotificationRemoved(const std::string& notification_id,
- bool user_id) override {
- [popup_collection_ removeNotification:notification_id];
- }
-
- void OnNotificationUpdated(const std::string& notification_id) override {
- [popup_collection_ updateNotification:notification_id];
- }
-
- private:
- message_center::MessageCenter* message_center_; // Weak, global.
-
- MCPopupCollection* popup_collection_; // Weak, owns this.
-};
-
-} // namespace
-
-@implementation MCPopupCollection
-
-- (id)initWithMessageCenter:(message_center::MessageCenter*)messageCenter {
- if ((self = [super init])) {
- messageCenter_ = messageCenter;
- observer_.reset(new PopupCollectionObserver(messageCenter_, self));
- popups_.reset([[NSMutableArray alloc] init]);
- popupsBeingRemoved_.reset([[NSMutableArray alloc] init]);
- popupAnimationDuration_ = kAnimationDuration;
- }
- return self;
-}
-
-- (void)dealloc {
- [popupsBeingRemoved_ makeObjectsPerformSelector:
- @selector(markPopupCollectionGone)];
- [self removeAllNotifications];
- [super dealloc];
-}
-
-- (BOOL)isAnimating {
- return !animatingNotificationIDs_.empty();
-}
-
-- (NSTimeInterval)popupAnimationDuration {
- return popupAnimationDuration_;
-}
-
-- (void)onPopupAnimationEnded:(const std::string&)notificationID {
- NSUInteger index = [popupsBeingRemoved_ indexOfObjectPassingTest:
- ^BOOL(id popup, NSUInteger index, BOOL* stop) {
- return [popup notificationID] == notificationID;
- }];
- if (index != NSNotFound)
- [popupsBeingRemoved_ removeObjectAtIndex:index];
-
- animatingNotificationIDs_.erase(notificationID);
- if (![self isAnimating])
- [self layoutNotifications];
-
- // Give the testing code a chance to do something, i.e. quitting the test
- // run loop.
- if (![self isAnimating] && testingAnimationEndedCallback_)
- testingAnimationEndedCallback_.get()();
-}
-
-// Testing API /////////////////////////////////////////////////////////////////
-
-- (NSArray*)popups {
- return popups_.get();
-}
-
-- (void)setScreenFrame:(NSRect)frame {
- testingScreenFrame_ = frame;
-}
-
-- (void)setAnimationDuration:(NSTimeInterval)duration {
- popupAnimationDuration_ = duration;
-}
-
-- (void)setAnimationEndedCallback:
- (message_center::AnimationEndedCallback)callback {
- testingAnimationEndedCallback_.reset(Block_copy(callback));
-}
-
-// Private /////////////////////////////////////////////////////////////////////
-
-- (NSRect)screenFrame {
- if (!NSIsEmptyRect(testingScreenFrame_))
- return testingScreenFrame_;
- return [[[NSScreen screens] firstObject] visibleFrame];
-}
-
-- (BOOL)addNotification:(const message_center::Notification*)notification {
- // Wait till all existing animations end.
- if ([self isAnimating])
- return NO;
-
- // The popup is owned by itself. It will be released at close.
- MCPopupController* popup =
- [[MCPopupController alloc] initWithNotification:notification
- messageCenter:messageCenter_
- popupCollection:self];
-
- NSRect screenFrame = [self screenFrame];
- NSRect popupFrame = [popup bounds];
-
- CGFloat x = NSMaxX(screenFrame) - message_center::kMarginBetweenPopups -
- NSWidth(popupFrame);
- CGFloat y = 0;
-
- MCPopupController* bottomPopup = [popups_ lastObject];
- if (!bottomPopup) {
- y = NSMaxY(screenFrame);
- } else {
- y = NSMinY([bottomPopup bounds]);
- }
-
- y -= message_center::kMarginBetweenPopups + NSHeight(popupFrame);
-
- if (y > NSMinY(screenFrame)) {
- animatingNotificationIDs_.insert(notification->id());
- NSRect bounds = [popup bounds];
- bounds.origin.x = x;
- bounds.origin.y = y;
- [popup showWithAnimation:bounds];
- [popups_ addObject:popup];
- messageCenter_->DisplayedNotification(
- notification->id(), message_center::DISPLAY_SOURCE_POPUP);
- return YES;
- }
-
- // The popup cannot fit on screen, so it has to be closed now.
- [popup close];
- return NO;
-}
-
-- (void)updateNotification:(const std::string&)notificationID {
- // The notification may not be on screen. Create it if needed.
- if ([self indexOfPopupWithNotificationID:notificationID] == NSNotFound) {
- [self layoutNewNotifications];
- return;
- }
-
- // Don't bother with the update if the notification is going to be removed.
- if (pendingRemoveNotificationIDs_.find(notificationID) !=
- pendingRemoveNotificationIDs_.end()) {
- return;
- }
-
- pendingUpdateNotificationIDs_.insert(notificationID);
- [self processPendingUpdateNotifications];
-}
-
-- (void)removeNotification:(const std::string&)notificationID {
- // The notification may not be on screen.
- if ([self indexOfPopupWithNotificationID:notificationID] == NSNotFound)
- return;
-
- // Don't bother with the update if the notification is going to be removed.
- pendingUpdateNotificationIDs_.erase(notificationID);
-
- pendingRemoveNotificationIDs_.insert(notificationID);
- [self processPendingRemoveNotifications];
-}
-
-- (void)removeAllNotifications {
- // In rare cases, the popup collection would be gone while an animation is
- // still playing. For exmaple, the test code could show a new notification
- // and dispose the collection immediately. Close the popup without animation
- // when this is the case.
- if ([self isAnimating])
- [popups_ makeObjectsPerformSelector:@selector(close)];
- else
- [popups_ makeObjectsPerformSelector:@selector(closeWithAnimation)];
- [popups_ makeObjectsPerformSelector:@selector(markPopupCollectionGone)];
- [popups_ removeAllObjects];
-}
-
-- (NSUInteger)indexOfPopupWithNotificationID:
- (const std::string&)notificationID {
- return [popups_ indexOfObjectPassingTest:
- ^BOOL(id popup, NSUInteger index, BOOL* stop) {
- return [popup notificationID] == notificationID;
- }];
-}
-
-- (void)layoutNotifications {
- // Wait till all existing animations end.
- if ([self isAnimating])
- return;
-
- NSRect screenFrame = [self screenFrame];
-
- // The popup starts at top-right corner.
- CGFloat maxY = NSMaxY(screenFrame);
-
- // Iterate all notifications and reposition each if needed. If one does not
- // fit on screen, close it and any other on-screen popups that come after it.
- NSUInteger removeAt = NSNotFound;
- for (NSUInteger i = 0; i < [popups_ count]; ++i) {
- MCPopupController* popup = [popups_ objectAtIndex:i];
- NSRect oldFrame = [popup bounds];
- NSRect frame = oldFrame;
- frame.origin.y =
- maxY - message_center::kMarginBetweenPopups - NSHeight(frame);
-
- // If this popup does not fit on screen, stop repositioning and close this
- // and subsequent popups.
- if (NSMinY(frame) < NSMinY(screenFrame)) {
- removeAt = i;
- break;
- }
-
- if (!NSEqualRects(frame, oldFrame)) {
- [popup setBounds:frame];
- animatingNotificationIDs_.insert([popup notificationID]);
- }
-
- // Set the new maximum Y to be the bottom of this notification.
- maxY = NSMinY(frame);
- }
-
- if (removeAt != NSNotFound) {
- // Remove any popups that are on screen but no longer fit.
- while ([popups_ count] >= removeAt && [popups_ count]) {
- [[popups_ lastObject] close];
- [popups_ removeLastObject];
- }
- } else {
- [self layoutNewNotifications];
- }
-
- [self processPendingRemoveNotifications];
- [self processPendingUpdateNotifications];
-}
-
-- (void)layoutNewNotifications {
- // Wait till all existing animations end.
- if ([self isAnimating])
- return;
-
- // Display any new popups that can now fit on screen, starting from the
- // oldest notification that has not been shown up.
- const auto& allPopups = messageCenter_->GetPopupNotifications();
- for (auto it = allPopups.rbegin(); it != allPopups.rend(); ++it) {
- if ([self indexOfPopupWithNotificationID:(*it)->id()] == NSNotFound) {
- // If there's no room left on screen to display notifications, stop
- // trying.
- if (![self addNotification:*it])
- break;
- }
- }
-}
-
-- (void)processPendingRemoveNotifications {
- // Wait till all existing animations end.
- if ([self isAnimating])
- return;
-
- for (const auto& notificationID : pendingRemoveNotificationIDs_) {
- NSUInteger index = [self indexOfPopupWithNotificationID:notificationID];
- if (index != NSNotFound) {
- [[popups_ objectAtIndex:index] closeWithAnimation];
- animatingNotificationIDs_.insert(notificationID);
-
- // Still need to track popup object and only remove it after the animation
- // ends. We need to notify these objects that the collection is gone
- // in the collection destructor.
- [popupsBeingRemoved_ addObject:[popups_ objectAtIndex:index]];
- [popups_ removeObjectAtIndex:index];
- }
- }
- pendingRemoveNotificationIDs_.clear();
-}
-
-- (void)processPendingUpdateNotifications {
- // Wait till all existing animations end.
- if ([self isAnimating])
- return;
-
- if (pendingUpdateNotificationIDs_.empty())
- return;
-
- // Go through all model objects in the message center. If there is a replaced
- // notification, the controller's current model object may be stale.
- const auto& modelPopups = messageCenter_->GetPopupNotifications();
- for (auto iter = modelPopups.begin(); iter != modelPopups.end(); ++iter) {
- const std::string& notificationID = (*iter)->id();
-
- // Does the notification need to be updated?
- std::set<std::string>::iterator pendingUpdateIter =
- pendingUpdateNotificationIDs_.find(notificationID);
- if (pendingUpdateIter == pendingUpdateNotificationIDs_.end())
- continue;
- pendingUpdateNotificationIDs_.erase(pendingUpdateIter);
-
- // Is the notification still on screen?
- NSUInteger index = [self indexOfPopupWithNotificationID:notificationID];
- if (index == NSNotFound)
- continue;
-
- MCPopupController* popup = [popups_ objectAtIndex:index];
-
- CGFloat oldHeight =
- NSHeight([[[popup notificationController] view] frame]);
- CGFloat newHeight = NSHeight(
- [[popup notificationController] updateNotification:*iter]);
-
- // The notification has changed height. This requires updating the popup
- // window.
- if (oldHeight != newHeight) {
- NSRect popupFrame = [popup bounds];
- popupFrame.origin.y -= newHeight - oldHeight;
- popupFrame.size.height += newHeight - oldHeight;
- [popup setBounds:popupFrame];
- animatingNotificationIDs_.insert([popup notificationID]);
- }
- }
-
- // Notification update could be received when a notification is excluded from
- // the popup notification list but still remains in the full notification
- // list, as in clicking the popup. In that case, the popup should be closed.
- for (auto iter = pendingUpdateNotificationIDs_.begin();
- iter != pendingUpdateNotificationIDs_.end(); ++iter) {
- pendingRemoveNotificationIDs_.insert(*iter);
- }
-
- pendingUpdateNotificationIDs_.clear();
-
- // Start re-layout of all notifications, so that it readjusts the Y origin of
- // all updated popups and any popups that come below them.
- [self layoutNotifications];
-}
-
-@end
diff --git a/chromium/ui/message_center/cocoa/popup_collection_unittest.mm b/chromium/ui/message_center/cocoa/popup_collection_unittest.mm
deleted file mode 100644
index e8a5d3fe9b3..00000000000
--- a/chromium/ui/message_center/cocoa/popup_collection_unittest.mm
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/message_center/cocoa/popup_collection.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/run_loop.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_environment.h"
-#import "ui/base/test/cocoa_helper.h"
-#import "ui/message_center/cocoa/notification_controller.h"
-#import "ui/message_center/cocoa/popup_controller.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
-#include "ui/message_center/public/cpp/notification.h"
-
-using base::ASCIIToUTF16;
-
-namespace message_center {
-
-class PopupCollectionTest : public ui::CocoaTest {
- public:
- PopupCollectionTest()
- : scoped_task_environment_(
- base::test::ScopedTaskEnvironment::MainThreadType::UI) {
- message_center::MessageCenter::Initialize();
- center_ = message_center::MessageCenter::Get();
- collection_.reset(
- [[MCPopupCollection alloc] initWithMessageCenter:center_]);
- [collection_ setAnimationDuration:0.001];
- [collection_ setAnimationEndedCallback:^{
- if (nested_run_loop_.get())
- nested_run_loop_->Quit();
- }];
- }
-
- void TearDown() override {
- collection_.reset(); // Close all popups.
- ui::CocoaTest::TearDown();
- }
-
- ~PopupCollectionTest() override { message_center::MessageCenter::Shutdown(); }
-
- message_center::NotifierId DummyNotifierId() {
- return message_center::NotifierId();
- }
-
- void AddThreeNotifications() {
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("This is the first notification to"
- " be displayed"),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
-
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "2", ASCIIToUTF16("Two"),
- ASCIIToUTF16("This is the second notification."), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
-
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "3", ASCIIToUTF16("Three"),
- ASCIIToUTF16("This is the third notification "
- "that has a much longer body "
- "than the other notifications. It "
- "may not fit on the screen if we "
- "set the screen size too small or "
- "if the notification is way too big"),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
- WaitForAnimationEnded();
- }
-
- bool CheckSpacingBetween(MCPopupController* upper, MCPopupController* lower) {
- CGFloat minY = NSMinY([[upper window] frame]);
- CGFloat maxY = NSMaxY([[lower window] frame]);
- CGFloat delta = minY - maxY;
- EXPECT_EQ(message_center::kMarginBetweenPopups, delta);
- return delta == message_center::kMarginBetweenPopups;
- }
-
- void WaitForAnimationEnded() {
- if (![collection_ isAnimating])
- return;
- nested_run_loop_.reset(new base::RunLoop());
- nested_run_loop_->Run();
- nested_run_loop_.reset();
- }
-
- base::test::ScopedTaskEnvironment scoped_task_environment_;
- std::unique_ptr<base::RunLoop> nested_run_loop_;
- message_center::MessageCenter* center_;
- base::scoped_nsobject<MCPopupCollection> collection_;
-};
-
-TEST_F(PopupCollectionTest, AddThreeCloseOne) {
- EXPECT_EQ(0u, [[collection_ popups] count]);
- AddThreeNotifications();
- EXPECT_EQ(3u, [[collection_ popups] count]);
-
- center_->RemoveNotification("2", true);
- WaitForAnimationEnded();
- EXPECT_EQ(2u, [[collection_ popups] count]);
-}
-
-TEST_F(PopupCollectionTest, AttemptFourOneOffscreen) {
- [collection_ setScreenFrame:NSMakeRect(0, 0, 800, 300)];
-
- EXPECT_EQ(0u, [[collection_ popups] count]);
- AddThreeNotifications();
- EXPECT_EQ(2u, [[collection_ popups] count]); // "3" does not fit on screen.
-
- std::unique_ptr<message_center::Notification> notification;
-
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "4", ASCIIToUTF16("Four"),
- ASCIIToUTF16("This is the fourth notification."), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
- WaitForAnimationEnded();
-
- // Remove "1" and "3" should fit on screen.
- center_->RemoveNotification("1", true);
- WaitForAnimationEnded();
- ASSERT_EQ(2u, [[collection_ popups] count]);
-
- EXPECT_EQ("2", [[[collection_ popups] objectAtIndex:0] notificationID]);
- EXPECT_EQ("3", [[[collection_ popups] objectAtIndex:1] notificationID]);
-
- // Remove "2" and "4" should fit on screen.
- center_->RemoveNotification("2", true);
- WaitForAnimationEnded();
- ASSERT_EQ(2u, [[collection_ popups] count]);
-
- EXPECT_EQ("3", [[[collection_ popups] objectAtIndex:0] notificationID]);
- EXPECT_EQ("4", [[[collection_ popups] objectAtIndex:1] notificationID]);
-}
-
-TEST_F(PopupCollectionTest, LayoutSpacing) {
- const CGFloat kScreenSize = 500;
- [collection_ setScreenFrame:NSMakeRect(0, 0, kScreenSize, kScreenSize)];
-
- AddThreeNotifications();
- NSArray* popups = [collection_ popups];
-
- EXPECT_EQ(message_center::kMarginBetweenPopups,
- kScreenSize - NSMaxY([[[popups objectAtIndex:0] window] frame]));
-
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
- [popups objectAtIndex:1]));
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
- [popups objectAtIndex:2]));
-
- // Set priority so that kMaxVisiblePopupNotifications does not hide it.
- message_center::RichNotificationData optional;
- optional.priority = message_center::HIGH_PRIORITY;
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "4", ASCIIToUTF16("Four"),
- ASCIIToUTF16("This is the fourth notification."), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(), optional, NULL));
- center_->AddNotification(std::move(notification));
- WaitForAnimationEnded();
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:2],
- [popups objectAtIndex:3]));
-
- // Remove "2".
- center_->RemoveNotification("2", true);
- WaitForAnimationEnded();
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
- [popups objectAtIndex:1]));
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
- [popups objectAtIndex:2]));
-
- // Remove "1".
- center_->RemoveNotification("2", true);
- WaitForAnimationEnded();
- EXPECT_EQ(message_center::kMarginBetweenPopups,
- kScreenSize - NSMaxY([[[popups objectAtIndex:0] window] frame]));
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
- [popups objectAtIndex:1]));
-}
-
-TEST_F(PopupCollectionTest, TinyScreen) {
- [collection_ setScreenFrame:NSMakeRect(0, 0, 800, 100)];
-
- EXPECT_EQ(0u, [[collection_ popups] count]);
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("This is the first notification to"
- " be displayed"),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
- WaitForAnimationEnded();
- EXPECT_EQ(1u, [[collection_ popups] count]);
-
- // Now give the notification a longer message so that it no longer fits.
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("This is now a very very very very "
- "very very very very very very very "
- "very very very very very very very "
- "very very very very very very very "
- "very very very very very very very "
- "very very very very very very very "
- "very very very very very very very "
- "long notification."),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->UpdateNotification("1", std::move(notification));
- WaitForAnimationEnded();
- EXPECT_EQ(0u, [[collection_ popups] count]);
-}
-
-TEST_F(PopupCollectionTest, UpdateIconAndBody) {
- AddThreeNotifications();
- NSArray* popups = [collection_ popups];
-
- EXPECT_EQ(3u, [popups count]);
-
- // Update "2" icon.
- MCNotificationController* controller =
- [[popups objectAtIndex:1] notificationController];
- EXPECT_FALSE([[controller iconView] image]);
- center_->SetNotificationIcon("2",
- gfx::Image([[NSImage imageNamed:NSImageNameUser] retain]));
- WaitForAnimationEnded();
- EXPECT_TRUE([[controller iconView] image]);
-
- EXPECT_EQ(3u, [popups count]);
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
- [popups objectAtIndex:1]));
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
- [popups objectAtIndex:2]));
-
- // Replace "1".
- controller = [[popups objectAtIndex:0] notificationController];
- NSRect old_frame = [[controller view] frame];
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1",
- ASCIIToUTF16("One is going to get a much longer "
- "title than it previously had."),
- ASCIIToUTF16("This is the first notification to "
- "be displayed, but it will also be "
- "updated to have a significantly "
- "longer body"),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
- WaitForAnimationEnded();
- EXPECT_GT(NSHeight([[controller view] frame]), NSHeight(old_frame));
-
- // Test updated spacing.
- EXPECT_EQ(3u, [popups count]);
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
- [popups objectAtIndex:1]));
- EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
- [popups objectAtIndex:2]));
- EXPECT_EQ("1", [[popups objectAtIndex:0] notificationID]);
- EXPECT_EQ("2", [[popups objectAtIndex:1] notificationID]);
- EXPECT_EQ("3", [[popups objectAtIndex:2] notificationID]);
-}
-
-TEST_F(PopupCollectionTest, UpdatePriority) {
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("This notification should not yet toast."), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- notification->set_priority(-1);
-
- center_->AddNotification(std::move(notification));
- WaitForAnimationEnded();
- NSArray* popups = [collection_ popups];
- EXPECT_EQ(0u, [popups count]);
-
- // Raise priority -1 to 1. Notification should display.
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("This notification should now toast"), gfx::Image(),
- base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- notification->set_priority(1);
-
- center_->UpdateNotification("1", std::move(notification));
- WaitForAnimationEnded();
- EXPECT_EQ(1u, [popups count]);
-}
-
-TEST_F(PopupCollectionTest, CloseCollectionBeforeNewPopupAnimationEnds) {
- // Add a notification and don't wait for the animation to finish.
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("This is the first notification to"
- " be displayed"),
- gfx::Image(), base::string16(), GURL(), DummyNotifierId(),
- message_center::RichNotificationData(), NULL));
- center_->AddNotification(std::move(notification));
-
- // Release the popup collection before the animation ends. No crash should
- // be expected.
- collection_.reset();
-}
-
-TEST_F(PopupCollectionTest, CloseCollectionBeforeClosePopupAnimationEnds) {
- AddThreeNotifications();
-
- // Remove a notification and don't wait for the animation to finish.
- center_->RemoveNotification("1", true);
-
- // Release the popup collection before the animation ends. No crash should
- // be expected.
- collection_.reset();
-}
-
-TEST_F(PopupCollectionTest, CloseCollectionBeforeUpdatePopupAnimationEnds) {
- AddThreeNotifications();
-
- // Update a notification and don't wait for the animation to finish.
- std::unique_ptr<message_center::Notification> notification;
- notification.reset(new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "1", ASCIIToUTF16("One"),
- ASCIIToUTF16("New message."), gfx::Image(), base::string16(), GURL(),
- DummyNotifierId(), message_center::RichNotificationData(), NULL));
- center_->UpdateNotification("1", std::move(notification));
-
- // Release the popup collection before the animation ends. No crash should
- // be expected.
- collection_.reset();
-}
-
-} // namespace message_center
diff --git a/chromium/ui/message_center/cocoa/popup_controller.h b/chromium/ui/message_center/cocoa/popup_controller.h
deleted file mode 100644
index f8527823bcf..00000000000
--- a/chromium/ui/message_center/cocoa/popup_controller.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_MESSAGE_CENTER_COCOA_POPUP_CONTROLLER_H_
-#define UI_MESSAGE_CENTER_COCOA_POPUP_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <string>
-
-#import "base/mac/scoped_nsobject.h"
-#import "ui/base/cocoa/tracking_area.h"
-#include "ui/message_center/message_center_export.h"
-
-namespace message_center {
-class MessageCenter;
-class Notification;
-}
-
-@class MCNotificationController;
-@class MCPopupCollection;
-
-// A window controller that hosts a notification as a popup balloon on the
-// user's desktop. The window controller manages its lifetime because the
-// popup collection will be destructed when the last popup is closed.
-MESSAGE_CENTER_EXPORT
-@interface MCPopupController : NSWindowController<NSAnimationDelegate> {
- @private
- // Global message center. Weak.
- message_center::MessageCenter* messageCenter_;
-
- // The collection that contains the popup. Weak.
- MCPopupCollection* popupCollection_;
-
- // The view controller that provide's the popup content view.
- base::scoped_nsobject<MCNotificationController> notificationController_;
-
- // If the swipe-away gesture received NSEventPhaseEnded.
- BOOL swipeGestureEnded_;
-
- // The frame of the popup before any swipe animation started. Used to
- // calculate the animating position of the window when swiping away.
- NSRect originalFrame_;
-
- // Is the popup currently being closed?
- BOOL isClosing_;
-
-#ifndef NDEBUG
- // Has the popup been closed before being dealloc-ed.
- BOOL hasBeenClosed_;
-#endif
-
- // The current bounds of the popup frame if no animation is playing.
- // Otherwise, it is the target bounds of the popup frame.
- NSRect bounds_;
-
- // Used to play animation when the popup shows, changes bounds and closes.
- base::scoped_nsobject<NSViewAnimation> boundsAnimation_;
-
- // Used to track the popup for mouse entered and exited events.
- ui::ScopedCrTrackingArea trackingArea_;
-}
-
-// Designated initializer.
-- (id)initWithNotification:(const message_center::Notification*)notification
- messageCenter:(message_center::MessageCenter*)messageCenter
- popupCollection:(MCPopupCollection*)popupCollection;
-
-// Accessor for the view controller.
-- (MCNotificationController*)notificationController;
-
-// Accessor for the notification model object.
-- (const message_center::Notification*)notification;
-
-// Gets the notification ID. This string is owned by the NotificationController
-// rather than the model object, so it's safe to use after the Notification has
-// been deleted.
-- (const std::string&)notificationID;
-
-// Shows the window with the sliding animation.
-- (void)showWithAnimation:(NSRect)newBounds;
-
-// Closes the window with the fade-out animation.
-- (void)closeWithAnimation;
-
-// Tells that the popupCollection_ is gone.
-- (void)markPopupCollectionGone;
-
-// Returns the window bounds. This is the target bounds to go to if the bounds
-// animation is playing.
-- (NSRect)bounds;
-
-// Changes the window bounds with animation.
-- (void)setBounds:(NSRect)newBounds;
-
-@end
-
-#endif // UI_MESSAGE_CENTER_COCOA_POPUP_CONTROLLER_H_
diff --git a/chromium/ui/message_center/cocoa/popup_controller.mm b/chromium/ui/message_center/cocoa/popup_controller.mm
deleted file mode 100644
index e8e77281495..00000000000
--- a/chromium/ui/message_center/cocoa/popup_controller.mm
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/message_center/cocoa/popup_controller.h"
-
-#include <cmath>
-
-#import "base/mac/foundation_util.h"
-#import "base/mac/sdk_forward_declarations.h"
-#import "ui/base/cocoa/window_size_constants.h"
-#import "ui/message_center/cocoa/notification_controller.h"
-#import "ui/message_center/cocoa/popup_collection.h"
-#include "ui/message_center/message_center.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-@interface MCPopupController (Private)
-- (void)notificationSwipeStarted;
-- (void)notificationSwipeMoved:(CGFloat)amount;
-- (void)notificationSwipeEnded:(BOOL)ended complete:(BOOL)isComplete;
-
-// This setter for |boundsAnimation_| also cleans up the state of the previous
-// |boundsAnimation_|.
-- (void)setBoundsAnimation:(NSViewAnimation*)animation;
-
-// Constructs an NSViewAnimation from |dictionary|, which should be a view
-// animation dictionary.
-- (NSViewAnimation*)animationWithDictionary:(NSDictionary*)dictionary;
-@end
-
-// Window Subclass /////////////////////////////////////////////////////////////
-
-@interface MCPopupWindow : NSPanel {
- // The cumulative X and Y scrollingDeltas since the -scrollWheel: event began.
- NSPoint totalScrollDelta_;
-}
-@end
-
-@implementation MCPopupWindow
-
-- (void)scrollWheel:(NSEvent*)event {
- // Gesture swiping only exists on 10.7+.
- if (![event respondsToSelector:@selector(phase)])
- return;
-
- NSEventPhase phase = [event phase];
- BOOL shouldTrackSwipe = NO;
-
- if (phase == NSEventPhaseBegan) {
- totalScrollDelta_ = NSZeroPoint;
- } else if (phase == NSEventPhaseChanged) {
- shouldTrackSwipe = YES;
- totalScrollDelta_.x += [event scrollingDeltaX];
- totalScrollDelta_.y += [event scrollingDeltaY];
- }
-
- // Only allow horizontal scrolling.
- if (std::abs(totalScrollDelta_.x) < std::abs(totalScrollDelta_.y))
- return;
-
- if (shouldTrackSwipe) {
- MCPopupController* controller =
- base::mac::ObjCCastStrict<MCPopupController>([self windowController]);
- BOOL directionInverted = [event isDirectionInvertedFromDevice];
-
- auto handler = ^(CGFloat gestureAmount, NSEventPhase phase,
- BOOL isComplete, BOOL* stop) {
- // The swipe direction should match the direction the user's fingers
- // are moving, not the interpreted scroll direction.
- if (directionInverted)
- gestureAmount *= -1;
-
- if (phase == NSEventPhaseBegan) {
- [controller notificationSwipeStarted];
- return;
- }
-
- [controller notificationSwipeMoved:gestureAmount];
-
- BOOL ended = phase == NSEventPhaseEnded;
- if (ended || isComplete)
- [controller notificationSwipeEnded:ended complete:isComplete];
- };
- [event trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection
- dampenAmountThresholdMin:-1
- max:1
- usingHandler:handler];
- }
-}
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////
-
-@implementation MCPopupController
-
-- (id)initWithNotification:(const message_center::Notification*)notification
- messageCenter:(message_center::MessageCenter*)messageCenter
- popupCollection:(MCPopupCollection*)popupCollection {
- base::scoped_nsobject<MCPopupWindow> window([[MCPopupWindow alloc]
- initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:NSNonactivatingPanelMask
- backing:NSBackingStoreBuffered
- defer:NO]);
- if ((self = [super initWithWindow:window])) {
- messageCenter_ = messageCenter;
- popupCollection_ = popupCollection;
- notificationController_.reset(
- [[MCNotificationController alloc] initWithNotification:notification
- messageCenter:messageCenter_]);
- bounds_ = [[notificationController_ view] frame];
-
- [window setFloatingPanel:YES];
- [window setBecomesKeyOnlyIfNeeded:YES];
- [window
- setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces |
- NSWindowCollectionBehaviorFullScreenAuxiliary];
-
- [window setHasShadow:YES];
- [window setContentView:[notificationController_ view]];
-
- trackingArea_.reset(
- [[CrTrackingArea alloc] initWithRect:NSZeroRect
- options:NSTrackingInVisibleRect |
- NSTrackingMouseEnteredAndExited |
- NSTrackingActiveAlways
- owner:self
- userInfo:nil]);
- [[window contentView] addTrackingArea:trackingArea_.get()];
- }
- return self;
-}
-
-#ifndef NDEBUG
-- (void)dealloc {
- DCHECK(hasBeenClosed_);
- [super dealloc];
-}
-#endif
-
-- (void)close {
-#ifndef NDEBUG
- hasBeenClosed_ = YES;
-#endif
- [self setBoundsAnimation:nil];
- if (trackingArea_.get())
- [[[self window] contentView] removeTrackingArea:trackingArea_.get()];
- [super close];
- [self performSelectorOnMainThread:@selector(release)
- withObject:nil
- waitUntilDone:NO
- modes:@[ NSDefaultRunLoopMode ]];
-}
-
-- (MCNotificationController*)notificationController {
- return notificationController_.get();
-}
-
-- (const message_center::Notification*)notification {
- return [notificationController_ notification];
-}
-
-- (const std::string&)notificationID {
- return [notificationController_ notificationID];
-}
-
-// Private /////////////////////////////////////////////////////////////////////
-
-- (void)notificationSwipeStarted {
- originalFrame_ = [[self window] frame];
- swipeGestureEnded_ = NO;
-}
-
-- (void)notificationSwipeMoved:(CGFloat)amount {
- NSWindow* window = [self window];
-
- [window setAlphaValue:1.0 - std::abs(amount)];
- NSRect frame = [window frame];
- CGFloat originalMin = NSMinX(originalFrame_);
- frame.origin.x = originalMin + (NSMidX(originalFrame_) - originalMin) *
- -amount;
- [window setFrame:frame display:YES];
-}
-
-- (void)notificationSwipeEnded:(BOOL)ended complete:(BOOL)isComplete {
- swipeGestureEnded_ |= ended;
- if (swipeGestureEnded_ && isComplete) {
- messageCenter_->RemoveNotification([self notificationID], /*by_user=*/true);
- [popupCollection_ onPopupAnimationEnded:[self notificationID]];
- }
-}
-
-- (void)setBoundsAnimation:(NSViewAnimation*)animation {
- [boundsAnimation_ stopAnimation];
- [boundsAnimation_ setDelegate:nil];
- boundsAnimation_.reset([animation retain]);
-}
-
-- (NSViewAnimation*)animationWithDictionary:(NSDictionary*)dictionary {
- return [[[NSViewAnimation alloc]
- initWithViewAnimations:@[ dictionary ]] autorelease];
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
- DCHECK_EQ(animation, boundsAnimation_.get());
- [self setBoundsAnimation:nil];
-
- [popupCollection_ onPopupAnimationEnded:[self notificationID]];
-
- if (isClosing_)
- [self close];
-}
-
-- (void)showWithAnimation:(NSRect)newBounds {
- bounds_ = newBounds;
- NSRect startBounds = newBounds;
- startBounds.origin.x += startBounds.size.width;
- [[self window] setFrame:startBounds display:NO];
- [[self window] setAlphaValue:0];
- [[self window] setCanHide:NO];
- [self showWindow:nil];
-
- // Slide-in and fade-in simultaneously.
- NSDictionary* animationDict = @{
- NSViewAnimationTargetKey : [self window],
- NSViewAnimationEndFrameKey : [NSValue valueWithRect:newBounds],
- NSViewAnimationEffectKey : NSViewAnimationFadeInEffect
- };
- NSViewAnimation* animation = [self animationWithDictionary:animationDict];
- [self setBoundsAnimation:animation];
- [boundsAnimation_ setDuration:[popupCollection_ popupAnimationDuration]];
- [boundsAnimation_ setDelegate:self];
- [boundsAnimation_ startAnimation];
-}
-
-- (void)closeWithAnimation {
- if (isClosing_)
- return;
-
-#ifndef NDEBUG
- hasBeenClosed_ = YES;
-#endif
- isClosing_ = YES;
-
- // If the notification was swiped closed, do not animate it as the
- // notification has already faded out.
- if (swipeGestureEnded_) {
- [self close];
- return;
- }
-
- NSDictionary* animationDict = @{
- NSViewAnimationTargetKey : [self window],
- NSViewAnimationEffectKey : NSViewAnimationFadeOutEffect
- };
- NSViewAnimation* animation = [self animationWithDictionary:animationDict];
- [self setBoundsAnimation:animation];
- [boundsAnimation_ setDuration:[popupCollection_ popupAnimationDuration]];
- [boundsAnimation_ setDelegate:self];
- [boundsAnimation_ startAnimation];
-}
-
-- (void)markPopupCollectionGone {
- popupCollection_ = nil;
-}
-
-- (NSRect)bounds {
- return bounds_;
-}
-
-- (void)setBounds:(NSRect)newBounds {
- if (isClosing_ || NSEqualRects(bounds_ , newBounds))
- return;
- bounds_ = newBounds;
-
- NSDictionary* animationDict = @{
- NSViewAnimationTargetKey : [self window],
- NSViewAnimationEndFrameKey : [NSValue valueWithRect:newBounds]
- };
- NSViewAnimation* animation = [self animationWithDictionary:animationDict];
- [self setBoundsAnimation:animation];
- [boundsAnimation_ setDuration:[popupCollection_ popupAnimationDuration]];
- [boundsAnimation_ setDelegate:self];
- [boundsAnimation_ startAnimation];
-}
-
-- (void)mouseEntered:(NSEvent*)event {
- messageCenter_->PausePopupTimers();
-}
-
-- (void)mouseExited:(NSEvent*)event {
- messageCenter_->RestartPopupTimers();
-}
-
-@end
diff --git a/chromium/ui/message_center/cocoa/popup_controller_unittest.mm b/chromium/ui/message_center/cocoa/popup_controller_unittest.mm
deleted file mode 100644
index 191b2d68463..00000000000
--- a/chromium/ui/message_center/cocoa/popup_controller_unittest.mm
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/message_center/cocoa/popup_controller.h"
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "ui/base/test/cocoa_helper.h"
-#include "ui/message_center/public/cpp/notification.h"
-
-using base::ASCIIToUTF16;
-
-namespace message_center {
-
-class PopupControllerTest : public ui::CocoaTest {
-};
-
-TEST_F(PopupControllerTest, Creation) {
- std::unique_ptr<message_center::Notification> notification(
- new message_center::Notification(
- message_center::NOTIFICATION_TYPE_SIMPLE, "",
- ASCIIToUTF16("Added to circles"),
- ASCIIToUTF16("Jonathan and 5 others"), gfx::Image(), base::string16(),
- GURL(), message_center::NotifierId(),
- message_center::RichNotificationData(), NULL));
-
- base::scoped_nsobject<MCPopupController> controller(
- [[MCPopupController alloc] initWithNotification:notification.get()
- messageCenter:nil
- popupCollection:nil]);
- // Add an extra ref count for scoped_nsobject since MCPopupController will
- // release itself when it is being closed.
- [controller retain];
-
- EXPECT_TRUE([controller window]);
- EXPECT_EQ(notification.get(), [controller notification]);
-
- [controller showWindow:nil];
- [controller close];
-}
-
-} // namespace message_center
diff --git a/chromium/ui/message_center/message_center_impl.cc b/chromium/ui/message_center/message_center_impl.cc
index 1c113d6d4e1..a0765b5ae17 100644
--- a/chromium/ui/message_center/message_center_impl.cc
+++ b/chromium/ui/message_center/message_center_impl.cc
@@ -100,6 +100,9 @@ void MessageCenterImpl::SetVisibility(Visibility visibility) {
for (auto& observer : observer_list_)
observer.OnNotificationUpdated(id);
}
+
+ for (Notification* notification : GetPopupNotifications())
+ MarkSinglePopupAsShown(notification->id(), false);
}
for (auto& observer : observer_list_)
diff --git a/chromium/ui/message_center/message_center_impl_unittest.cc b/chromium/ui/message_center/message_center_impl_unittest.cc
index 6d85eb7ed32..80214ba549e 100644
--- a/chromium/ui/message_center/message_center_impl_unittest.cc
+++ b/chromium/ui/message_center/message_center_impl_unittest.cc
@@ -199,7 +199,7 @@ class MessageCenterImplTest : public testing::Test {
return std::make_unique<Notification>(
type, id, UTF8ToUTF16("title"), UTF8ToUTF16(id),
gfx::Image() /* icon */, base::string16() /* display_source */, GURL(),
- NotifierId(NotifierId::APPLICATION, notifier_id), optional_fields,
+ NotifierId(NotifierType::APPLICATION, notifier_id), optional_fields,
base::MakeRefCounted<TestDelegate>());
}
@@ -458,7 +458,7 @@ TEST_F(MessageCenterImplTest, PopupTimersControllerRestartOnUpdate) {
}
TEST_F(MessageCenterImplTest, NotificationBlocker) {
- NotifierId notifier_id(NotifierId::APPLICATION, "app1");
+ NotifierId notifier_id(NotifierType::APPLICATION, "app1");
// Multiple blockers to verify the case that one blocker blocks but another
// doesn't.
ToggledNotificationBlocker blocker1(message_center());
@@ -514,7 +514,7 @@ TEST_F(MessageCenterImplTest, NotificationBlocker) {
}
TEST_F(MessageCenterImplTest, NotificationsDuringBlocked) {
- NotifierId notifier_id(NotifierId::APPLICATION, "app1");
+ NotifierId notifier_id(NotifierType::APPLICATION, "app1");
ToggledNotificationBlocker blocker(message_center());
message_center()->AddNotification(std::unique_ptr<Notification>(
@@ -550,8 +550,8 @@ TEST_F(MessageCenterImplTest, NotificationsDuringBlocked) {
// Similar to other blocker cases but this test case allows |notifier_id2| even
// in blocked.
TEST_F(MessageCenterImplTest, NotificationBlockerAllowsPopups) {
- NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
- NotifierId notifier_id2(NotifierId::APPLICATION, "app2");
+ NotifierId notifier_id1(NotifierType::APPLICATION, "app1");
+ NotifierId notifier_id2(NotifierType::APPLICATION, "app2");
PopupNotificationBlocker blocker(message_center(), notifier_id2);
message_center()->AddNotification(std::unique_ptr<Notification>(
@@ -605,8 +605,8 @@ TEST_F(MessageCenterImplTest, NotificationBlockerAllowsPopups) {
// This would provide the feature to 'separated' message centers per-profile for
// ChromeOS multi-login.
TEST_F(MessageCenterImplTest, TotalNotificationBlocker) {
- NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
- NotifierId notifier_id2(NotifierId::APPLICATION, "app2");
+ NotifierId notifier_id1(NotifierType::APPLICATION, "app1");
+ NotifierId notifier_id2(NotifierType::APPLICATION, "app2");
TotalNotificationBlocker blocker(message_center(), notifier_id2);
message_center()->AddNotification(std::unique_ptr<Notification>(
@@ -674,8 +674,8 @@ TEST_F(MessageCenterImplTest, TotalNotificationBlocker) {
}
TEST_F(MessageCenterImplTest, RemoveAllNotifications) {
- NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
- NotifierId notifier_id2(NotifierId::APPLICATION, "app2");
+ NotifierId notifier_id1(NotifierType::APPLICATION, "app1");
+ NotifierId notifier_id2(NotifierType::APPLICATION, "app2");
TotalNotificationBlocker blocker(message_center(), notifier_id1);
blocker.SetNotificationsEnabled(false);
@@ -712,8 +712,8 @@ TEST_F(MessageCenterImplTest, RemoveAllNotifications) {
#if defined(OS_CHROMEOS)
TEST_F(MessageCenterImplTest, RemoveAllNotificationsWithPinned) {
- NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
- NotifierId notifier_id2(NotifierId::APPLICATION, "app2");
+ NotifierId notifier_id1(NotifierType::APPLICATION, "app1");
+ NotifierId notifier_id2(NotifierType::APPLICATION, "app2");
TotalNotificationBlocker blocker(message_center(), notifier_id1);
blocker.SetNotificationsEnabled(false);
@@ -793,24 +793,24 @@ TEST_F(MessageCenterImplTest, NotifierEnabledChanged) {
// Removing all of app2's notifications should only leave app1's.
message_center()->RemoveNotificationsForNotifierId(
- NotifierId(NotifierId::APPLICATION, "app2"));
+ NotifierId(NotifierType::APPLICATION, "app2"));
ASSERT_EQ(3u, message_center()->NotificationCount());
// Removal operations should be idempotent.
message_center()->RemoveNotificationsForNotifierId(
- NotifierId(NotifierId::APPLICATION, "app2"));
+ NotifierId(NotifierType::APPLICATION, "app2"));
ASSERT_EQ(3u, message_center()->NotificationCount());
// Now we remove the remaining notifications.
message_center()->RemoveNotificationsForNotifierId(
- NotifierId(NotifierId::APPLICATION, "app1"));
+ NotifierId(NotifierType::APPLICATION, "app1"));
ASSERT_EQ(0u, message_center()->NotificationCount());
}
TEST_F(MessageCenterImplTest, UpdateWhileMessageCenterVisible) {
std::string id1("id1");
std::string id2("id2");
- NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
+ NotifierId notifier_id1(NotifierType::APPLICATION, "app1");
// First, add and update a notification to ensure updates happen
// normally.
diff --git a/chromium/ui/message_center/message_center_stats_collector.cc b/chromium/ui/message_center/message_center_stats_collector.cc
index 4f3faa699ad..ac1be55a795 100644
--- a/chromium/ui/message_center/message_center_stats_collector.cc
+++ b/chromium/ui/message_center/message_center_stats_collector.cc
@@ -47,6 +47,10 @@ void MessageCenterStatsCollector::NotificationStats::RecordAggregateStats() {
}
}
+void MessageCenterStatsCollector::RecordNotifierType(NotifierType type) {
+ UMA_HISTOGRAM_ENUMERATION("Notifications.NotifierType", type);
+}
+
MessageCenterStatsCollector::MessageCenterStatsCollector(
MessageCenter* message_center)
: message_center_(message_center) {
@@ -65,6 +69,11 @@ void MessageCenterStatsCollector::OnNotificationAdded(
DCHECK(iter != stats_.end());
stats_[notification_id].CollectAction(NOTIFICATION_ACTION_ADD);
+
+ const auto* notification =
+ message_center_->FindVisibleNotificationById(notification_id);
+ if (notification)
+ RecordNotifierType(notification->notifier_id().type);
}
void MessageCenterStatsCollector::OnNotificationRemoved(
diff --git a/chromium/ui/message_center/message_center_stats_collector.h b/chromium/ui/message_center/message_center_stats_collector.h
index c2e212c3111..3770c703268 100644
--- a/chromium/ui/message_center/message_center_stats_collector.h
+++ b/chromium/ui/message_center/message_center_stats_collector.h
@@ -12,6 +12,7 @@
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/message_center_types.h"
+#include "ui/message_center/public/cpp/notifier_id.h"
namespace message_center {
@@ -61,6 +62,9 @@ class MessageCenterStatsCollector : public MessageCenterObserver {
bool actions_[NOTIFICATION_ACTION_COUNT];
};
+ // Sends notifier type to UMA. Called when a notification is added.
+ void RecordNotifierType(NotifierType type);
+
// MessageCenterObserver
void OnNotificationAdded(const std::string& notification_id) override;
void OnNotificationRemoved(const std::string& notification_id,
diff --git a/chromium/ui/message_center/notification_list_unittest.cc b/chromium/ui/message_center/notification_list_unittest.cc
index 71432f104a3..f0818324d84 100644
--- a/chromium/ui/message_center/notification_list_unittest.cc
+++ b/chromium/ui/message_center/notification_list_unittest.cc
@@ -64,7 +64,7 @@ class NotificationListTest : public testing::Test {
UTF8ToUTF16(base::StringPrintf(kTitleFormat, counter_)),
UTF8ToUTF16(base::StringPrintf(kMessageFormat, counter_)), gfx::Image(),
UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), optional_fields,
+ NotifierId(NotifierType::APPLICATION, kExtensionId), optional_fields,
NULL));
return notification;
}
@@ -175,8 +175,8 @@ TEST_F(NotificationListTest, UpdateNotification) {
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), RichNotificationData(),
- NULL));
+ NotifierId(NotifierType::APPLICATION, kExtensionId),
+ RichNotificationData(), NULL));
notification_list_->UpdateNotificationMessage(id0, std::move(notification));
EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_));
const NotificationList::Notifications notifications =
@@ -225,10 +225,10 @@ TEST_F(NotificationListTest, UpdateNotificationWithRenotifyAndQuietMode) {
}
TEST_F(NotificationListTest, GetNotificationsByNotifierId) {
- NotifierId id0(NotifierId::APPLICATION, "ext0");
- NotifierId id1(NotifierId::APPLICATION, "ext1");
+ NotifierId id0(NotifierType::APPLICATION, "ext0");
+ NotifierId id1(NotifierType::APPLICATION, "ext1");
NotifierId id2(GURL("http://example.com"));
- NotifierId id3(NotifierId::SYSTEM_COMPONENT, "system-notifier");
+ NotifierId id3(NotifierType::SYSTEM_COMPONENT, "system-notifier");
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, "id0", UTF8ToUTF16("title0"),
UTF8ToUTF16("message0"), gfx::Image(), UTF8ToUTF16("source0"), GURL(),
@@ -366,7 +366,7 @@ TEST_F(NotificationListTest, GetNotificationsByAppId) {
std::unique_ptr<Notification> notification(
new Notification(NOTIFICATION_TYPE_PROGRESS, id1, UTF8ToUTF16("updated"),
UTF8ToUTF16("updated"), gfx::Image(), base::string16(),
- GURL(), NotifierId(NotifierId::APPLICATION, app_id1),
+ GURL(), NotifierId(NotifierType::APPLICATION, app_id1),
RichNotificationData(), NULL));
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(1u, notification_list_->GetNotificationsByAppId(app_id1).size());
@@ -387,7 +387,7 @@ TEST_F(NotificationListTest, GetNotificationsByAppId) {
notification.reset(
new Notification(NOTIFICATION_TYPE_PROGRESS, id1, UTF8ToUTF16("updated"),
UTF8ToUTF16("updated"), gfx::Image(), base::string16(),
- GURL(), NotifierId(NotifierId::APPLICATION, app_id1),
+ GURL(), NotifierId(NotifierType::APPLICATION, app_id1),
RichNotificationData(), NULL));
notification_list_->AddNotification(std::move(notification));
@@ -395,7 +395,7 @@ TEST_F(NotificationListTest, GetNotificationsByAppId) {
notification.reset(
new Notification(NOTIFICATION_TYPE_PROGRESS, id2, UTF8ToUTF16("updated"),
UTF8ToUTF16("updated"), gfx::Image(), base::string16(),
- GURL(), NotifierId(NotifierId::APPLICATION, app_id1),
+ GURL(), NotifierId(NotifierType::APPLICATION, app_id1),
RichNotificationData(), NULL));
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(2u, notification_list_->GetNotificationsByAppId(app_id1).size());
@@ -405,7 +405,7 @@ TEST_F(NotificationListTest, GetNotificationsByAppId) {
notification.reset(
new Notification(NOTIFICATION_TYPE_PROGRESS, id3, UTF8ToUTF16("updated"),
UTF8ToUTF16("updated"), gfx::Image(), base::string16(),
- GURL(), NotifierId(NotifierId::APPLICATION, app_id2),
+ GURL(), NotifierId(NotifierType::APPLICATION, app_id2),
RichNotificationData(), NULL));
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(2u, notification_list_->GetNotificationsByAppId(app_id1).size());
@@ -466,7 +466,7 @@ TEST_F(NotificationListTest, UpdateWithoutMessageCenterView) {
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource),
- GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), optional,
+ GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), optional,
NULL));
notification_list_->UpdateNotificationMessage(id0, std::move(notification));
EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_));
@@ -497,7 +497,7 @@ TEST_F(NotificationListTest, Renotify) {
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), optional, NULL));
+ NotifierId(NotifierType::APPLICATION, kExtensionId), optional, NULL));
notification_list_->UpdateNotificationMessage(id0, std::move(notification));
EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_));
EXPECT_EQ(1u, GetPopupCounts());
@@ -521,7 +521,7 @@ TEST_F(NotificationListTest, PriorityAndRenotify) {
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL));
+ NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL));
notification_list_->UpdateNotificationMessage(id0, std::move(notification));
EXPECT_EQ(1u, GetPopupCounts());
notification_list_->MarkSinglePopupAsShown(id0, true);
@@ -531,7 +531,7 @@ TEST_F(NotificationListTest, PriorityAndRenotify) {
notification.reset(new Notification(
NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle2"),
UTF8ToUTF16("newbody2"), gfx::Image(), UTF8ToUTF16(kDisplaySource),
- GURL(), NotifierId(NotifierId::APPLICATION, kExtensionId), priority,
+ GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), priority,
NULL));
notification_list_->UpdateNotificationMessage(id0, std::move(notification));
EXPECT_EQ(0u, GetPopupCounts());
@@ -541,7 +541,7 @@ TEST_F(NotificationListTest, PriorityAndRenotify) {
notification.reset(new Notification(
NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL));
+ NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL));
notification_list_->UpdateNotificationMessage(id1, std::move(notification));
EXPECT_EQ(0u, GetPopupCounts());
@@ -550,7 +550,7 @@ TEST_F(NotificationListTest, PriorityAndRenotify) {
notification.reset(new Notification(
NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), priority, NULL));
+ NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL));
notification_list_->UpdateNotificationMessage(id1, std::move(notification));
EXPECT_EQ(1u, GetPopupCounts());
notification_list_->MarkSinglePopupAsShown(id1, true);
@@ -650,8 +650,8 @@ TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) {
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"),
UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(),
- NotifierId(NotifierId::APPLICATION, kExtensionId), RichNotificationData(),
- NULL));
+ NotifierId(NotifierType::APPLICATION, kExtensionId),
+ RichNotificationData(), NULL));
notification_list_->UpdateNotificationMessage(id1, std::move(notification));
Notification* n1 = GetNotification(id1);
EXPECT_TRUE(n1 == NULL);
diff --git a/chromium/ui/message_center/popup_timers_controller.cc b/chromium/ui/message_center/popup_timers_controller.cc
index 0c5eeadf3fd..8fa599372b5 100644
--- a/chromium/ui/message_center/popup_timers_controller.cc
+++ b/chromium/ui/message_center/popup_timers_controller.cc
@@ -22,7 +22,7 @@ base::TimeDelta GetTimeoutForNotification(Notification* notification) {
#else
const bool use_high_priority_delay =
notification->priority() > DEFAULT_PRIORITY ||
- notification->notifier_id().type == NotifierId::WEB_PAGE;
+ notification->notifier_id().type == NotifierType::WEB_PAGE;
#endif
if (use_high_priority_delay)
diff --git a/chromium/ui/message_center/public/cpp/message_center_constants.h b/chromium/ui/message_center/public/cpp/message_center_constants.h
index 6af58c7ec30..0bce5eea640 100644
--- a/chromium/ui/message_center/public/cpp/message_center_constants.h
+++ b/chromium/ui/message_center/public/cpp/message_center_constants.h
@@ -82,11 +82,6 @@ constexpr SkColor kSmallImageMaskBackgroundColor =
constexpr SkColor kControlButtonBackgroundColor =
SkColorSetA(SK_ColorWHITE, 0.9 * 0xff);
-// Accent colors of system notifications.
-constexpr SkColor kSystemNotificationColorNormal = gfx::kGoogleBlue700;
-constexpr SkColor kSystemNotificationColorWarning = gfx::kGoogleYellow900;
-constexpr SkColor kSystemNotificationColorCriticalWarning = gfx::kGoogleRed700;
-
// Default accent color of notifications that are not generated by system.
constexpr SkColor kNotificationDefaultAccentColor = gfx::kChromeIconGrey;
@@ -142,14 +137,6 @@ constexpr int kMarginBetweenPopups = 10;
// The corners are only rounded in Chrome OS.
constexpr int kNotificationCornerRadius = 2;
-// Layout parameters for swipe control of notifications in message center.
-constexpr int kSwipeControlButtonImageSize = 20;
-constexpr int kSwipeControlButtonSize = 36;
-constexpr int kSwipeControlButtonVerticalMargin = 24;
-constexpr int kSwipeControlButtonHorizontalMargin = 8;
-constexpr SkColor kSwipeControlBackgroundColor =
- SkColorSetRGB(0xee, 0xee, 0xee);
-
// Close if notification is slided more than this amount in addition to the
// width of the buttons and their margins.
constexpr int kSwipeCloseMargin = 64;
diff --git a/chromium/ui/message_center/public/cpp/notification.cc b/chromium/ui/message_center/public/cpp/notification.cc
index d444352c1d3..25fe154b736 100644
--- a/chromium/ui/message_center/public/cpp/notification.cc
+++ b/chromium/ui/message_center/public/cpp/notification.cc
@@ -38,7 +38,8 @@ const gfx::ImageSkia CreateSolidColorImage(int width,
gfx::Image DeepCopyImage(const gfx::Image& image) {
if (image.IsEmpty())
return gfx::Image();
- std::unique_ptr<gfx::ImageSkia> image_skia(image.CopyImageSkia());
+ std::unique_ptr<gfx::ImageSkia> image_skia(
+ new gfx::ImageSkia(*image.ToImageSkia()));
return gfx::Image(*image_skia);
}
@@ -156,60 +157,6 @@ gfx::Image Notification::GenerateMaskedSmallIcon(int dip_size,
}
// static
-std::unique_ptr<Notification> Notification::CreateSystemNotification(
- const std::string& notification_id,
- const base::string16& title,
- const base::string16& message,
- const std::string& system_component_id,
- const base::RepeatingClosure& click_callback) {
- DCHECK(!click_callback.is_null());
- std::unique_ptr<Notification> notification = CreateSystemNotification(
- NOTIFICATION_TYPE_SIMPLE, notification_id, title, message,
- base::string16() /* display_source */, GURL(),
- NotifierId(NotifierId::SYSTEM_COMPONENT, system_component_id),
- RichNotificationData(),
- new HandleNotificationClickDelegate(click_callback), gfx::kNoneIcon,
- SystemNotificationWarningLevel::CRITICAL_WARNING);
- notification->SetSystemPriority();
- return notification;
-}
-
-// static
-std::unique_ptr<Notification> Notification::CreateSystemNotification(
- NotificationType type,
- const std::string& id,
- const base::string16& title,
- const base::string16& message,
- const base::string16& display_source,
- const GURL& origin_url,
- const NotifierId& notifier_id,
- const RichNotificationData& optional_fields,
- scoped_refptr<NotificationDelegate> delegate,
- const gfx::VectorIcon& small_image,
- SystemNotificationWarningLevel color_type) {
- DCHECK_EQ(NotifierId::SYSTEM_COMPONENT, notifier_id.type);
- SkColor color = kSystemNotificationColorNormal;
- switch (color_type) {
- case SystemNotificationWarningLevel::NORMAL:
- color = kSystemNotificationColorNormal;
- break;
- case SystemNotificationWarningLevel::WARNING:
- color = kSystemNotificationColorWarning;
- break;
- case SystemNotificationWarningLevel::CRITICAL_WARNING:
- color = kSystemNotificationColorCriticalWarning;
- break;
- }
- std::unique_ptr<Notification> notification = std::make_unique<Notification>(
- type, id, title, message, gfx::Image(), display_source, origin_url,
- notifier_id, optional_fields, delegate);
- notification->set_accent_color(color);
- if (!small_image.is_empty())
- notification->set_vector_small_image(small_image);
- return notification;
-}
-
-// static
void RegisterVectorIcons(
const std::vector<const gfx::VectorIcon*>& vector_icons) {
for (const gfx::VectorIcon* icon : vector_icons) {
diff --git a/chromium/ui/message_center/public/cpp/notification.h b/chromium/ui/message_center/public/cpp/notification.h
index 0b04be65c6a..7ec1310f2c8 100644
--- a/chromium/ui/message_center/public/cpp/notification.h
+++ b/chromium/ui/message_center/public/cpp/notification.h
@@ -169,7 +169,7 @@ class MESSAGE_CENTER_PUBLIC_EXPORT RichNotificationData {
// Unified theme color used in new style notification.
// Usually, it should not be set directly.
- // For system notification, CreateSystemNotification with
+ // For system notification, ash::CreateSystemNotification with
// SystemNotificationWarningLevel should be used.
SkColor accent_color = SK_ColorTRANSPARENT;
@@ -430,39 +430,11 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// method explicitly, to avoid setting it accidentally.
void SetSystemPriority();
- // Helper method to create a simple system notification. |click_callback|
- // will be invoked when the notification is clicked.
- //
- // It should only be used for critical notification, as SetSystemPriority and
- // CRITICAL_WARNING color are set inside, which means the notification would
- // not go away without user interaction.
- //
- // TODO(tetsui): Add a function parameter |small_image| of gfx::VectorIcon, so
- // display source of critical system notification is illustrated by icon.
- static std::unique_ptr<Notification> CreateSystemNotification(
- const std::string& notification_id,
- const base::string16& title,
- const base::string16& message,
- const std::string& system_component_id,
- const base::RepeatingClosure& click_callback);
-
- // Factory method to create all kinds of notifications generated by system,
- // from normal priority ones to critical priority ones.
- // |small_image| is a small icon show on the upper left header to illustrate
- // |display_source| of the notification.
- // One specified in the |optional_fields| is overridden.
- static std::unique_ptr<Notification> CreateSystemNotification(
- NotificationType type,
- const std::string& id,
- const base::string16& title,
- const base::string16& message,
- const base::string16& display_source,
- const GURL& origin_url,
- const NotifierId& notifier_id,
- const RichNotificationData& optional_fields,
- scoped_refptr<NotificationDelegate> delegate,
- const gfx::VectorIcon& small_image,
- SystemNotificationWarningLevel color_type);
+ const std::string& custom_view_type() const { return custom_view_type_; }
+ void set_custom_view_type(const std::string& custom_view_type) {
+ DCHECK_EQ(type(), NotificationType::NOTIFICATION_TYPE_CUSTOM);
+ custom_view_type_ = custom_view_type;
+ }
protected:
// The type of notification we'd like displayed.
@@ -497,6 +469,11 @@ class MESSAGE_CENTER_PUBLIC_EXPORT Notification {
// A proxy object that allows access back to the JavaScript object that
// represents the notification, for firing events.
scoped_refptr<NotificationDelegate> delegate_;
+
+ // For custom notifications this determines which factory will be used for
+ // creating the view for this notification. The type should match the type
+ // used to register the factory in MessageViewFactory.
+ std::string custom_view_type_;
};
// Registering a vector icon allows it to later be looked up by name. This is
diff --git a/chromium/ui/message_center/public/cpp/notifier_id.cc b/chromium/ui/message_center/public/cpp/notifier_id.cc
index c25aaeb47b1..3549b9ae81e 100644
--- a/chromium/ui/message_center/public/cpp/notifier_id.cc
+++ b/chromium/ui/message_center/public/cpp/notifier_id.cc
@@ -8,15 +8,16 @@
namespace message_center {
-NotifierId::NotifierId() : type(SYSTEM_COMPONENT) {}
+NotifierId::NotifierId() : type(NotifierType::SYSTEM_COMPONENT) {}
NotifierId::NotifierId(NotifierType type, const std::string& id)
: type(type), id(id) {
- DCHECK(type != WEB_PAGE);
+ DCHECK(type != NotifierType::WEB_PAGE);
DCHECK(!id.empty());
}
-NotifierId::NotifierId(const GURL& url) : type(WEB_PAGE), url(url) {}
+NotifierId::NotifierId(const GURL& url)
+ : type(NotifierType::WEB_PAGE), url(url) {}
NotifierId::NotifierId(const NotifierId& other) = default;
@@ -27,7 +28,7 @@ bool NotifierId::operator==(const NotifierId& other) const {
if (profile_id != other.profile_id)
return false;
- if (type == WEB_PAGE)
+ if (type == NotifierType::WEB_PAGE)
return url == other.url;
return id == other.id;
@@ -40,7 +41,7 @@ bool NotifierId::operator<(const NotifierId& other) const {
if (profile_id != other.profile_id)
return profile_id < other.profile_id;
- if (type == WEB_PAGE)
+ if (type == NotifierType::WEB_PAGE)
return url < other.url;
return id < other.id;
diff --git a/chromium/ui/message_center/public/cpp/notifier_id.h b/chromium/ui/message_center/public/cpp/notifier_id.h
index 720d3a74655..eae94adc415 100644
--- a/chromium/ui/message_center/public/cpp/notifier_id.h
+++ b/chromium/ui/message_center/public/cpp/notifier_id.h
@@ -18,19 +18,20 @@
namespace message_center {
-// A struct that identifies the source of notifications. For example, a web page
-// might send multiple notifications but they'd all have the same NotifierId.
-struct MESSAGE_CENTER_PUBLIC_EXPORT NotifierId {
// This enum is being used for histogram reporting and the elements should not
// be re-ordered.
- enum NotifierType : int {
- APPLICATION = 0,
- ARC_APPLICATION = 1,
- WEB_PAGE = 2,
- SYSTEM_COMPONENT = 3,
- SIZE,
- };
+enum class NotifierType : int {
+ APPLICATION = 0,
+ ARC_APPLICATION = 1,
+ WEB_PAGE = 2,
+ SYSTEM_COMPONENT = 3,
+ CROSTINI_APPLICATION = 4,
+ kMaxValue = CROSTINI_APPLICATION,
+};
+// A struct that identifies the source of notifications. For example, a web page
+// might send multiple notifications but they'd all have the same NotifierId.
+struct MESSAGE_CENTER_PUBLIC_EXPORT NotifierId {
// Default constructor needed for generated mojom files and tests.
NotifierId();
diff --git a/chromium/ui/message_center/public/mojo/notification.mojom b/chromium/ui/message_center/public/mojo/notification.mojom
index 5edb43011bf..eb7fba8b453 100644
--- a/chromium/ui/message_center/public/mojo/notification.mojom
+++ b/chromium/ui/message_center/public/mojo/notification.mojom
@@ -89,4 +89,5 @@ struct Notification {
// |shown_as_popup_| intentionally omitted.
// |is_read_| intentionally omitted.
// |delegate_| intentionally omitted.
+ // |custom_view_type_| intentionally omitted.
};
diff --git a/chromium/ui/message_center/public/mojo/notifier_id.mojom b/chromium/ui/message_center/public/mojo/notifier_id.mojom
index 0227ad3f250..9c2f3133fe7 100644
--- a/chromium/ui/message_center/public/mojo/notifier_id.mojom
+++ b/chromium/ui/message_center/public/mojo/notifier_id.mojom
@@ -7,14 +7,14 @@ module message_center.mojom;
import "mojo/public/mojom/base/string16.mojom";
import "url/mojom/url.mojom";
-// Equivalent to message_center::NotifierId::NotifierType. Used in UMA, so it
+// Equivalent to message_center::NotifierType. Used in UMA, so it
// should not be reordered.
enum NotifierType {
APPLICATION = 0,
ARC_APPLICATION = 1,
WEB_PAGE = 2,
SYSTEM_COMPONENT = 3,
- SIZE,
+ CROSTINI_APPLICATION = 4,
};
// Equivalent to message_center::NotifierId.
diff --git a/chromium/ui/message_center/public/mojo/notifier_id.typemap b/chromium/ui/message_center/public/mojo/notifier_id.typemap
index 743319ce232..d6a2ff42b98 100644
--- a/chromium/ui/message_center/public/mojo/notifier_id.typemap
+++ b/chromium/ui/message_center/public/mojo/notifier_id.typemap
@@ -11,5 +11,5 @@ deps = [
]
type_mappings = [
"message_center.mojom.NotifierId=message_center::NotifierId",
- "message_center.mojom.NotifierType=message_center::NotifierId::NotifierType",
+ "message_center.mojom.NotifierType=message_center::NotifierType",
]
diff --git a/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc
index 016424fedc8..cbdcff36bae 100644
--- a/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc
+++ b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.cc
@@ -12,7 +12,7 @@ using NotifierIdStructTraits =
message_center::NotifierId>;
// static
-const message_center::NotifierId::NotifierType& NotifierIdStructTraits::type(
+message_center::NotifierType NotifierIdStructTraits::type(
const message_center::NotifierId& n) {
return n.type;
}
diff --git a/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h
index fefc0d91f17..ba7007f2f1c 100644
--- a/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h
+++ b/chromium/ui/message_center/public/mojo/notifier_id_struct_traits.h
@@ -12,42 +12,43 @@ namespace mojo {
template <>
struct EnumTraits<message_center::mojom::NotifierType,
- message_center::NotifierId::NotifierType> {
+ message_center::NotifierType> {
static message_center::mojom::NotifierType ToMojom(
- message_center::NotifierId::NotifierType input) {
+ message_center::NotifierType input) {
switch (input) {
- case message_center::NotifierId::APPLICATION:
+ case message_center::NotifierType::APPLICATION:
return message_center::mojom::NotifierType::APPLICATION;
- case message_center::NotifierId::ARC_APPLICATION:
+ case message_center::NotifierType::ARC_APPLICATION:
return message_center::mojom::NotifierType::ARC_APPLICATION;
- case message_center::NotifierId::WEB_PAGE:
+ case message_center::NotifierType::WEB_PAGE:
return message_center::mojom::NotifierType::WEB_PAGE;
- case message_center::NotifierId::SYSTEM_COMPONENT:
+ case message_center::NotifierType::SYSTEM_COMPONENT:
return message_center::mojom::NotifierType::SYSTEM_COMPONENT;
- case message_center::NotifierId::SIZE:
- break;
+ case message_center::NotifierType::CROSTINI_APPLICATION:
+ return message_center::mojom::NotifierType::CROSTINI_APPLICATION;
}
NOTREACHED();
- return message_center::mojom::NotifierType::SIZE;
+ return message_center::mojom::NotifierType::APPLICATION;
}
static bool FromMojom(message_center::mojom::NotifierType input,
- message_center::NotifierId::NotifierType* out) {
+ message_center::NotifierType* out) {
switch (input) {
case message_center::mojom::NotifierType::APPLICATION:
- *out = message_center::NotifierId::APPLICATION;
+ *out = message_center::NotifierType::APPLICATION;
return true;
case message_center::mojom::NotifierType::ARC_APPLICATION:
- *out = message_center::NotifierId::ARC_APPLICATION;
+ *out = message_center::NotifierType::ARC_APPLICATION;
return true;
case message_center::mojom::NotifierType::WEB_PAGE:
- *out = message_center::NotifierId::WEB_PAGE;
+ *out = message_center::NotifierType::WEB_PAGE;
return true;
case message_center::mojom::NotifierType::SYSTEM_COMPONENT:
- *out = message_center::NotifierId::SYSTEM_COMPONENT;
+ *out = message_center::NotifierType::SYSTEM_COMPONENT;
+ return true;
+ case message_center::mojom::NotifierType::CROSTINI_APPLICATION:
+ *out = message_center::NotifierType::CROSTINI_APPLICATION;
return true;
- case message_center::mojom::NotifierType::SIZE:
- break;
}
NOTREACHED();
return false;
@@ -57,8 +58,7 @@ struct EnumTraits<message_center::mojom::NotifierType,
template <>
struct StructTraits<message_center::mojom::NotifierIdDataView,
message_center::NotifierId> {
- static const message_center::NotifierId::NotifierType& type(
- const message_center::NotifierId& n);
+ static message_center::NotifierType type(const message_center::NotifierId& n);
static const std::string& id(const message_center::NotifierId& n);
static const GURL& url(const message_center::NotifierId& n);
static const std::string& profile_id(const message_center::NotifierId& n);
diff --git a/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc b/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc
index faefc694c95..138444f48c9 100644
--- a/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc
+++ b/chromium/ui/message_center/public/mojo/struct_traits_unittest.cc
@@ -81,7 +81,7 @@ TEST_F(StructTraitsTest, Notification) {
gfx::Image icon(gfx::test::CreateImage(64, 64));
base::string16 display_source(base::ASCIIToUTF16("display_source"));
GURL origin_url("www.example.com");
- NotifierId notifier_id(NotifierId::NotifierType::APPLICATION, id);
+ NotifierId notifier_id(NotifierType::APPLICATION, id);
notifier_id.profile_id = "profile_id";
RichNotificationData optional_fields;
optional_fields.settings_button_handler = SettingsButtonHandler::INLINE;
@@ -114,7 +114,7 @@ TEST_F(StructTraitsTest, EmptyIconNotification) {
base::ASCIIToUTF16("I'm a notification with no icon!"));
base::string16 display_source(base::ASCIIToUTF16("display_source"));
GURL origin_url("www.example.com");
- NotifierId notifier_id(NotifierId::NotifierType::APPLICATION, id);
+ NotifierId notifier_id(NotifierType::APPLICATION, id);
Notification input(type, id, title, message, gfx::Image(), display_source,
origin_url, notifier_id, RichNotificationData(), nullptr);
mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
diff --git a/chromium/ui/message_center/views/bounded_label.cc b/chromium/ui/message_center/views/bounded_label.cc
index 01ad8a33463..086e97743d9 100644
--- a/chromium/ui/message_center/views/bounded_label.cc
+++ b/chromium/ui/message_center/views/bounded_label.cc
@@ -199,7 +199,7 @@ void InnerBoundedLabel::SetText(const base::string16& new_text) {
}
int InnerBoundedLabel::GetTextFlags() {
- int flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::CHARACTER_BREAK;
+ int flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::CHARACTER_BREAKABLE;
// We can't use subpixel rendering if the background is non-opaque.
if (SkColorGetA(background_color()) != 0xFF)
@@ -303,6 +303,10 @@ int BoundedLabel::GetLineLimit() const {
return line_limit_;
}
+const gfx::FontList& BoundedLabel::font_list() const {
+ return label_->font_list();
+}
+
int BoundedLabel::GetLinesForWidthAndLimit(int width, int limit) {
return visible() ? label_->GetLinesForWidthAndLimit(width, limit) : 0;
}
diff --git a/chromium/ui/message_center/views/bounded_label.h b/chromium/ui/message_center/views/bounded_label.h
index ff7aa7a4228..095c0db53e1 100644
--- a/chromium/ui/message_center/views/bounded_label.h
+++ b/chromium/ui/message_center/views/bounded_label.h
@@ -47,6 +47,9 @@ class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View {
int GetLineHeight() const;
int GetLineLimit() const;
+ // Gets the FontList used by this label.
+ const gfx::FontList& font_list() const;
+
// Pass in a -1 width to use the preferred width, a -1 limit to skip limits.
int GetLinesForWidthAndLimit(int width, int limit);
gfx::Size GetSizeForWidthAndLines(int width, int lines);
diff --git a/chromium/ui/message_center/views/bounded_label_unittest.cc b/chromium/ui/message_center/views/bounded_label_unittest.cc
index bcdae9157d4..45e45608111 100644
--- a/chromium/ui/message_center/views/bounded_label_unittest.cc
+++ b/chromium/ui/message_center/views/bounded_label_unittest.cc
@@ -8,12 +8,17 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
#include "ui/views/controls/label.h"
#include "ui/views/test/views_test_base.h"
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+
namespace message_center {
namespace test {
@@ -101,6 +106,13 @@ class BoundedLabelTest : public views::ViewsTestBase {
/* Elision tests **************************************************************/
TEST_F(BoundedLabelTest, GetWrappedTextTest) {
+#if defined(OS_MACOSX)
+ // Skip this test on macOS 10.10, which has slightly different font metrics
+ // than the other OSes we support.
+ if (base::mac::IsOS10_10())
+ return;
+#endif
+
// One word per line: No ellision should be made when not necessary.
TEST_WRAP("123", "123", 301, 1);
TEST_WRAP("123", "123", 301, 2);
@@ -110,9 +122,9 @@ TEST_F(BoundedLabelTest, GetWrappedTextTest) {
TEST_WRAP("123\n456\n789", "123 456 789", 301, 3);
// One word per line: Ellisions should be made when necessary.
- TEST_WRAP("123...", "123 456", 301, 1);
- TEST_WRAP("123...", "123 456 789", 301, 1);
- TEST_WRAP("123\n456...", "123 456 789", 301, 2);
+ TEST_WRAP("123...", "123 456", 302, 1);
+ TEST_WRAP("123...", "123 456 789", 302, 1);
+ TEST_WRAP("123\n456...", "123 456 789", 302, 2);
// Two words per line: No ellision should be made when not necessary.
TEST_WRAP("123 456", "123 456", 621, 1);
diff --git a/chromium/ui/message_center/views/message_popup_collection.cc b/chromium/ui/message_center/views/message_popup_collection.cc
index e0c7dd335bc..e6d93b9d4f2 100644
--- a/chromium/ui/message_center/views/message_popup_collection.cc
+++ b/chromium/ui/message_center/views/message_popup_collection.cc
@@ -47,6 +47,11 @@ void MessagePopupCollection::Update() {
RemoveClosedPopupItems();
+ if (MessageCenter::Get()->IsMessageCenterVisible()) {
+ CloseAllPopupsNow();
+ return;
+ }
+
if (animation_->is_animating()) {
UpdateByAnimation();
return;
@@ -62,7 +67,8 @@ void MessagePopupCollection::Update() {
if (state_ != State::IDLE) {
// If not in IDLE state, start animation.
- animation_->SetDuration(state_ == State::MOVE_DOWN
+ animation_->SetDuration(state_ == State::MOVE_DOWN ||
+ state_ == State::MOVE_UP_FOR_INVERSE
? kMoveDownDuration
: kFadeInFadeOutDuration);
animation_->Start();
@@ -72,31 +78,6 @@ void MessagePopupCollection::Update() {
DCHECK(state_ == State::IDLE || animation_->is_animating());
}
-void MessagePopupCollection::MarkAllPopupsShown(bool animate) {
- if (is_updating_)
- return;
- {
- base::AutoReset<bool> reset(&is_updating_, true);
-
- for (const auto& item : popup_items_)
- MessageCenter::Get()->MarkSinglePopupAsShown(item.id, false);
-
- ResetHotMode();
- state_ = State::IDLE;
- animation_->End();
- }
-
- if (animate) {
- // Restart animation for FADE_OUT.
- Update();
- } else {
- // Mark "animating" the popups which is marked as shown.
- MarkRemovedPopup();
- // Remove the animating-marked popups immwdiately without animation.
- CloseAnimatingPopups();
- }
-}
-
void MessagePopupCollection::ResetBounds() {
if (is_updating_)
return;
@@ -189,6 +170,11 @@ void MessagePopupCollection::OnCenterVisibilityChanged(Visibility visibility) {
Update();
}
+void MessagePopupCollection::OnBlockingStateChanged(
+ NotificationBlocker* blocker) {
+ Update();
+}
+
void MessagePopupCollection::AnimationEnded(const gfx::Animation* animation) {
Update();
}
@@ -236,16 +222,22 @@ void MessagePopupCollection::TransitionFromAnimation() {
// If the animation is finished, transition to IDLE.
state_ = State::IDLE;
} else if (state_ == State::FADE_OUT && !popup_items_.empty()) {
- // If FADE_OUT animation is finished and we still have remaining popups,
- // we have to MOVE_DOWN them.
- state_ = State::MOVE_DOWN;
-
- // If we're going to add a new popup after this MOVE_DOWN, do the collapse
- // animation at the same time. Otherwise it will take another MOVE_DOWN.
- if (HasAddedPopup())
- CollapseAllPopups();
-
- MoveDownPopups();
+ if ((HasAddedPopup() && CollapseAllPopups()) || !inverse_) {
+ // If FADE_OUT animation is finished and we still have remaining popups,
+ // we have to MOVE_DOWN them.
+ // If we're going to add a new popup after this MOVE_DOWN, do the collapse
+ // animation at the same time. Otherwise it will take another MOVE_DOWN.
+ state_ = State::MOVE_DOWN;
+ MoveDownPopups();
+ } else {
+ // If there's no collapsable popups and |inverse_| is on, there's nothing
+ // to do after FADE_OUT.
+ state_ = State::IDLE;
+ }
+ } else if (state_ == State::MOVE_UP_FOR_INVERSE) {
+ for (auto& item : popup_items_)
+ item.is_animating = item.will_fade_in;
+ state_ = State::FADE_IN;
}
}
@@ -277,8 +269,16 @@ void MessagePopupCollection::TransitionToAnimation() {
MoveDownPopups();
return;
} else if (AddPopup()) {
- // If a popup is actually added, show FADE_IN animation.
- state_ = State::FADE_IN;
+ // A popup is actually added.
+ if (inverse_ && popup_items_.size() > 1) {
+ // If |inverse_| is on and there are existing notifications that have to
+ // be moved up (existing ones + new one, so > 1), transition to
+ // MOVE_UP_FOR_INVERSE.
+ state_ = State::MOVE_UP_FOR_INVERSE;
+ } else {
+ // Show FADE_IN animation.
+ state_ = State::FADE_IN;
+ }
return;
}
}
@@ -320,7 +320,7 @@ void MessagePopupCollection::CalculateBounds() {
for (size_t i = 0; i < popup_items_.size(); ++i) {
gfx::Size preferred_size(
kNotificationWidth,
- popup_items_[i].popup->GetHeightForWidth(kNotificationWidth));
+ GetPopupItem(i)->popup->GetHeightForWidth(kNotificationWidth));
// Align the top of i-th popup to |hot_top_|.
if (is_hot_ && hot_index_ == i) {
@@ -336,8 +336,8 @@ void MessagePopupCollection::CalculateBounds() {
if (!alignment_delegate_->IsTopDown())
origin_y -= preferred_size.height();
- popup_items_[i].start_bounds = popup_items_[i].bounds;
- popup_items_[i].bounds =
+ GetPopupItem(i)->start_bounds = GetPopupItem(i)->bounds;
+ GetPopupItem(i)->bounds =
gfx::Rect(gfx::Point(origin_x, origin_y), preferred_size);
const int delta = preferred_size.height() + kMarginBetweenPopups;
@@ -364,7 +364,8 @@ void MessagePopupCollection::UpdateByAnimation() {
else if (state_ == State::FADE_OUT)
item.popup->SetOpacity(gfx::Tween::FloatValueBetween(value, 1.0f, 0.0f));
- if (state_ == State::FADE_IN || state_ == State::MOVE_DOWN) {
+ if (state_ == State::FADE_IN || state_ == State::MOVE_DOWN ||
+ state_ == State::MOVE_UP_FOR_INVERSE) {
item.popup->SetPopupBounds(
gfx::Tween::RectValueBetween(value, item.start_bounds, item.bounds));
}
@@ -399,9 +400,11 @@ bool MessagePopupCollection::AddPopup() {
if (!new_notification)
return false;
- // Reset animation flag of existing popups.
- for (auto& item : popup_items_)
+ // Reset animation flags of existing popups.
+ for (auto& item : popup_items_) {
item.is_animating = false;
+ item.will_fade_in = false;
+ }
{
PopupItem item;
@@ -418,6 +421,15 @@ bool MessagePopupCollection::AddPopup() {
popup_items_.push_back(item);
}
+ // There are existing notifications that have to be moved up (existing ones +
+ // new one, so > 1).
+ if (inverse_ && popup_items_.size() > 1) {
+ for (auto& item : popup_items_) {
+ item.will_fade_in = item.is_animating;
+ item.is_animating = !item.is_animating;
+ }
+ }
+
MessageCenter::Get()->DisplayedNotification(new_notification->id(),
DISPLAY_SOURCE_POPUP);
@@ -431,12 +443,6 @@ bool MessagePopupCollection::AddPopup() {
}
void MessagePopupCollection::MarkRemovedPopup() {
- if (MessageCenter::Get()->IsMessageCenterVisible()) {
- for (auto& item : popup_items_)
- item.is_animating = true;
- return;
- }
-
std::set<std::string> existing_ids;
for (Notification* notification :
MessageCenter::Get()->GetPopupNotifications()) {
@@ -479,10 +485,10 @@ bool MessagePopupCollection::IsNextEdgeOutsideWorkArea(
void MessagePopupCollection::StartHotMode() {
for (size_t i = 0; i < popup_items_.size(); ++i) {
- if (popup_items_[i].is_animating && popup_items_[i].popup->is_hovered()) {
+ if (GetPopupItem(i)->is_animating && GetPopupItem(i)->popup->is_hovered()) {
is_hot_ = true;
hot_index_ = i;
- hot_top_ = popup_items_[i].bounds.y();
+ hot_top_ = GetPopupItem(i)->bounds.y();
break;
}
}
@@ -529,6 +535,16 @@ void MessagePopupCollection::RemoveClosedPopupItems() {
base::EraseIf(popup_items_, [](const auto& item) { return !item.popup; });
}
+void MessagePopupCollection::CloseAllPopupsNow() {
+ for (auto& item : popup_items_)
+ item.is_animating = true;
+ CloseAnimatingPopups();
+
+ ResetHotMode();
+ state_ = State::IDLE;
+ animation_->End();
+}
+
bool MessagePopupCollection::CollapseAllPopups() {
bool changed = false;
for (auto& item : popup_items_) {
@@ -546,9 +562,6 @@ bool MessagePopupCollection::CollapseAllPopups() {
}
bool MessagePopupCollection::HasAddedPopup() const {
- if (MessageCenter::Get()->IsMessageCenterVisible())
- return false;
-
std::set<std::string> existing_ids;
for (const auto& item : popup_items_)
existing_ids.insert(item.id);
@@ -568,9 +581,6 @@ bool MessagePopupCollection::HasRemovedPopup() const {
existing_ids.insert(notification->id());
}
- if (MessageCenter::Get()->IsMessageCenterVisible())
- return !popup_items_.empty();
-
for (const auto& item : popup_items_) {
if (!existing_ids.count(item.id))
return true;
@@ -594,4 +604,11 @@ bool MessagePopupCollection::IsAnyPopupActive() const {
return false;
}
+MessagePopupCollection::PopupItem* MessagePopupCollection::GetPopupItem(
+ size_t index_from_top) {
+ DCHECK_LT(index_from_top, popup_items_.size());
+ return &popup_items_[inverse_ ? popup_items_.size() - index_from_top - 1
+ : index_from_top];
+}
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_popup_collection.h b/chromium/ui/message_center/views/message_popup_collection.h
index 23708b208ec..c9daa1a6c4b 100644
--- a/chromium/ui/message_center/views/message_popup_collection.h
+++ b/chromium/ui/message_center/views/message_popup_collection.h
@@ -34,10 +34,6 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// Update popups based on current |state_|.
void Update();
- // Close all popups. Called from UiController when Notification Center is
- // opened.
- void MarkAllPopupsShown(bool animate);
-
// Reset all popup positions. Called from PopupAlignmentDelegate when
// alignment and work area might be changed.
void ResetBounds();
@@ -54,12 +50,15 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
bool by_user) override;
void OnNotificationUpdated(const std::string& notification_id) override;
void OnCenterVisibilityChanged(Visibility visibility) override;
+ void OnBlockingStateChanged(NotificationBlocker* blocker) override;
// AnimationDelegate:
void AnimationEnded(const gfx::Animation* animation) override;
void AnimationProgressed(const gfx::Animation* animation) override;
void AnimationCanceled(const gfx::Animation* animation) override;
+ void set_inverse() { inverse_ = true; }
+
protected:
// TODO(tetsui): Merge PopupAlignmentDelegate into MessagePopupCollection and
// make subclasses e.g. DesktopMessagePopupCollection and
@@ -91,7 +90,11 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// Moving down notifications. Notification collapsing and resizing are also
// done in MOVE_DOWN.
- MOVE_DOWN
+ MOVE_DOWN,
+
+ // Moving up notifications in order to show new one by FADE_IN. This is only
+ // used when |inverse_| is true.
+ MOVE_UP_FOR_INVERSE
};
// Stores animation related state of a popup.
@@ -107,6 +110,11 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// The final bounds of the popup.
gfx::Rect bounds;
+ // The popup is waiting for MOVE_UP_FOR_INVERSE animation so that it can
+ // FADE_IN after that. The value is only used when the animation type is
+ // MOVE_UP_FOR_INVERSE.
+ bool will_fade_in = false;
+
// If the popup is animating.
bool is_animating = false;
@@ -160,6 +168,9 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
void ClosePopupsOutsideWorkArea();
void RemoveClosedPopupItems();
+ // Stops all the animation and closes all the popups immediately.
+ void CloseAllPopupsNow();
+
// Collapse all existing popups. Return true if size of any popup is actually
// changed.
bool CollapseAllPopups();
@@ -174,6 +185,10 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// Return true if any popup is activated.
bool IsAnyPopupActive() const;
+ // Returns the popup which is visually |index_from_top|-th from the top.
+ // When |inverse_| is false, it's same as popup_items_[i].
+ PopupItem* GetPopupItem(size_t index_from_top);
+
// Animation state. See the comment of State.
State state_ = State::IDLE;
@@ -212,6 +227,16 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection
// |hot_index_| is aligned to |hot_top_|. Only valid if |is_hot_| is true.
int hot_top_ = 0;
+ // Invert ordering of notification popups i.e. showing the latest notification
+ // at the top. It changes the state transition like this:
+ // Normal:
+ // * a new notification comes in: FADE_IN
+ // * a notification comes out: FADE_OUT -> MOVE_DOWN
+ // Inverted:
+ // * a new notification comes in: MOVE_UP_FOR_INVERSE -> FADE_IN
+ // * a notification comes out: FADE_OUT
+ bool inverse_ = false;
+
DISALLOW_COPY_AND_ASSIGN(MessagePopupCollection);
};
diff --git a/chromium/ui/message_center/views/message_popup_collection_unittest.cc b/chromium/ui/message_center/views/message_popup_collection_unittest.cc
index 350deba6b3c..e80a138bc2d 100644
--- a/chromium/ui/message_center/views/message_popup_collection_unittest.cc
+++ b/chromium/ui/message_center/views/message_popup_collection_unittest.cc
@@ -261,9 +261,15 @@ class MessagePopupCollectionTest : public views::ViewsTestBase,
popup_collection_->SetAnimationValue(1.0);
}
- void AnimateToMiddle() { popup_collection_->SetAnimationValue(0.5); }
+ void AnimateToMiddle() {
+ EXPECT_TRUE(popup_collection_->IsAnimating());
+ popup_collection_->SetAnimationValue(0.5);
+ }
- void AnimateToEnd() { popup_collection_->SetAnimationValue(1.0); }
+ void AnimateToEnd() {
+ EXPECT_TRUE(popup_collection_->IsAnimating());
+ popup_collection_->SetAnimationValue(1.0);
+ }
MockMessagePopupView* GetPopup(const std::string& id) {
for (auto* popup : popup_collection_->popups()) {
@@ -377,6 +383,43 @@ TEST_F(MessagePopupCollectionTest, FadeInMultipleNotifications) {
}
}
+TEST_F(MessagePopupCollectionTest, FadeInMultipleNotificationsInverse) {
+ popup_collection()->set_inverse();
+
+ std::vector<std::string> ids;
+ for (size_t i = 0; i < kMaxVisiblePopupNotifications; ++i)
+ ids.push_back(AddNotification());
+
+ for (size_t i = 0; i < ids.size(); ++i) {
+ EXPECT_EQ(ids[i], last_displayed_id());
+ EXPECT_EQ(i + 1, GetPopupCounts());
+ const int before_x = GetPopupAt(i)->GetBoundsInScreen().x();
+ AnimateToMiddle();
+ EXPECT_LT(0.0f, GetPopupAt(i)->GetOpacity());
+ EXPECT_GT(before_x, GetPopupAt(i)->GetBoundsInScreen().x());
+ AnimateToEnd();
+ EXPECT_EQ(1.0f, GetPopupAt(i)->GetOpacity());
+ EXPECT_TRUE(work_area().Contains(GetPopupAt(i)->GetBoundsInScreen()));
+ if (i + 1 < ids.size()) {
+ const int before_y = GetPopupAt(i)->GetBoundsInScreen().y();
+ AnimateToMiddle();
+ EXPECT_GT(before_y, GetPopupAt(i)->GetBoundsInScreen().y());
+ AnimateToEnd();
+ }
+ }
+ EXPECT_FALSE(IsAnimating());
+
+ EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts());
+
+ for (size_t i = 0; i < ids.size(); ++i)
+ EXPECT_EQ(ids[i], GetPopupAt(i)->id());
+
+ for (size_t i = 0; i < ids.size() - 1; ++i) {
+ EXPECT_GT(GetPopupAt(i + 1)->GetBoundsInScreen().x(),
+ GetPopupAt(i)->GetBoundsInScreen().bottom());
+ }
+}
+
TEST_F(MessagePopupCollectionTest, UpdateContents) {
std::string id = AddNotification();
AnimateToEnd();
@@ -406,33 +449,26 @@ TEST_F(MessagePopupCollectionTest, UpdateContentsCausesPopupClose) {
EXPECT_EQ(0u, GetPopupCounts());
}
-TEST_F(MessagePopupCollectionTest, MarkAllPopupsShown) {
+TEST_F(MessagePopupCollectionTest, MessageCenterVisibility) {
+ // It only applies to a platform with MessageCenterView i.e. Chrome OS.
+ MessageCenter::Get()->SetHasMessageCenterView(true);
+
for (size_t i = 0; i < kMaxVisiblePopupNotifications; ++i)
AddNotification();
AnimateUntilIdle();
EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts());
- popup_collection()->MarkAllPopupsShown(true /* animate */);
-
EXPECT_EQ(3u, GetPopupCounts());
- EXPECT_EQ(0u, MessageCenter::Get()->GetPopupNotifications().size());
-
- AnimateUntilIdle();
-
- EXPECT_EQ(0u, GetPopupCounts());
- EXPECT_EQ(0u, MessageCenter::Get()->GetPopupNotifications().size());
-}
-
-TEST_F(MessagePopupCollectionTest, MarkAllPopupsShownWithoutAnimation) {
- for (size_t i = 0; i < kMaxVisiblePopupNotifications; ++i)
- AddNotification();
- AnimateUntilIdle();
-
- EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts());
+ EXPECT_EQ(3u, MessageCenter::Get()->GetPopupNotifications().size());
- popup_collection()->MarkAllPopupsShown(false /* animate */);
+ // The notification should be hidden when MessageCenterView is visible.
+ MessageCenter::Get()->SetVisibility(Visibility::VISIBILITY_MESSAGE_CENTER);
+ // It should not animate in order to show ARC++ notifications properly.
+ EXPECT_FALSE(IsAnimating());
+ MessageCenter::Get()->SetVisibility(Visibility::VISIBILITY_TRANSIENT);
+ EXPECT_FALSE(IsAnimating());
EXPECT_EQ(0u, GetPopupCounts());
EXPECT_EQ(0u, MessageCenter::Get()->GetPopupNotifications().size());
}
@@ -509,6 +545,57 @@ TEST_F(MessagePopupCollectionTest, NotificationsMoveDown) {
EXPECT_FALSE(IsAnimating());
}
+TEST_F(MessagePopupCollectionTest, NotificationsMoveUpForInverse) {
+ popup_collection()->set_inverse();
+
+ std::vector<std::string> ids;
+ for (size_t i = 0; i < kMaxVisiblePopupNotifications + 1; ++i)
+ ids.push_back(AddNotification());
+
+ AnimateUntilIdle();
+
+ EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts());
+ EXPECT_FALSE(IsAnimating());
+
+ gfx::Rect dismissed = GetPopup(ids.front())->GetBoundsInScreen();
+
+ MessageCenter::Get()->MarkSinglePopupAsShown(ids.front(), false);
+ EXPECT_TRUE(IsAnimating());
+
+ // FADE_OUT
+ AnimateToMiddle();
+ EXPECT_GT(1.0f, GetPopup(ids[0])->GetOpacity());
+ EXPECT_EQ(ids[0], GetPopup(ids[0])->id());
+
+ AnimateToEnd();
+ EXPECT_EQ(ids[1], GetPopup(ids[1])->id());
+ EXPECT_TRUE(IsAnimating());
+
+ gfx::Rect before = GetPopup(ids[1])->GetBoundsInScreen();
+
+ // MOVE_UP_FOR_INVERSE
+ AnimateToMiddle();
+ gfx::Rect moving = GetPopup(ids[1])->GetBoundsInScreen();
+ EXPECT_LT(moving.bottom(), before.bottom());
+ EXPECT_LT(dismissed.bottom(), moving.bottom());
+
+ AnimateToEnd();
+ gfx::Rect after = GetPopup(ids[1])->GetBoundsInScreen();
+ EXPECT_EQ(dismissed, after);
+ EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts());
+ EXPECT_TRUE(IsAnimating());
+
+ EXPECT_EQ(0.f, GetPopup(ids.back())->GetOpacity());
+
+ // FADE_IN
+ AnimateToMiddle();
+ EXPECT_LT(0.0f, GetPopup(ids.back())->GetOpacity());
+
+ AnimateToEnd();
+ EXPECT_EQ(1.0f, GetPopup(ids.back())->GetOpacity());
+ EXPECT_FALSE(IsAnimating());
+}
+
TEST_F(MessagePopupCollectionTest, PopupResized) {
std::vector<std::string> ids;
for (size_t i = 0; i < kMaxVisiblePopupNotifications; ++i)
@@ -836,6 +923,38 @@ TEST_F(MessagePopupCollectionTest, DefaultPositioning) {
EXPECT_EQ(r1.x(), r2.x());
}
+TEST_F(MessagePopupCollectionTest, DefaultPositioningInverse) {
+ popup_collection()->set_inverse();
+
+ std::string id0 = AddNotification();
+ std::string id1 = AddNotification();
+ std::string id2 = AddNotification();
+ std::string id3 = AddNotification();
+
+ AnimateUntilIdle();
+
+ // This part is inverted.
+ gfx::Rect r0 = GetPopup(id2)->GetBoundsInScreen();
+ gfx::Rect r1 = GetPopup(id1)->GetBoundsInScreen();
+ gfx::Rect r2 = GetPopup(id0)->GetBoundsInScreen();
+
+ // The 4th toast is not shown yet.
+ EXPECT_FALSE(GetPopup(id3));
+
+ // 3 toasts are shown, equal size, vertical stack.
+ EXPECT_EQ(r0.width(), r1.width());
+ EXPECT_EQ(r1.width(), r2.width());
+
+ EXPECT_EQ(r0.height(), r1.height());
+ EXPECT_EQ(r1.height(), r2.height());
+
+ EXPECT_GT(r0.y(), r1.y());
+ EXPECT_GT(r1.y(), r2.y());
+
+ EXPECT_EQ(r0.x(), r1.x());
+ EXPECT_EQ(r1.x(), r2.x());
+}
+
TEST_F(MessagePopupCollectionTest, DefaultPositioningWithRightTaskbar) {
// If taskbar is on the right we show the toasts bottom to top as usual.
@@ -969,16 +1088,9 @@ TEST_F(MessagePopupCollectionTest, HighPriorityNotificationShownAgain) {
AnimateUntilIdle();
EXPECT_EQ(1u, GetPopupCounts());
- // The notification with system priority should not be dismissed by
- // MarkAllPopupsShown.
- popup_collection()->MarkAllPopupsShown(true /* animate */);
- EXPECT_FALSE(IsAnimating());
- EXPECT_EQ(1u, GetPopupCounts());
-
// The notification should be hidden when MessageCenterView is visible.
MessageCenter::Get()->SetVisibility(Visibility::VISIBILITY_MESSAGE_CENTER);
- EXPECT_TRUE(IsAnimating());
- AnimateUntilIdle();
+ EXPECT_FALSE(IsAnimating());
EXPECT_EQ(0u, GetPopupCounts());
// The notification should be shown again when MessageCenterView is hidden.
diff --git a/chromium/ui/message_center/views/message_popup_view.cc b/chromium/ui/message_center/views/message_popup_view.cc
index ebae9ce9f20..a1def8d7f9d 100644
--- a/chromium/ui/message_center/views/message_popup_view.cc
+++ b/chromium/ui/message_center/views/message_popup_view.cc
@@ -83,11 +83,13 @@ void MessagePopupView::UpdateContents(const Notification& notification) {
}
}
+#if !defined(OS_MACOSX)
float MessagePopupView::GetOpacity() const {
if (!IsWidgetValid())
return 0.f;
return GetWidget()->GetLayer()->opacity();
}
+#endif
void MessagePopupView::SetPopupBounds(const gfx::Rect& bounds) {
if (!IsWidgetValid())
diff --git a/chromium/ui/message_center/views/message_popup_view_mac.mm b/chromium/ui/message_center/views/message_popup_view_mac.mm
new file mode 100644
index 00000000000..17d369ccd90
--- /dev/null
+++ b/chromium/ui/message_center/views/message_popup_view_mac.mm
@@ -0,0 +1,19 @@
+// 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.
+
+#import "ui/message_center/views/message_popup_view.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "ui/views/widget/widget.h"
+
+namespace message_center {
+
+float MessagePopupView::GetOpacity() const {
+ if (!IsWidgetValid())
+ return 0.f;
+ return [GetWidget()->GetNativeWindow().GetNativeNSWindow() alphaValue];
+}
+
+} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc
index a3782fe4bb0..86772103554 100644
--- a/chromium/ui/message_center/views/message_view.cc
+++ b/chromium/ui/message_center/views/message_view.cc
@@ -118,20 +118,12 @@ void MessageView::SetIsNested() {
is_nested_ = true;
// Update enability since it might be changed by "is_nested" flag.
slide_out_controller_.set_slide_mode(CalculateSlideMode());
+ slide_out_controller_.set_update_opacity(false);
SetBorder(views::CreateRoundedRectBorder(
kNotificationBorderThickness, kNotificationCornerRadius, kBorderColor));
-
- auto* control_buttons_view = GetControlButtonsView();
- if (control_buttons_view) {
- int control_button_count =
- (control_buttons_view->settings_button() ? 1 : 0) +
- (control_buttons_view->snooze_button() ? 1 : 0);
- if (control_button_count)
- slide_out_controller_.EnableSwipeControl(control_button_count);
- // TODO(crbug.com/1177464): support updating the swipe control when
- // should_show_setting_buttons is changed after notification creation.
- }
+ if (GetControlButtonsView())
+ GetControlButtonsView()->ShowCloseButton(GetMode() != Mode::PINNED);
}
void MessageView::CloseSwipeControl() {
@@ -324,7 +316,13 @@ ui::Layer* MessageView::GetSlideOutLayer() {
return is_nested_ ? layer() : GetWidget()->GetLayer();
}
-void MessageView::OnSlideChanged() {
+void MessageView::OnSlideStarted() {
+ for (auto* observer : slide_observers_) {
+ observer->OnSlideStarted(notification_id_);
+ }
+}
+
+void MessageView::OnSlideChanged(bool in_progress) {
for (auto* observer : slide_observers_) {
observer->OnSlideChanged(notification_id_);
}
@@ -392,18 +390,20 @@ void MessageView::DisableSlideForcibly(bool disable) {
slide_out_controller_.set_slide_mode(CalculateSlideMode());
}
+void MessageView::SetSlideButtonWidth(int control_button_width) {
+ slide_out_controller_.SetSwipeControlWidth(control_button_width);
+}
+
void MessageView::OnCloseButtonPressed() {
MessageCenter::Get()->RemoveNotification(notification_id_,
true /* by_user */);
}
void MessageView::OnSettingsButtonPressed(const ui::Event& event) {
- slide_out_controller_.CloseSwipeControl();
MessageCenter::Get()->ClickOnSettingsButton(notification_id_);
}
void MessageView::OnSnoozeButtonPressed(const ui::Event& event) {
- slide_out_controller_.CloseSwipeControl();
// No default implementation for snooze.
}
diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h
index 49138c6780b..a0ea2aef23d 100644
--- a/chromium/ui/message_center/views/message_view.h
+++ b/chromium/ui/message_center/views/message_view.h
@@ -38,6 +38,10 @@ class NotificationControlButtonsView;
// An base class for a notification entry. Contains background and other
// elements shared by derived notification views.
+// TODO(pkasting): This class only subclasses InkDropHostView because the
+// NotificationViewMD subclass needs ink drop functionality. Rework ink drops
+// to not need to be the base class of views which use them, and move the
+// functionality to the subclass that uses these.
class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
public SlideOutController::Delegate,
public views::FocusChangeListener {
@@ -46,7 +50,10 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
class SlideObserver {
public:
- virtual void OnSlideChanged(const std::string& notification_id) = 0;
+ virtual ~SlideObserver() = default;
+
+ virtual void OnSlideStarted(const std::string& notification_id) {}
+ virtual void OnSlideChanged(const std::string& notification_id) {}
};
enum class Mode {
@@ -104,7 +111,7 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
virtual void OnSettingsButtonPressed(const ui::Event& event);
virtual void OnSnoozeButtonPressed(const ui::Event& event);
- // views::View
+ // views::InkDropHostView:
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
@@ -120,9 +127,10 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
void AddedToWidget() override;
const char* GetClassName() const final;
- // message_center::SlideOutController::Delegate
+ // message_center::SlideOutController::Delegate:
ui::Layer* GetSlideOutLayer() override;
- void OnSlideChanged() override;
+ void OnSlideStarted() override;
+ void OnSlideChanged(bool in_progress) override;
void OnSlideOut() override;
// views::FocusChangeListener:
@@ -144,15 +152,13 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView,
// mode.
void DisableSlideForcibly(bool disable);
+ // Updates the width of the buttons which are hidden and avail by swipe.
+ void SetSlideButtonWidth(int coutrol_button_width);
+
void set_scroller(views::ScrollView* scroller) { scroller_ = scroller; }
std::string notification_id() const { return notification_id_; }
protected:
- // Creates and add close button to view hierarchy when necessary. Derived
- // classes should call this after its view hierarchy is populated to ensure
- // it is on top of other views.
- void CreateOrUpdateCloseButtonView(const Notification& notification);
-
virtual void UpdateControlButtonsVisibility() = 0;
// Changes the background color and schedules a paint.
diff --git a/chromium/ui/message_center/views/message_view_factory.cc b/chromium/ui/message_center/views/message_view_factory.cc
index ce4ef494d27..0ce0d313328 100644
--- a/chromium/ui/message_center/views/message_view_factory.cc
+++ b/chromium/ui/message_center/views/message_view_factory.cc
@@ -4,6 +4,8 @@
#include "ui/message_center/views/message_view_factory.h"
+#include <vector>
+
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/lazy_instance.h"
@@ -16,8 +18,19 @@ namespace message_center {
namespace {
-base::LazyInstance<MessageViewFactory::CustomMessageViewFactoryFunction>::Leaky
- g_custom_view_factory = LAZY_INSTANCE_INITIALIZER;
+using MessageViewCustomFactoryMap =
+ std::map<std::string, MessageViewFactory::CustomMessageViewFactoryFunction>;
+
+base::LazyInstance<MessageViewCustomFactoryMap>::Leaky g_custom_view_factories =
+ LAZY_INSTANCE_INITIALIZER;
+
+std::unique_ptr<MessageView> GetCustomNotificationView(
+ const Notification& notification) {
+ MessageViewCustomFactoryMap* factories = g_custom_view_factories.Pointer();
+ auto iter = factories->find(notification.custom_view_type());
+ DCHECK(iter != factories->end());
+ return iter->second.Run(notification);
+}
} // namespace
@@ -37,8 +50,7 @@ MessageView* MessageViewFactory::Create(const Notification& notification) {
notification_view = new NotificationView(notification);
break;
case NOTIFICATION_TYPE_CUSTOM:
- notification_view =
- g_custom_view_factory.Get().Run(notification).release();
+ notification_view = GetCustomNotificationView(notification).release();
break;
default:
// If the caller asks for an unrecognized kind of view (entirely possible
@@ -56,13 +68,24 @@ MessageView* MessageViewFactory::Create(const Notification& notification) {
// static
void MessageViewFactory::SetCustomNotificationViewFactory(
+ const std::string& custom_view_type,
const CustomMessageViewFactoryFunction& factory_function) {
- g_custom_view_factory.Get() = factory_function;
+ MessageViewCustomFactoryMap* factories = g_custom_view_factories.Pointer();
+ DCHECK(factories->find(custom_view_type) == factories->end());
+ factories->emplace(custom_view_type, factory_function);
+}
+
+// static
+bool MessageViewFactory::HasCustomNotificationViewFactory(
+ const std::string& custom_view_type) {
+ MessageViewCustomFactoryMap* factories = g_custom_view_factories.Pointer();
+ return factories->find(custom_view_type) != factories->end();
}
// static
-bool MessageViewFactory::HasCustomNotificationViewFactory() {
- return !g_custom_view_factory.Get().is_null();
+void MessageViewFactory::ClearCustomNotificationViewFactoryForTest(
+ const std::string& custom_view_type) {
+ g_custom_view_factories.Get().erase(custom_view_type);
}
} // namespace message_center
diff --git a/chromium/ui/message_center/views/message_view_factory.h b/chromium/ui/message_center/views/message_view_factory.h
index 30c8520fdcd..f4d48b8b7a9 100644
--- a/chromium/ui/message_center/views/message_view_factory.h
+++ b/chromium/ui/message_center/views/message_view_factory.h
@@ -8,6 +8,7 @@
#include "ui/message_center/message_center_export.h"
#include <memory>
+#include <string>
#include "base/callback_forward.h"
@@ -29,16 +30,18 @@ class MESSAGE_CENTER_EXPORT MessageViewFactory {
static MessageView* Create(const Notification& notification);
- // Sets the function that will be invoked to create a custom notification
- // view. This should be a repeating callback. It's an error to attempt to show
- // a custom notification without first having called this function. Currently,
- // only ARC uses custom notifications, so this doesn't need to distinguish
- // between various sources of custom notification.
+ // Sets the function that will be invoked to create a custom notification view
+ // for a specific |custom_view_type|. This should be a repeating callback.
+ // It's an error to attempt to show a custom notification without first having
+ // called this function. The |custom_view_type| on the notification should
+ // also match the type used here.
static void SetCustomNotificationViewFactory(
+ const std::string& custom_view_type,
const CustomMessageViewFactoryFunction& factory_function);
-
- // Returns whether the custom view factory function has already been set.
- static bool HasCustomNotificationViewFactory();
+ static bool HasCustomNotificationViewFactory(
+ const std::string& custom_view_type);
+ static void ClearCustomNotificationViewFactoryForTest(
+ const std::string& custom_view_type);
};
} // namespace message_center
diff --git a/chromium/ui/message_center/views/notification_header_view.cc b/chromium/ui/message_center/views/notification_header_view.cc
index b9b83d8e7c3..947da04c92c 100644
--- a/chromium/ui/message_center/views/notification_header_view.cc
+++ b/chromium/ui/message_center/views/notification_header_view.cc
@@ -117,7 +117,7 @@ void ExpandButton::OnBlur() {
void ExpandButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kButton;
- node_data->SetName(views::ImageView::GetTooltipText());
+ node_data->SetName(tooltip_text());
}
// Do relative time string formatting that is similar to
@@ -369,7 +369,7 @@ void NotificationHeaderView::SetExpanded(bool expanded) {
expand_button_->SetImage(gfx::CreateVectorIcon(
expanded ? kNotificationExpandLessIcon : kNotificationExpandMoreIcon,
kExpandIconSize, accent_color_));
- expand_button_->SetTooltipText(l10n_util::GetStringUTF16(
+ expand_button_->set_tooltip_text(l10n_util::GetStringUTF16(
expanded ? IDS_MESSAGE_CENTER_COLLAPSE_NOTIFICATION
: IDS_MESSAGE_CENTER_EXPAND_NOTIFICATION));
NotifyAccessibilityEvent(ax::mojom::Event::kStateChanged, true);
diff --git a/chromium/ui/message_center/views/notification_header_view.h b/chromium/ui/message_center/views/notification_header_view.h
index b1f14665034..72f6caa7e51 100644
--- a/chromium/ui/message_center/views/notification_header_view.h
+++ b/chromium/ui/message_center/views/notification_header_view.h
@@ -6,6 +6,7 @@
#define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_HEADER_VIEW_H_
#include "base/macros.h"
+#include "ui/message_center/message_center_export.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/views/controls/button/button.h"
@@ -18,7 +19,7 @@ namespace message_center {
class NotificationControlButtonsView;
-class NotificationHeaderView : public views::Button {
+class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
public:
NotificationHeaderView(NotificationControlButtonsView* control_buttons_view,
views::ButtonListener* listener);
diff --git a/chromium/ui/message_center/views/notification_menu_model_unittest.cc b/chromium/ui/message_center/views/notification_menu_model_unittest.cc
index 7cde296d9cf..937ed1c187a 100644
--- a/chromium/ui/message_center/views/notification_menu_model_unittest.cc
+++ b/chromium/ui/message_center/views/notification_menu_model_unittest.cc
@@ -77,7 +77,7 @@ TEST_F(NotificationMenuModelTest, ContextMenuTestWithMessageCenter) {
base::string16 display_source = base::ASCIIToUTF16("www.test.org");
NotifierId notifier_id = DummyNotifierId();
- NotifierId notifier_id2(NotifierId::APPLICATION, "sample-app");
+ NotifierId notifier_id2(NotifierType::APPLICATION, "sample-app");
std::unique_ptr<Notification> notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, id2,
base::ASCIIToUTF16("Test Web Notification"),
diff --git a/chromium/ui/message_center/views/notification_view.cc b/chromium/ui/message_center/views/notification_view.cc
index 7094e2d2959..1bea4a1494e 100644
--- a/chromium/ui/message_center/views/notification_view.cc
+++ b/chromium/ui/message_center/views/notification_view.cc
@@ -94,6 +94,17 @@ std::unique_ptr<views::Border> MakeSeparatorBorder(int top,
return views::CreateSolidSidedBorder(top, left, 0, 0, color);
}
+#if !defined(OS_CHROMEOS)
+// static
+void SetBorderRight(views::View* view, int right) {
+ const gfx::Insets& insets = view->GetInsets();
+ if (insets.right() != right) {
+ view->SetBorder(
+ MakeEmptyBorder(insets.top(), insets.left(), insets.bottom(), right));
+ }
+}
+#endif
+
// NotificationItemView ////////////////////////////////////////////////////////
// NotificationItemViews are responsible for drawing each list notification
@@ -146,6 +157,8 @@ void NotificationItemView::SetVisible(bool visible) {
// NotificationView ////////////////////////////////////////////////////////////
void NotificationView::CreateOrUpdateViews(const Notification& notification) {
+ top_view_count_ = 0;
+
CreateOrUpdateTitleView(notification);
CreateOrUpdateMessageView(notification);
CreateOrUpdateProgressBarView(notification);
@@ -243,7 +256,14 @@ int NotificationView::GetHeightForWidth(int width) const {
}
void NotificationView::Layout() {
+ // |ShrinkTopmostLabel| updates the borders of views to make space for the
+ // control buttons. We have to update the borders before calling
+ // |MessageView::Layout| so that the latest values get taken into account
+ // while layouting. As |ShrinkTopmostLabel| only depends on the PreferredSize,
+ // this is valid to do before calling |MessageView::Layout|.
+ ShrinkTopmostLabel();
MessageView::Layout();
+
gfx::Insets insets = GetInsets();
int content_width = width() - insets.width();
gfx::Rect content_bounds = GetContentsBounds();
@@ -260,7 +280,6 @@ void NotificationView::Layout() {
// Top views.
int top_height = top_view_->GetHeightForWidth(content_width);
top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height);
- ShrinkTopmostLabel();
// Icon.
icon_view_->SetBounds(insets.left(), insets.top(), kNotificationIconSize,
@@ -370,10 +389,12 @@ void NotificationView::CreateOrUpdateTitleView(
title_view_->SetLineLimit(kMaxTitleLines);
title_view_->SetColor(kRegularTextColor);
title_view_->SetBorder(MakeTextBorder(padding, 3, 0));
- top_view_->AddChildView(title_view_);
+ top_view_->AddChildViewAt(title_view_, top_view_count_);
} else {
title_view_->SetText(title);
}
+
+ top_view_count_++;
}
void NotificationView::CreateOrUpdateMessageView(
@@ -396,12 +417,13 @@ void NotificationView::CreateOrUpdateMessageView(
message_view_->SetLineHeight(kMessageLineHeight);
message_view_->SetColor(kRegularTextColor);
message_view_->SetBorder(MakeTextBorder(padding, 4, 0));
- top_view_->AddChildView(message_view_);
+ top_view_->AddChildViewAt(message_view_, top_view_count_);
} else {
message_view_->SetText(text);
}
message_view_->SetVisible(notification.items().empty());
+ top_view_count_++;
}
base::string16 NotificationView::FormatContextMessage(
@@ -440,10 +462,12 @@ void NotificationView::CreateOrUpdateContextMessageView(
context_message_view_->SetLineHeight(kMessageLineHeight);
context_message_view_->SetColor(kDimTextColor);
context_message_view_->SetBorder(MakeTextBorder(padding, 4, 0));
- top_view_->AddChildView(context_message_view_);
+ top_view_->AddChildViewAt(context_message_view_, top_view_count_);
} else {
context_message_view_->SetText(message);
}
+
+ top_view_count_++;
}
void NotificationView::CreateOrUpdateProgressBarView(
@@ -461,11 +485,12 @@ void NotificationView::CreateOrUpdateProgressBarView(
progress_bar_view_ = new views::ProgressBar();
progress_bar_view_->SetBorder(MakeProgressBarBorder(
kProgressBarTopPadding, kProgressBarBottomPadding));
- top_view_->AddChildView(progress_bar_view_);
+ top_view_->AddChildViewAt(progress_bar_view_, top_view_count_);
}
progress_bar_view_->SetValue(notification.progress() / 100.0);
progress_bar_view_->SetVisible(notification.items().empty());
+ top_view_count_++;
}
void NotificationView::CreateOrUpdateListItemViews(
@@ -485,7 +510,7 @@ void NotificationView::CreateOrUpdateListItemViews(
NotificationItemView* item_view = new NotificationItemView(items[i]);
item_view->SetBorder(MakeTextBorder(padding, i ? 0 : 4, 0));
item_views_.push_back(item_view);
- top_view_->AddChildView(item_view);
+ top_view_->AddChildViewAt(item_view, top_view_count_++);
}
}
@@ -670,12 +695,12 @@ void NotificationView::ShrinkTopmostLabel() {
// Reduce width of the topmost label not to be covered by the control buttons
// only on non Chrome OS platform.
#if !defined(OS_CHROMEOS)
- const int content_width = width() - GetInsets().width();
- const int buttons_width = control_buttons_view_->GetPreferredSize().width();
- if (top_view_->child_count() > 0) {
- gfx::Rect bounds = top_view_->child_at(0)->bounds();
- bounds.set_width(content_width - buttons_width);
- top_view_->child_at(0)->SetBoundsRect(bounds);
+ const int child_count = top_view_->child_count();
+ if (child_count > 0) {
+ const int buttons_width = control_buttons_view_->GetPreferredSize().width();
+ SetBorderRight(top_view_->child_at(0), kTextRightPadding + buttons_width);
+ for (int i = 1; i < child_count; ++i)
+ SetBorderRight(top_view_->child_at(i), kTextRightPadding);
}
#endif
}
diff --git a/chromium/ui/message_center/views/notification_view.h b/chromium/ui/message_center/views/notification_view.h
index b0869eba067..e58e29e7bc0 100644
--- a/chromium/ui/message_center/views/notification_view.h
+++ b/chromium/ui/message_center/views/notification_view.h
@@ -60,8 +60,10 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestLineLimits);
FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestIconSizing);
FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestImageSizing);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TitleWrappingTest);
FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateButtonsStateTest);
FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateButtonCountTest);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateViewsOrderingTest);
friend class NotificationViewTest;
@@ -108,6 +110,10 @@ class MESSAGE_CENTER_EXPORT NotificationView : public MessageView,
std::unique_ptr<views::ImageView> small_image_view_;
NotificationControlButtonsView* control_buttons_view_;
+ // Counter for view layouting, which is used during the CreateOrUpdate*
+ // phases to keep track of the view ordering. See crbug.com/901045
+ int top_view_count_;
+
DISALLOW_COPY_AND_ASSIGN(NotificationView);
};
diff --git a/chromium/ui/message_center/views/notification_view_md.cc b/chromium/ui/message_center/views/notification_view_md.cc
index c27bfd96816..e6fcbfff3cf 100644
--- a/chromium/ui/message_center/views/notification_view_md.cc
+++ b/chromium/ui/message_center/views/notification_view_md.cc
@@ -90,9 +90,6 @@ constexpr SkColor kLargeImageBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5);
constexpr SkColor kRegularTextColorMD = SkColorSetRGB(0x21, 0x21, 0x21);
constexpr SkColor kDimTextColorMD = SkColorSetRGB(0x75, 0x75, 0x75);
-// Background of inline settings area.
-const SkColor kSettingsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee);
-
// Text color and icon color of inline reply area when the textfield is empty.
constexpr SkColor kTextfieldPlaceholderTextColorMD =
SkColorSetA(SK_ColorWHITE, 0x8A);
@@ -335,7 +332,7 @@ NotificationButtonMD::NotificationButtonMD(
views::style::CONTEXT_BUTTON_MD),
placeholder_(placeholder) {
SetHorizontalAlignment(gfx::ALIGN_CENTER);
- SetInkDropMode(views::LabelButton::InkDropMode::ON);
+ SetInkDropMode(InkDropMode::ON);
set_has_ink_drop_action_on_click(true);
set_ink_drop_base_color(SK_ColorBLACK);
set_ink_drop_visible_opacity(kActionButtonInkDropRippleVisibleOpacity);
@@ -440,6 +437,7 @@ bool NotificationInputContainerMD::HandleKeyEvent(views::Textfield* sender,
event.key_code() == ui::VKEY_RETURN) {
delegate_->OnNotificationInputSubmit(
textfield_->GetProperty(kTextfieldIndexKey), textfield_->text());
+ textfield_->SetText(base::string16());
return true;
}
return event.type() == ui::ET_KEY_RELEASED;
@@ -480,6 +478,8 @@ class InlineSettingsRadioButton : public views::RadioButton {
// ////////////////////////////////////////////////////////////
void NotificationViewMD::CreateOrUpdateViews(const Notification& notification) {
+ left_content_count_ = 0;
+
CreateOrUpdateContextTitleView(notification);
CreateOrUpdateTitleView(notification);
CreateOrUpdateMessageView(notification);
@@ -619,12 +619,6 @@ void NotificationViewMD::OnFocus() {
ScrollRectToVisible(GetLocalBounds());
}
-void NotificationViewMD::ScrollRectToVisible(const gfx::Rect& rect) {
- // Notification want to show the whole notification when a part of it (like
- // a button) gets focused.
- views::View::ScrollRectToVisible(GetLocalBounds());
-}
-
bool NotificationViewMD::OnMousePressed(const ui::MouseEvent& event) {
last_mouse_pressed_timestamp_ = base::TimeTicks(event.time_stamp());
return true;
@@ -709,17 +703,17 @@ void NotificationViewMD::UpdateControlButtonsVisibilityWithNotification(
void NotificationViewMD::ButtonPressed(views::Button* sender,
const ui::Event& event) {
- // Certain operations can cause |this| to be destructed, so copy the members
- // we send to other parts of the code.
- // TODO(dewittj): Remove this hack.
- std::string id(notification_id());
-
// Tapping anywhere on |header_row_| can expand the notification, though only
// |expand_button| can be focused by TAB.
if (sender == header_row_) {
if (IsExpandable() && content_row_->visible()) {
SetManuallyExpandedOrCollapsed(true);
+ auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
ToggleExpanded();
+ // Check |this| is valid before continuing, because ToggleExpanded() might
+ // cause |this| to be deleted.
+ if (!weak_ptr)
+ return;
Layout();
SchedulePaint();
}
@@ -749,14 +743,12 @@ void NotificationViewMD::ButtonPressed(views::Button* sender,
Layout();
SchedulePaint();
} else {
- MessageCenter::Get()->ClickOnNotificationButton(id, i);
+ MessageCenter::Get()->ClickOnNotificationButton(notification_id(), i);
}
return;
}
if (sender == settings_done_button_) {
- if (block_all_button_->checked())
- MessageCenter::Get()->DisableNotification(id);
ToggleInlineSettings(event);
return;
}
@@ -781,8 +773,8 @@ void NotificationViewMD::CreateOrUpdateContextTitleView(
app_name = url_formatter::FormatUrlForSecurityDisplay(
notification.origin_url(),
url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
- } else if (app_name.empty() &&
- notification.notifier_id().type == NotifierId::SYSTEM_COMPONENT) {
+ } else if (app_name.empty() && notification.notifier_id().type ==
+ NotifierType::SYSTEM_COMPONENT) {
app_name = MessageCenter::Get()->GetSystemNotificationAppName();
}
header_row_->SetAppName(app_name);
@@ -810,10 +802,12 @@ void NotificationViewMD::CreateOrUpdateTitleView(
title_view_->SetFontList(font_list);
title_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
title_view_->SetEnabledColor(kRegularTextColorMD);
- left_content_->AddChildView(title_view_);
+ left_content_->AddChildViewAt(title_view_, left_content_count_);
} else {
title_view_->SetText(title);
}
+
+ left_content_count_++;
}
void NotificationViewMD::CreateOrUpdateMessageView(
@@ -836,12 +830,13 @@ void NotificationViewMD::CreateOrUpdateMessageView(
message_view_->SetLineLimit(kMaxLinesForMessageView);
message_view_->SetColor(kDimTextColorMD);
- left_content_->AddChildView(message_view_);
+ left_content_->AddChildViewAt(message_view_, left_content_count_);
} else {
message_view_->SetText(text);
}
message_view_->SetVisible(notification.items().empty());
+ left_content_count_++;
}
void NotificationViewMD::CreateOrUpdateCompactTitleMessageView(
@@ -855,12 +850,14 @@ void NotificationViewMD::CreateOrUpdateCompactTitleMessageView(
}
if (!compact_title_message_view_) {
compact_title_message_view_ = new CompactTitleMessageView();
- left_content_->AddChildView(compact_title_message_view_);
+ left_content_->AddChildViewAt(compact_title_message_view_,
+ left_content_count_);
}
compact_title_message_view_->set_title(notification.title());
compact_title_message_view_->set_message(notification.message());
left_content_->InvalidateLayout();
+ left_content_count_++;
}
void NotificationViewMD::CreateOrUpdateProgressBarView(
@@ -880,7 +877,7 @@ void NotificationViewMD::CreateOrUpdateProgressBarView(
/* allow_round_corner */ false);
progress_bar_view_->SetBorder(
views::CreateEmptyBorder(kProgressBarTopPadding, 0, 0, 0));
- left_content_->AddChildView(progress_bar_view_);
+ left_content_->AddChildViewAt(progress_bar_view_, left_content_count_);
}
progress_bar_view_->SetValue(notification.progress() / 100.0);
@@ -890,6 +887,8 @@ void NotificationViewMD::CreateOrUpdateProgressBarView(
header_row_->SetProgress(notification.progress());
else
header_row_->ClearProgress();
+
+ left_content_count_++;
}
void NotificationViewMD::CreateOrUpdateProgressStatusView(
@@ -911,10 +910,11 @@ void NotificationViewMD::CreateOrUpdateProgressStatusView(
status_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
status_view_->SetEnabledColor(kDimTextColorMD);
status_view_->SetBorder(views::CreateEmptyBorder(kStatusTextPadding));
- left_content_->AddChildView(status_view_);
+ left_content_->AddChildViewAt(status_view_, left_content_count_);
}
status_view_->SetText(notification.progress_status());
+ left_content_count_++;
}
void NotificationViewMD::CreateOrUpdateListItemViews(
@@ -929,7 +929,7 @@ void NotificationViewMD::CreateOrUpdateListItemViews(
++i) {
std::unique_ptr<views::View> item_view = CreateItemView(items[i]);
item_views_.push_back(item_view.get());
- left_content_->AddChildView(item_view.release());
+ left_content_->AddChildViewAt(item_view.release(), left_content_count_++);
}
list_items_count_ = items.size();
@@ -1012,14 +1012,26 @@ void NotificationViewMD::CreateOrUpdateActionButtonViews(
const std::vector<ButtonInfo>& buttons = notification.buttons();
bool new_buttons = action_buttons_.size() != buttons.size();
- if (new_buttons || buttons.size() == 0) {
+ if (new_buttons || buttons.empty()) {
for (auto* item : action_buttons_)
delete item;
action_buttons_.clear();
+ if (buttons.empty())
+ actions_row_->SetVisible(false);
}
DCHECK_EQ(this, actions_row_->parent());
+ // Hide inline reply field if it doesn't exist anymore.
+ if (inline_reply_->visible()) {
+ const size_t index =
+ inline_reply_->textfield()->GetProperty(kTextfieldIndexKey);
+ if (index >= buttons.size() || !buttons[index].placeholder.has_value()) {
+ action_buttons_row_->SetVisible(true);
+ inline_reply_->SetVisible(false);
+ }
+ }
+
for (size_t i = 0; i < buttons.size(); ++i) {
ButtonInfo button_info = buttons[i];
if (new_buttons) {
@@ -1029,6 +1041,7 @@ void NotificationViewMD::CreateOrUpdateActionButtonViews(
action_buttons_row_->AddChildView(button);
} else {
action_buttons_[i]->SetText(button_info.title);
+ action_buttons_[i]->set_placeholder(button_info.placeholder);
action_buttons_[i]->SchedulePaint();
action_buttons_[i]->Layout();
}
@@ -1074,20 +1087,22 @@ void NotificationViewMD::CreateOrUpdateInlineSettingsViews(
int block_notifications_message_id = 0;
switch (notification.notifier_id().type) {
- case NotifierId::APPLICATION:
- case NotifierId::ARC_APPLICATION:
+ case NotifierType::APPLICATION:
+ case NotifierType::ARC_APPLICATION:
block_notifications_message_id =
IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_APP;
break;
- case NotifierId::WEB_PAGE:
+ case NotifierType::WEB_PAGE:
block_notifications_message_id =
IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_SITE;
break;
- case NotifierId::SYSTEM_COMPONENT:
- case NotifierId::SIZE:
+ case NotifierType::SYSTEM_COMPONENT:
block_notifications_message_id =
IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS;
break;
+ case NotifierType::CROSTINI_APPLICATION:
+ NOTREACHED();
+ break;
}
DCHECK_NE(block_notifications_message_id, 0);
@@ -1197,6 +1212,8 @@ void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
return;
bool inline_settings_visible = !settings_row_->visible();
+ bool disable_notification =
+ settings_row_->visible() && block_all_button_->checked();
settings_row_->SetVisible(inline_settings_visible);
content_row_->SetVisible(!inline_settings_visible);
@@ -1218,6 +1235,11 @@ void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
Layout();
SchedulePaint();
+
+ // Call DisableNotification() at the end, because |this| can be deleted at any
+ // point after it's called.
+ if (disable_notification)
+ MessageCenter::Get()->DisableNotification(notification_id());
}
// TODO(yoshiki): Move this to the parent class (MessageView) and share the code
@@ -1267,11 +1289,6 @@ void NotificationViewMD::SetManuallyExpandedOrCollapsed(bool value) {
}
void NotificationViewMD::OnSettingsButtonPressed(const ui::Event& event) {
- // TODO(yamaguchi): remove this line and call CloseSwipeControl() from parent
- // view of this view. The parent view should activate the swipe control of
- // the slider attached to this view.
- CloseSwipeControl();
-
if (settings_row_)
ToggleInlineSettings(event);
else
@@ -1344,7 +1361,8 @@ std::unique_ptr<views::InkDropRipple> NotificationViewMD::CreateInkDropRipple()
}
SkColor NotificationViewMD::GetInkDropBaseColor() const {
- return kSettingsRowBackgroundColor;
+ // Background of inline settings area.
+ return SkColorSetRGB(0xEE, 0xEE, 0xEE);
}
void NotificationViewMD::InkDropAnimationStarted() {
diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h
index 4ead77eeb3c..a954fff6d6f 100644
--- a/chromium/ui/message_center/views/notification_view_md.h
+++ b/chromium/ui/message_center/views/notification_view_md.h
@@ -99,9 +99,12 @@ class NotificationButtonMD : public views::LabelButton {
const base::Optional<base::string16>& placeholder() const {
return placeholder_;
}
+ void set_placeholder(const base::Optional<base::string16>& placeholder) {
+ placeholder_ = placeholder;
+ }
private:
- const base::Optional<base::string16> placeholder_;
+ base::Optional<base::string16> placeholder_;
DISALLOW_COPY_AND_ASSIGN(NotificationButtonMD);
};
@@ -171,7 +174,6 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
// Overridden from views::View:
void Layout() override;
void OnFocus() override;
- void ScrollRectToVisible(const gfx::Rect& rect) override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
@@ -213,11 +215,17 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestClickExpanded);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestActionButtonClick);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestInlineReply);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
+ TestInlineReplyRemovedByUpdate);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestAccentColor);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, NotificationWithoutIcon);
FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateViewsOrderingTest);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestDeleteOnToggleExpanded);
+ FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest,
+ TestDeleteOnDisableNotification);
friend class NotificationViewMDTest;
@@ -288,6 +296,10 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
views::View* action_buttons_row_ = nullptr;
NotificationInputContainerMD* inline_reply_ = nullptr;
+ // Counter for view layouting, which is used during the CreateOrUpdate*
+ // phases to keep track of the view ordering. See crbug.com/901045
+ int left_content_count_;
+
// Views for inline settings.
views::RadioButton* block_all_button_ = nullptr;
views::RadioButton* dont_block_button_ = nullptr;
@@ -297,6 +309,8 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD
base::TimeTicks last_mouse_pressed_timestamp_;
+ base::WeakPtrFactory<NotificationViewMD> weak_ptr_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(NotificationViewMD);
};
diff --git a/chromium/ui/message_center/views/notification_view_md_unittest.cc b/chromium/ui/message_center/views/notification_view_md_unittest.cc
index b39c64ce3b2..bd23045b068 100644
--- a/chromium/ui/message_center/views/notification_view_md_unittest.cc
+++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc
@@ -4,6 +4,8 @@
#include "ui/message_center/views/notification_view_md.h"
+#include <memory>
+
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -14,6 +16,7 @@
#include "ui/events/test/event_generator.h"
#include "ui/gfx/canvas.h"
#include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_observer.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/views/bounded_label.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
@@ -26,6 +29,7 @@
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
+#include "ui/views/widget/widget_utils.h"
namespace message_center {
@@ -92,10 +96,17 @@ class NotificationTestDelegate : public NotificationDelegate {
DISALLOW_COPY_AND_ASSIGN(NotificationTestDelegate);
};
+class DummyEvent : public ui::Event {
+ public:
+ DummyEvent() : Event(ui::ET_UNKNOWN, base::TimeTicks(), 0) {}
+ ~DummyEvent() override = default;
+};
+
class NotificationViewMDTest
: public views::ViewsTestBase,
public views::ViewObserver,
- public message_center::MessageView::SlideObserver {
+ public message_center::MessageView::SlideObserver,
+ public message_center::MessageCenterObserver {
public:
NotificationViewMDTest();
~NotificationViewMDTest() override;
@@ -118,6 +129,19 @@ class NotificationViewMDTest
// Overridden from message_center::MessageView::Observer:
void OnSlideChanged(const std::string& notification_id) override {}
+ // Overridden from message_center::MessageCenterObserver:
+ void OnNotificationRemoved(const std::string& notification_id,
+ bool by_user) override;
+
+ void set_delete_on_preferred_size_changed(
+ bool delete_on_preferred_size_changed) {
+ delete_on_preferred_size_changed_ = delete_on_preferred_size_changed;
+ }
+
+ void set_delete_on_notification_removed(bool delete_on_notification_removed) {
+ delete_on_notification_removed_ = delete_on_notification_removed;
+ }
+
protected:
const gfx::Image CreateTestImage(int width, int height) const;
const SkBitmap CreateBitmap(int width, int height) const;
@@ -137,6 +161,8 @@ class NotificationViewMDTest
void ScrollBy(int dx);
views::View* GetCloseButton();
+ bool delete_on_preferred_size_changed_ = false;
+ bool delete_on_notification_removed_ = false;
std::set<std::string> removed_ids_;
scoped_refptr<NotificationTestDelegate> delegate_;
std::unique_ptr<NotificationViewMD> notification_view_;
@@ -158,7 +184,7 @@ std::unique_ptr<Notification> NotificationViewMDTest::CreateSimpleNotification()
NOTIFICATION_TYPE_BASE_FORMAT, std::string(kDefaultNotificationId),
base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"),
CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), GURL(),
- NotifierId(NotifierId::APPLICATION, "extension_id"), data, delegate_);
+ NotifierId(NotifierType::APPLICATION, "extension_id"), data, delegate_);
notification->set_small_image(CreateTestImage(16, 16));
notification->set_image(CreateTestImage(320, 240));
@@ -175,13 +201,21 @@ void NotificationViewMDTest::SetUp() {
std::unique_ptr<Notification> notification = CreateSimpleNotification();
UpdateNotificationViews(*notification);
+
+ MessageCenter::Get()->AddObserver(this);
}
void NotificationViewMDTest::TearDown() {
- notification_view_->SetInkDropMode(MessageView::InkDropMode::OFF);
- notification_view_->RemoveObserver(this);
- widget()->Close();
- notification_view_.reset();
+ MessageCenter::Get()->RemoveObserver(this);
+
+ DCHECK(notification_view_ || delete_on_preferred_size_changed_ ||
+ delete_on_notification_removed_);
+ if (notification_view_) {
+ notification_view_->SetInkDropMode(MessageView::InkDropMode::OFF);
+ notification_view_->RemoveObserver(this);
+ widget()->Close();
+ notification_view_.reset();
+ }
MessageCenter::Shutdown();
views::ViewsTestBase::TearDown();
}
@@ -189,9 +223,24 @@ void NotificationViewMDTest::TearDown() {
void NotificationViewMDTest::OnViewPreferredSizeChanged(
views::View* observed_view) {
EXPECT_EQ(observed_view, notification_view());
+ if (delete_on_preferred_size_changed_) {
+ widget()->CloseNow();
+ notification_view_.reset();
+ return;
+ }
widget()->SetSize(notification_view()->GetPreferredSize());
}
+void NotificationViewMDTest::OnNotificationRemoved(
+ const std::string& notification_id,
+ bool by_user) {
+ if (delete_on_notification_removed_) {
+ widget()->CloseNow();
+ notification_view_.reset();
+ return;
+ }
+}
+
const gfx::Image NotificationViewMDTest::CreateTestImage(int width,
int height) const {
return gfx::Image::CreateFrom1xBitmap(CreateBitmap(width, height));
@@ -260,7 +309,6 @@ void NotificationViewMDTest::UpdateNotificationViews(
// created by the method.
notification_view_ = std::make_unique<NotificationViewMD>(notification);
notification_view_->AddObserver(this);
- notification_view_->SetIsNested();
notification_view_->set_owned_by_client();
views::Widget::InitParams init_params(
@@ -293,7 +341,7 @@ bool NotificationViewMDTest::IsRemovedAfterIdle(
void NotificationViewMDTest::DispatchGesture(
const ui::GestureEventDetails& details) {
ui::test::EventGenerator generator(
- notification_view()->GetWidget()->GetNativeWindow());
+ GetRootWindow(notification_view()->GetWidget()));
ui::GestureEvent event(0, 0, 0, ui::EventTimeForNow(), details);
generator.Dispatch(&event);
}
@@ -344,6 +392,36 @@ TEST_F(NotificationViewMDTest, CreateOrUpdateTest) {
EXPECT_EQ(nullptr, notification_view()->icon_view_);
}
+TEST_F(NotificationViewMDTest, UpdateViewsOrderingTest) {
+ EXPECT_NE(nullptr, notification_view()->title_view_);
+ EXPECT_NE(nullptr, notification_view()->message_view_);
+ EXPECT_EQ(0, notification_view()->left_content_->GetIndexOf(
+ notification_view()->title_view_));
+ EXPECT_EQ(1, notification_view()->left_content_->GetIndexOf(
+ notification_view()->message_view_));
+
+ std::unique_ptr<Notification> notification = CreateSimpleNotification();
+ notification->set_title(base::string16());
+
+ notification_view()->CreateOrUpdateViews(*notification);
+
+ EXPECT_EQ(nullptr, notification_view()->title_view_);
+ EXPECT_NE(nullptr, notification_view()->message_view_);
+ EXPECT_EQ(0, notification_view()->left_content_->GetIndexOf(
+ notification_view()->message_view_));
+
+ notification->set_title(base::UTF8ToUTF16("title"));
+
+ notification_view()->CreateOrUpdateViews(*notification);
+
+ EXPECT_NE(nullptr, notification_view()->title_view_);
+ EXPECT_NE(nullptr, notification_view()->message_view_);
+ EXPECT_EQ(0, notification_view()->left_content_->GetIndexOf(
+ notification_view()->title_view_));
+ EXPECT_EQ(1, notification_view()->left_content_->GetIndexOf(
+ notification_view()->message_view_));
+}
+
TEST_F(NotificationViewMDTest, TestIconSizing) {
// TODO(tetsui): Remove duplicated integer literal in CreateOrUpdateIconView.
const int kNotificationIconSize = 36;
@@ -401,9 +479,9 @@ TEST_F(NotificationViewMDTest, UpdateButtonsStateTest) {
gfx::Point cursor_location(1, 1);
views::View::ConvertPointToWidget(notification_view()->action_buttons_[0],
&cursor_location);
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
+ ui::test::EventGenerator generator(
+ GetRootWindow(notification_view()->GetWidget()));
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_HOVERED,
notification_view()->action_buttons_[0]->state());
@@ -416,9 +494,9 @@ TEST_F(NotificationViewMDTest, UpdateButtonsStateTest) {
// Now construct a mouse move event 1 pixel outside the boundary of the
// widget.
cursor_location = gfx::Point(-1, -1);
- move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
+ views::View::ConvertPointToWidget(notification_view()->action_buttons_[0],
+ &cursor_location);
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_NORMAL,
notification_view()->action_buttons_[0]->state());
@@ -445,11 +523,9 @@ TEST_F(NotificationViewMDTest, UpdateButtonCountTest) {
gfx::Point cursor_location(1, 1);
views::View::ConvertPointToScreen(notification_view()->action_buttons_[0],
&cursor_location);
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- ui::EventDispatchDetails details =
- views::test::WidgetTest::GetEventSink(widget())->OnEventFromSource(&move);
- EXPECT_FALSE(details.dispatcher_destroyed);
+ ui::test::EventGenerator generator(
+ GetRootWindow(notification_view()->GetWidget()));
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_HOVERED,
notification_view()->action_buttons_[0]->state());
@@ -466,9 +542,9 @@ TEST_F(NotificationViewMDTest, UpdateButtonCountTest) {
// Now construct a mouse move event 1 pixel outside the boundary of the
// widget.
cursor_location = gfx::Point(-1, -1);
- move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
+ views::View::ConvertPointToScreen(notification_view()->action_buttons_[0],
+ &cursor_location);
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_NORMAL,
notification_view()->action_buttons_[0]->state());
@@ -482,7 +558,7 @@ TEST_F(NotificationViewMDTest, TestActionButtonClick) {
UpdateNotificationViews(*notification);
widget()->Show();
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
// Action buttons are hidden by collapsed state.
if (!notification_view()->expanded_)
@@ -510,7 +586,7 @@ TEST_F(NotificationViewMDTest, TestInlineReply) {
UpdateNotificationViews(*notification);
widget()->Show();
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
// Action buttons are hidden by collapsed state.
if (!notification_view()->expanded_)
@@ -567,7 +643,7 @@ TEST_F(NotificationViewMDTest, TestInlineReply) {
// Nothing should be submitted at this point.
EXPECT_EQ(-1, delegate_->clicked_button_index());
- EXPECT_EQ(base::EmptyString16(), delegate_->submitted_reply_string());
+ EXPECT_EQ(base::string16(), delegate_->submitted_reply_string());
// Click the button again and focus on the inline textfield.
generator.ClickLeftButton();
@@ -588,7 +664,63 @@ TEST_F(NotificationViewMDTest, TestInlineReply) {
EXPECT_EQ(base::ASCIIToUTF16("test"), delegate_->submitted_reply_string());
}
-TEST_F(NotificationViewMDTest, SlideOut) {
+TEST_F(NotificationViewMDTest, TestInlineReplyRemovedByUpdate) {
+ std::unique_ptr<Notification> notification = CreateSimpleNotification();
+
+ std::vector<ButtonInfo> buttons = CreateButtons(2);
+ buttons[1].placeholder = base::string16();
+ notification->set_buttons(buttons);
+ UpdateNotificationViews(*notification);
+ widget()->Show();
+
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
+
+ // Action buttons are hidden by collapsed state.
+ if (!notification_view()->expanded_)
+ notification_view()->ToggleExpanded();
+ EXPECT_TRUE(notification_view()->actions_row_->visible());
+
+ // Now construct a mouse click event 1 pixel inside the boundary of the action
+ // button.
+ gfx::Point cursor_location(1, 1);
+ views::View::ConvertPointToScreen(notification_view()->action_buttons_[1],
+ &cursor_location);
+ generator.MoveMouseTo(cursor_location);
+ generator.ClickLeftButton();
+
+ // Nothing should be submitted at this point.
+ EXPECT_EQ(-1, delegate_->clicked_button_index());
+
+ EXPECT_TRUE(notification_view()->inline_reply_->visible());
+ EXPECT_FALSE(notification_view()->action_buttons_row_->visible());
+
+ buttons[1].placeholder = base::nullopt;
+ notification->set_buttons(buttons);
+ UpdateNotificationViews(*notification);
+
+ EXPECT_FALSE(notification_view()->inline_reply_->visible());
+ EXPECT_TRUE(notification_view()->action_buttons_row_->visible());
+
+ // Now it emits click event.
+ delegate_->set_expecting_button_click(true);
+ generator.ClickLeftButton();
+ EXPECT_EQ(1, delegate_->clicked_button_index());
+
+ buttons.clear();
+ notification->set_buttons(buttons);
+ UpdateNotificationViews(*notification);
+
+ EXPECT_FALSE(notification_view()->actions_row_->visible());
+}
+
+// Synthetic scroll events are not supported on Mac in the views
+// test framework.
+#if defined(OS_MACOSX)
+#define MAYBE_SlideOut DISABLED_SlideOut
+#else
+#define MAYBE_SlideOut SlideOut
+#endif
+TEST_F(NotificationViewMDTest, MAYBE_SlideOut) {
ui::ScopedAnimationDurationScaleMode zero_duration_scope(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
@@ -610,7 +742,13 @@ TEST_F(NotificationViewMDTest, SlideOut) {
EXPECT_TRUE(IsRemovedAfterIdle(kDefaultNotificationId));
}
-TEST_F(NotificationViewMDTest, SlideOutNested) {
+#if defined(OS_MACOSX)
+#define MAYBE_SlideOutNested DISABLED_SlideOutNested
+#else
+#define MAYBE_SlideOutNested SlideOutNested
+#endif
+TEST_F(NotificationViewMDTest, MAYBE_SlideOutNested) {
+ notification_view()->SetIsNested();
ui::ScopedAnimationDurationScaleMode zero_duration_scope(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
@@ -630,7 +768,12 @@ TEST_F(NotificationViewMDTest, SlideOutNested) {
EXPECT_TRUE(IsRemovedAfterIdle(kDefaultNotificationId));
}
-TEST_F(NotificationViewMDTest, DisableSlideForcibly) {
+#if defined(OS_MACOSX)
+#define MAYBE_DisableSlideForcibly DISABLED_DisableSlideForcibly
+#else
+#define MAYBE_DisableSlideForcibly DisableSlideForcibly
+#endif
+TEST_F(NotificationViewMDTest, MAYBE_DisableSlideForcibly) {
ui::ScopedAnimationDurationScaleMode zero_duration_scope(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
@@ -658,6 +801,7 @@ TEST_F(NotificationViewMDTest, DisableSlideForcibly) {
#if defined(OS_CHROMEOS)
TEST_F(NotificationViewMDTest, SlideOutPinned) {
+ notification_view()->SetIsNested();
ui::ScopedAnimationDurationScaleMode zero_duration_scope(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
@@ -674,6 +818,7 @@ TEST_F(NotificationViewMDTest, SlideOutPinned) {
}
TEST_F(NotificationViewMDTest, Pinned) {
+ notification_view()->SetIsNested();
std::unique_ptr<Notification> notification = CreateSimpleNotification();
// Visible at the initial state.
@@ -726,7 +871,7 @@ TEST_F(NotificationViewMDTest, SnoozeButton) {
message_center::NOTIFICATION_TYPE_CUSTOM, kDefaultNotificationId,
base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), gfx::Image(),
base::UTF8ToUTF16("display source"), GURL(),
- message_center::NotifierId(message_center::NotifierId::ARC_APPLICATION,
+ message_center::NotifierId(message_center::NotifierType::ARC_APPLICATION,
"test_app_id"),
rich_data, nullptr);
@@ -779,7 +924,7 @@ TEST_F(NotificationViewMDTest, ExpandLongMessage) {
gfx::Point done_cursor_location(1, 1);
views::View::ConvertPointToScreen(notification_view()->header_row_,
&done_cursor_location);
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
generator.MoveMouseTo(done_cursor_location);
generator.ClickLeftButton();
@@ -883,13 +1028,14 @@ TEST_F(NotificationViewMDTest, InlineSettings) {
notification->set_type(NOTIFICATION_TYPE_SIMPLE);
UpdateNotificationViews(*notification);
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
+
// Inline settings will be shown by clicking settings button.
EXPECT_FALSE(notification_view()->settings_row_->visible());
gfx::Point settings_cursor_location(1, 1);
- views::View::ConvertPointToScreen(
+ views::View::ConvertPointToTarget(
notification_view()->control_buttons_view_->settings_button(),
- &settings_cursor_location);
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ notification_view(), &settings_cursor_location);
generator.MoveMouseTo(settings_cursor_location);
generator.ClickLeftButton();
EXPECT_TRUE(notification_view()->settings_row_->visible());
@@ -904,8 +1050,9 @@ TEST_F(NotificationViewMDTest, InlineSettings) {
// Construct a mouse click event 1 pixel inside the done button.
gfx::Point done_cursor_location(1, 1);
- views::View::ConvertPointToScreen(notification_view()->settings_done_button_,
- &done_cursor_location);
+ views::View::ConvertPointToTarget(
+ notification_view()->control_buttons_view_->settings_button(),
+ notification_view(), &done_cursor_location);
generator.MoveMouseTo(done_cursor_location);
generator.ClickLeftButton();
@@ -919,7 +1066,8 @@ TEST_F(NotificationViewMDTest, InlineSettings) {
// Construct a mouse click event 1 pixel inside the block all button.
gfx::Point block_cursor_location(1, 1);
- views::View::ConvertPointToScreen(notification_view()->block_all_button_,
+ views::View::ConvertPointToTarget(notification_view()->block_all_button_,
+ notification_view(),
&block_cursor_location);
generator.MoveMouseTo(block_cursor_location);
generator.ClickLeftButton();
@@ -937,7 +1085,8 @@ TEST_F(NotificationViewMDTest, TestClick) {
UpdateNotificationViews(*notification);
widget()->Show();
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(
+ GetRootWindow(notification_view()->GetWidget()));
// Collapse the notification if it's expanded.
if (notification_view()->expanded_)
@@ -947,7 +1096,6 @@ TEST_F(NotificationViewMDTest, TestClick) {
// Now construct a mouse click event 2 pixel inside from the bottom.
gfx::Point cursor_location(notification_view()->size().width() / 2,
notification_view()->size().height() - 2);
- views::View::ConvertPointToScreen(notification_view(), &cursor_location);
generator.MoveMouseTo(cursor_location);
generator.ClickLeftButton();
@@ -961,7 +1109,7 @@ TEST_F(NotificationViewMDTest, TestClickExpanded) {
UpdateNotificationViews(*notification);
widget()->Show();
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
// Expand the notification if it's collapsed.
if (!notification_view()->expanded_)
@@ -971,11 +1119,42 @@ TEST_F(NotificationViewMDTest, TestClickExpanded) {
// Now construct a mouse click event 2 pixel inside from the bottom.
gfx::Point cursor_location(notification_view()->size().width() / 2,
notification_view()->size().height() - 2);
- views::View::ConvertPointToScreen(notification_view(), &cursor_location);
generator.MoveMouseTo(cursor_location);
generator.ClickLeftButton();
EXPECT_TRUE(delegate_->clicked());
}
+TEST_F(NotificationViewMDTest, TestDeleteOnToggleExpanded) {
+ std::unique_ptr<Notification> notification = CreateSimpleNotification();
+ notification->set_type(NotificationType::NOTIFICATION_TYPE_SIMPLE);
+ notification->set_title(base::string16());
+ notification->set_message(base::ASCIIToUTF16(
+ "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore "
+ "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud "
+ "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."));
+ UpdateNotificationViews(*notification);
+ EXPECT_FALSE(notification_view()->expanded_);
+
+ // The view can be deleted by PreferredSizeChanged(). https://crbug.com/918933
+ set_delete_on_preferred_size_changed(true);
+ notification_view()->ButtonPressed(notification_view()->header_row_,
+ DummyEvent());
+}
+
+TEST_F(NotificationViewMDTest, TestDeleteOnDisableNotification) {
+ std::unique_ptr<Notification> notification = CreateSimpleNotification();
+ notification->set_type(NOTIFICATION_TYPE_SIMPLE);
+ UpdateNotificationViews(*notification);
+
+ notification_view()->OnSettingsButtonPressed(DummyEvent());
+ notification_view()->block_all_button_->NotifyClick(DummyEvent());
+
+ // After DisableNotification() is called, |notification_view| can be deleted.
+ // https://crbug.com/924922
+ set_delete_on_notification_removed(true);
+ notification_view()->ButtonPressed(notification_view()->settings_done_button_,
+ DummyEvent());
+}
+
} // namespace message_center
diff --git a/chromium/ui/message_center/views/notification_view_unittest.cc b/chromium/ui/message_center/views/notification_view_unittest.cc
index b79aae0c2c0..eb7f688f821 100644
--- a/chromium/ui/message_center/views/notification_view_unittest.cc
+++ b/chromium/ui/message_center/views/notification_view_unittest.cc
@@ -22,22 +22,26 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/text_utils.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/notification_list.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_types.h"
+#include "ui/message_center/views/bounded_label.h"
#include "ui/message_center/views/message_view_factory.h"
#include "ui/message_center/views/notification_button.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/message_center/views/padded_button.h"
#include "ui/message_center/views/proportional_image_view.h"
#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_utils.h"
#if defined(OS_WIN)
#include "ui/base/win/shell.h"
@@ -165,6 +169,49 @@ class NotificationViewTest : public views::ViewsTestBase {
.x();
}
+ int GetTitleWidth() {
+ return notification_view()->title_view_->GetContentsBounds().width();
+ }
+
+ int GetTitleHeight() {
+ return notification_view()->title_view_->GetContentsBounds().height();
+ }
+
+ int GetTitleCharactersPerLine(base::char16 character) {
+ int available_width = GetTitleWidth();
+#if !defined(OS_CHROMEOS)
+ // On non-ChromeOS systems, we expect the available width to be reduced by
+ // the width of the control buttons view.
+ available_width -=
+ notification_view()->control_buttons_view_->GetPreferredSize().width();
+#endif
+ const gfx::FontList& font_list =
+ notification_view()->title_view_->font_list();
+
+ // To get the number of characters that fit into one line of text with a
+ // given width, we first get the width of one character.
+ int char_width =
+ gfx::GetStringWidth(base::string16(1, character), font_list);
+
+ // We then assume that multiple of these characters next to each other have
+ // a total width of N * char_width. This is usually a very good estimation,
+ // but based on the platform, it may vary due to font shaping.
+ int characters_per_line = available_width / char_width;
+
+ // These while loops account for any unexpected font shaping and are not
+ // expected to be expensive.
+ while (gfx::GetStringWidth(base::string16(characters_per_line, character),
+ font_list) <= available_width) {
+ characters_per_line++;
+ }
+ while (gfx::GetStringWidth(base::string16(characters_per_line, character),
+ font_list) > available_width) {
+ characters_per_line--;
+ }
+
+ return characters_per_line;
+ }
+
bool IsRemovedAfterIdle(const std::string& notification_id) const {
base::RunLoop().RunUntilIdle();
return !MessageCenter::Get()->FindVisibleNotificationById(notification_id);
@@ -174,7 +221,7 @@ class NotificationViewTest : public views::ViewsTestBase {
void DispatchGesture(const ui::GestureEventDetails& details) {
ui::test::EventGenerator generator(
- notification_view()->GetWidget()->GetNativeWindow());
+ GetRootWindow(notification_view()->GetWidget()));
ui::GestureEvent event(0, 0, 0, ui::EventTimeForNow(), details);
generator.Dispatch(&event);
}
@@ -218,8 +265,7 @@ void NotificationViewTest::SetUp() {
NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"),
base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"),
CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), GURL(),
- NotifierId(NotifierId::APPLICATION, "extension_id"), *data_,
- NULL));
+ NotifierId(NotifierType::APPLICATION, "extension_id"), *data_, NULL));
notification_->set_small_image(CreateTestImage(16, 16));
notification_->set_image(CreateTestImage(320, 240));
@@ -284,6 +330,35 @@ TEST_F(NotificationViewTest, CreateOrUpdateTest) {
EXPECT_TRUE(NULL != notification_view()->icon_view_);
}
+TEST_F(NotificationViewTest, UpdateViewsOrderingTest) {
+ EXPECT_NE(nullptr, notification_view()->title_view_);
+ EXPECT_NE(nullptr, notification_view()->message_view_);
+ EXPECT_EQ(0, notification_view()->top_view_->GetIndexOf(
+ notification_view()->title_view_));
+ EXPECT_EQ(1, notification_view()->top_view_->GetIndexOf(
+ notification_view()->message_view_));
+
+ notification()->set_title(base::string16());
+
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_EQ(nullptr, notification_view()->title_view_);
+ EXPECT_NE(nullptr, notification_view()->message_view_);
+ EXPECT_EQ(0, notification_view()->top_view_->GetIndexOf(
+ notification_view()->message_view_));
+
+ notification()->set_title(base::UTF8ToUTF16("title"));
+
+ notification_view()->CreateOrUpdateViews(*notification());
+
+ EXPECT_NE(nullptr, notification_view()->title_view_);
+ EXPECT_NE(nullptr, notification_view()->message_view_);
+ EXPECT_EQ(0, notification_view()->top_view_->GetIndexOf(
+ notification_view()->title_view_));
+ EXPECT_EQ(1, notification_view()->top_view_->GetIndexOf(
+ notification_view()->message_view_));
+}
+
TEST_F(NotificationViewTest, CreateOrUpdateTestSettingsButton) {
data()->settings_button_handler = SettingsButtonHandler::INLINE;
Notification notification(
@@ -291,7 +366,7 @@ TEST_F(NotificationViewTest, CreateOrUpdateTestSettingsButton) {
base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"),
CreateTestImage(80, 80), base::UTF8ToUTF16("display source"),
GURL("https://hello.com"),
- NotifierId(NotifierId::APPLICATION, "extension_id"), *data(), nullptr);
+ NotifierId(NotifierType::APPLICATION, "extension_id"), *data(), nullptr);
notification_view()->UpdateWithNotification(notification);
EXPECT_TRUE(NULL != notification_view()->title_view_);
@@ -458,16 +533,15 @@ TEST_F(NotificationViewTest, UpdateButtonCountTest) {
EXPECT_EQ(views::Button::STATE_NORMAL,
notification_view()->action_buttons_[1]->state());
+ ui::test::EventGenerator generator(
+ GetRootWindow(notification_view()->GetWidget()));
+
// Now construct a mouse move event 1 pixel inside the boundary of the action
// button.
gfx::Point cursor_location(1, 1);
- views::View::ConvertPointToScreen(notification_view()->action_buttons_[0],
- &cursor_location);
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- ui::EventDispatchDetails details =
- views::test::WidgetTest::GetEventSink(widget())->OnEventFromSource(&move);
- EXPECT_FALSE(details.dispatcher_destroyed);
+ views::View::ConvertPointToTarget(notification_view()->action_buttons_[0],
+ notification_view(), &cursor_location);
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_HOVERED,
notification_view()->action_buttons_[0]->state());
@@ -484,9 +558,8 @@ TEST_F(NotificationViewTest, UpdateButtonCountTest) {
// Now construct a mouse move event 1 pixel outside the boundary of the
// widget.
cursor_location = gfx::Point(-1, -1);
- move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
+ views::View::ConvertPointToScreen(notification_view(), &cursor_location);
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_NORMAL,
notification_view()->action_buttons_[0]->state());
@@ -499,32 +572,30 @@ TEST_F(NotificationViewTest, SettingsButtonTest) {
base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"),
CreateTestImage(80, 80), base::UTF8ToUTF16("display source"),
GURL("https://hello.com"),
- NotifierId(NotifierId::APPLICATION, "extension_id"), *data(), nullptr);
+ NotifierId(NotifierType::APPLICATION, "extension_id"), *data(), nullptr);
notification_view()->UpdateWithNotification(notf);
widget()->Show();
EXPECT_TRUE(NULL != GetSettingsButton());
EXPECT_EQ(views::Button::STATE_NORMAL, GetSettingsButton()->state());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
+
// Now construct a mouse move event 1 pixel inside the boundary of the action
// button.
gfx::Point cursor_location(1, 1);
- views::View::ConvertPointToScreen(GetSettingsButton(), &cursor_location);
- ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
- ui::EventDispatchDetails details =
- views::test::WidgetTest::GetEventSink(widget())->OnEventFromSource(&move);
- EXPECT_FALSE(details.dispatcher_destroyed);
+ views::View::ConvertPointToTarget(GetSettingsButton(), notification_view(),
+ &cursor_location);
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_HOVERED, GetSettingsButton()->state());
// Now construct a mouse move event 1 pixel outside the boundary of the
// widget.
cursor_location = gfx::Point(-1, -1);
- move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location,
- ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
- widget()->OnMouseEvent(&move);
+ views::View::ConvertPointToTarget(GetSettingsButton(), notification_view(),
+ &cursor_location);
+ generator.MoveMouseTo(cursor_location);
EXPECT_EQ(views::Button::STATE_NORMAL, GetSettingsButton()->state());
}
@@ -544,6 +615,50 @@ TEST_F(NotificationViewTest, ViewOrderingTest) {
CheckVerticalOrderInNotification();
}
+TEST_F(NotificationViewTest, TitleWrappingTest) {
+ data()->settings_button_handler = SettingsButtonHandler::INLINE;
+ Notification notf(
+ NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"),
+ base::UTF8ToUTF16(""), base::UTF8ToUTF16("message"),
+ CreateTestImage(80, 80), base::UTF8ToUTF16("display source"),
+ GURL("https://hello.com"),
+ NotifierId(NotifierType::APPLICATION, "extension_id"), *data(), nullptr);
+
+ const base::char16 character = '1';
+ const int characters_per_line = GetTitleCharactersPerLine(character);
+
+ // Test a very short title
+ notf.set_title(base::string16(1, character));
+ notification_view()->UpdateWithNotification(notf);
+ int one_line_height = GetTitleHeight();
+
+ // Test a title that exactly fits into one line
+ notf.set_title(base::string16(characters_per_line, character));
+ notification_view()->UpdateWithNotification(notf);
+ EXPECT_EQ(one_line_height, GetTitleHeight());
+
+ // Test a title that breaks into 2 lines with only 1 char in the second line
+ notf.set_title(base::string16(characters_per_line + 1, character));
+ notification_view()->UpdateWithNotification(notf);
+ int two_line_height = GetTitleHeight();
+ EXPECT_GT(two_line_height, one_line_height);
+
+ // Test a title that clearly breaks into 2 lines
+ notf.set_title(base::string16(characters_per_line + 10, character));
+ notification_view()->UpdateWithNotification(notf);
+ EXPECT_EQ(two_line_height, GetTitleHeight());
+
+ // Test a title that fits exactly into 2 lines
+ notf.set_title(base::string16(characters_per_line * 2, character));
+ notification_view()->UpdateWithNotification(notf);
+ EXPECT_EQ(two_line_height, GetTitleHeight());
+
+ // Test a title that would break into 3 lines but has ellipsis in the 2nd line
+ notf.set_title(base::string16(characters_per_line * 2 + 1, character));
+ notification_view()->UpdateWithNotification(notf);
+ EXPECT_EQ(two_line_height, GetTitleHeight());
+}
+
TEST_F(NotificationViewTest, FormatContextMessageTest) {
const std::string kRegularContextText = "Context Text";
const std::string kVeryLongContextText =
@@ -617,7 +732,14 @@ TEST_F(NotificationViewTest, FormatContextMessageTest) {
EXPECT_TRUE(result_utf8.find("hello") == std::string::npos);
}
-TEST_F(NotificationViewTest, SlideOut) {
+// Synthetic scroll events are not supported on Mac in the views
+// test framework.
+#if defined(OS_MACOSX)
+#define MAYBE_SlideOut DISABLED_SlideOut
+#else
+#define MAYBE_SlideOut SlideOut
+#endif
+TEST_F(NotificationViewTest, MAYBE_SlideOut) {
ui::ScopedAnimationDurationScaleMode zero_duration_scope(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
@@ -640,7 +762,12 @@ TEST_F(NotificationViewTest, SlideOut) {
EXPECT_TRUE(IsRemovedAfterIdle(notification_id));
}
-TEST_F(NotificationViewTest, SlideOutNested) {
+#if defined(OS_MACOSX)
+#define MAYBE_SlideOutNested DISABLED_SlideOutNested
+#else
+#define MAYBE_SlideOutNested SlideOutNested
+#endif
+TEST_F(NotificationViewTest, MAYBE_SlideOutNested) {
ui::ScopedAnimationDurationScaleMode zero_duration_scope(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
diff --git a/chromium/ui/message_center/views/padded_button.h b/chromium/ui/message_center/views/padded_button.h
index 2d9c6b0a1d2..3c48a1f6c6e 100644
--- a/chromium/ui/message_center/views/padded_button.h
+++ b/chromium/ui/message_center/views/padded_button.h
@@ -26,7 +26,7 @@ class MESSAGE_CENTER_EXPORT PaddedButton : public views::ImageButton {
PaddedButton(views::ButtonListener* listener);
~PaddedButton() override = default;
- // Overridden from InkDropHostView
+ // views::ImageButton:
std::unique_ptr<views::InkDrop> CreateInkDrop() override;
std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
diff --git a/chromium/ui/message_center/views/slide_out_controller.cc b/chromium/ui/message_center/views/slide_out_controller.cc
index f338931e7fc..28c5043570b 100644
--- a/chromium/ui/message_center/views/slide_out_controller.cc
+++ b/chromium/ui/message_center/views/slide_out_controller.cc
@@ -44,12 +44,13 @@ void SlideOutController::OnGestureEvent(ui::GestureEvent* event) {
if (mode_ == SlideMode::FULL &&
fabsf(event->details().velocity_x()) > kFlingThresholdForClose) {
SlideOutAndClose(event->details().velocity_x());
+ delegate_->OnSlideChanged(false);
event->StopPropagation();
return;
}
CaptureControlOpenState();
RestoreVisualState();
- delegate_->OnSlideChanged();
+ delegate_->OnSlideChanged(false);
return;
}
@@ -70,6 +71,7 @@ void SlideOutController::OnGestureEvent(ui::GestureEvent* event) {
default:
NOTREACHED();
}
+ delegate_->OnSlideStarted();
} else if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
// The scroll-update events include the incremental scroll amount.
gesture_amount_ += event->details().scroll_x();
@@ -98,23 +100,25 @@ void SlideOutController::OnGestureEvent(ui::GestureEvent* event) {
break;
}
- layer->SetOpacity(opacity);
+ SetOpacityIfNecessary(opacity);
gfx::Transform transform;
transform.Translate(scroll_amount, 0.0);
layer->SetTransform(transform);
+ delegate_->OnSlideChanged(true);
} else if (event->type() == ui::ET_GESTURE_SCROLL_END) {
float scrolled_ratio = fabsf(gesture_amount_) / width;
if (mode_ == SlideMode::FULL &&
scrolled_ratio >= scroll_amount_for_closing_notification / width) {
SlideOutAndClose(gesture_amount_);
+ delegate_->OnSlideChanged(false);
event->StopPropagation();
return;
}
CaptureControlOpenState();
RestoreVisualState();
+ delegate_->OnSlideChanged(false);
}
- delegate_->OnSlideChanged();
event->SetHandled();
}
@@ -125,6 +129,7 @@ void SlideOutController::RestoreVisualState() {
ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(kSwipeRestoreDurationMS));
+ settings.AddObserver(this);
gfx::Transform transform;
switch (control_open_state_) {
case SwipeControlOpenState::CLOSED:
@@ -137,14 +142,23 @@ void SlideOutController::RestoreVisualState() {
transform.Translate(swipe_control_width_, 0);
break;
}
+
+ if (layer->transform() == transform && opacity_ == 1.f) {
+ // Nothing are changed and no animation starts.
+ return;
+ }
+
+ // In this case, animation starts. OnImplicitAnimationsCompleted will be
+ // called just after the animation finishes.
layer->SetTransform(transform);
- layer->SetOpacity(1.f);
+ SetOpacityIfNecessary(1.f);
+ delegate_->OnSlideChanged(true);
}
void SlideOutController::SlideOutAndClose(int direction) {
ui::Layer* layer = delegate_->GetSlideOutLayer();
const int kSwipeOutTotalDurationMS = 150;
- int swipe_out_duration = kSwipeOutTotalDurationMS * layer->opacity();
+ int swipe_out_duration = kSwipeOutTotalDurationMS * opacity_;
ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(swipe_out_duration));
@@ -153,13 +167,25 @@ void SlideOutController::SlideOutAndClose(int direction) {
gfx::Transform transform;
int width = layer->bounds().width();
transform.Translate(direction < 0 ? -width : width, 0.0);
+
+ // An animation starts. OnImplicitAnimationsCompleted will be called just
+ // after the animation finishes.
layer->SetTransform(transform);
- layer->SetOpacity(0.f);
- delegate_->OnSlideChanged();
+ SetOpacityIfNecessary(0.f);
+ delegate_->OnSlideChanged(true);
+}
+
+void SlideOutController::SetOpacityIfNecessary(float opacity) {
+ if (update_opacity_)
+ delegate_->GetSlideOutLayer()->SetOpacity(opacity);
+ opacity_ = opacity;
}
void SlideOutController::OnImplicitAnimationsCompleted() {
- delegate_->OnSlideChanged();
+ if (opacity_ > 0)
+ return;
+
+ // Call Delegate::OnSlideOut() if this animation came from SlideOutAndClose().
// OnImplicitAnimationsCompleted is called from BeginMainFrame, so we should
// delay operation that might result in deletion of LayerTreeHost.
@@ -169,12 +195,9 @@ void SlideOutController::OnImplicitAnimationsCompleted() {
base::BindOnce(&Delegate::OnSlideOut, base::Unretained(delegate_)));
}
-void SlideOutController::EnableSwipeControl(int button_count) {
- DCHECK(button_count > 0);
- swipe_control_width_ =
- kSwipeControlButtonSize * button_count +
- kSwipeControlButtonHorizontalMargin * (button_count + 1);
- has_swipe_control_ = true;
+void SlideOutController::SetSwipeControlWidth(int swipe_control_width) {
+ swipe_control_width_ = swipe_control_width;
+ has_swipe_control_ = (swipe_control_width != 0);
}
void SlideOutController::CloseSwipeControl() {
diff --git a/chromium/ui/message_center/views/slide_out_controller.h b/chromium/ui/message_center/views/slide_out_controller.h
index 61048583093..1a1ec5cb49a 100644
--- a/chromium/ui/message_center/views/slide_out_controller.h
+++ b/chromium/ui/message_center/views/slide_out_controller.h
@@ -30,8 +30,12 @@ class MESSAGE_CENTER_EXPORT SlideOutController
// Returns the layer for slide operations.
virtual ui::Layer* GetSlideOutLayer() = 0;
- // Called when a slide starts, ends, or is updated.
- virtual void OnSlideChanged() = 0;
+ // Called when a manual slide starts.
+ virtual void OnSlideStarted() {}
+
+ // Called when a manual slide updates or ends. The argument is true if the
+ // slide starts or in progress, false if it ends.
+ virtual void OnSlideChanged(bool in_progress) = 0;
// Called when user intends to close the View by sliding it out.
virtual void OnSlideOut() = 0;
@@ -40,7 +44,13 @@ class MESSAGE_CENTER_EXPORT SlideOutController
SlideOutController(ui::EventTarget* target, Delegate* delegate);
~SlideOutController() override;
- void set_slide_mode(SlideMode mode) { mode_ = mode; }
+ void set_update_opacity(bool update_opacity) {
+ update_opacity_ = update_opacity;
+ }
+ void set_slide_mode(SlideMode mode) {
+ // TODO(yoshiki): Close the slide when the slide mode sets to NO_SLIDE.
+ mode_ = mode;
+ }
float gesture_amount() const { return gesture_amount_; }
SlideMode mode() const { return mode_; }
@@ -50,9 +60,10 @@ class MESSAGE_CENTER_EXPORT SlideOutController
// ui::ImplicitAnimationObserver
void OnImplicitAnimationsCompleted() override;
- // Enables the swipe control. Buttons will appea behind the view as user
- // slides it partially and it's kept open after the gesture.
- void EnableSwipeControl(int button_count);
+ // Enables the swipe control with specifying the width of buttons. Buttons
+ // will appear behind the view as user slides it partially and it's kept open
+ // after the gesture.
+ void SetSwipeControlWidth(int swipe_control_width);
float GetGestureAmount() const { return gesture_amount_; }
// Moves slide back to the center position to closes the swipe control.
@@ -73,6 +84,9 @@ class MESSAGE_CENTER_EXPORT SlideOutController
// |direction| indicates which way the slide occurs.
void SlideOutAndClose(int direction);
+ // Sets the opacity of the slide out layer if |update_opacity_| is true.
+ void SetOpacityIfNecessary(float opacity);
+
ui::ScopedTargetHandler target_handling_;
Delegate* delegate_;
@@ -95,6 +109,12 @@ class MESSAGE_CENTER_EXPORT SlideOutController
// Changed only when |mode_| is FULL and |has_swipe_control_| is true.
SwipeControlOpenState control_open_state_ = SwipeControlOpenState::CLOSED;
+ // If false, it doesn't update the opacity.
+ bool update_opacity_ = true;
+
+ // Last opacity set by SetOpacityIfNecessary.
+ float opacity_ = 1.0;
+
DISALLOW_COPY_AND_ASSIGN(SlideOutController);
};
diff --git a/chromium/ui/message_center/views/slide_out_controller_unittest.cc b/chromium/ui/message_center/views/slide_out_controller_unittest.cc
new file mode 100644
index 00000000000..ae2348fc82f
--- /dev/null
+++ b/chromium/ui/message_center/views/slide_out_controller_unittest.cc
@@ -0,0 +1,121 @@
+// 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/message_center/views/slide_out_controller.h"
+
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+
+namespace message_center {
+
+class SlideOutControllerDelegate : public SlideOutController::Delegate {
+ public:
+ explicit SlideOutControllerDelegate(views::View* target) : target_(target) {}
+ virtual ~SlideOutControllerDelegate() = default;
+
+ ui::Layer* GetSlideOutLayer() override { return target_->layer(); }
+
+ void OnSlideStarted() override { ++slide_started_count_; }
+
+ void OnSlideChanged(bool in_progress) override {
+ slide_changed_last_value_ = in_progress;
+ ++slide_changed_count_;
+ }
+
+ void OnSlideOut() override { ++slide_out_count_; }
+
+ base::Optional<bool> slide_changed_last_value_;
+ int slide_started_count_ = 0;
+ int slide_changed_count_ = 0;
+ int slide_out_count_ = 0;
+
+ private:
+ views::View* const target_;
+};
+
+class SlideOutControllerTest : public views::ViewsTestBase {
+ public:
+ SlideOutControllerTest() = default;
+ ~SlideOutControllerTest() override = default;
+
+ void SetUp() override {
+ views::ViewsTestBase::SetUp();
+
+ widget_ = std::make_unique<views::Widget>();
+
+ views::Widget::InitParams params =
+ CreateParams(views::Widget::InitParams::TYPE_POPUP);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(50, 50, 650, 650);
+ widget_->Init(params);
+ views::View* root = widget_->GetRootView();
+
+ views::View* target_ = new views::View();
+ target_->SetPaintToLayer(ui::LAYER_TEXTURED);
+ target_->SetSize(gfx::Size(50, 50));
+
+ root->AddChildView(target_);
+ widget_->Show();
+
+ delegate_ = std::make_unique<SlideOutControllerDelegate>(target_);
+ slide_out_controller_ =
+ std::make_unique<SlideOutController>(target_, delegate_.get());
+ }
+
+ void TearDown() override {
+ slide_out_controller_.reset();
+ delegate_.reset();
+ widget_.reset();
+
+ views::ViewsTestBase::TearDown();
+ }
+
+ protected:
+ SlideOutController* slide_out_controller() {
+ return slide_out_controller_.get();
+ }
+
+ SlideOutControllerDelegate* delegate() { return delegate_.get(); }
+
+ private:
+ std::unique_ptr<views::Widget> widget_;
+ std::unique_ptr<SlideOutController> slide_out_controller_;
+ std::unique_ptr<SlideOutControllerDelegate> delegate_;
+};
+
+TEST_F(SlideOutControllerTest, OnGestureEventAndDelegate) {
+ ui::GestureEvent scroll_begin(
+ 0, 0, ui::EF_NONE,
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(1),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
+ slide_out_controller()->OnGestureEvent(&scroll_begin);
+
+ EXPECT_EQ(1, delegate()->slide_started_count_);
+ EXPECT_EQ(0, delegate()->slide_changed_count_);
+ EXPECT_EQ(0, delegate()->slide_out_count_);
+
+ ui::GestureEvent scroll_update(
+ 0, 0, ui::EF_NONE,
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(2),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE));
+ slide_out_controller()->OnGestureEvent(&scroll_update);
+
+ EXPECT_EQ(1, delegate()->slide_started_count_);
+ EXPECT_EQ(1, delegate()->slide_changed_count_);
+ EXPECT_TRUE(delegate()->slide_changed_last_value_.value());
+ EXPECT_EQ(0, delegate()->slide_out_count_);
+
+ ui::GestureEvent scroll_end(
+ 0, 0, ui::EF_NONE,
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(3),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
+ slide_out_controller()->OnGestureEvent(&scroll_end);
+
+ EXPECT_EQ(1, delegate()->slide_started_count_);
+ EXPECT_EQ(2, delegate()->slide_changed_count_);
+ EXPECT_FALSE(delegate()->slide_changed_last_value_.value());
+ EXPECT_EQ(0, delegate()->slide_out_count_);
+}
+
+} // namespace message_center
diff --git a/chromium/ui/native_theme/common_theme.cc b/chromium/ui/native_theme/common_theme.cc
index 6b4f08797ba..74c8e5cb48e 100644
--- a/chromium/ui/native_theme/common_theme.cc
+++ b/chromium/ui/native_theme/common_theme.cc
@@ -18,6 +18,22 @@ namespace ui {
SkColor GetAuraColor(NativeTheme::ColorId color_id,
const NativeTheme* base_theme) {
+ // TODO(lgrey): High contrast dark mode.
+ if (base_theme->SystemDarkModeEnabled()) {
+ switch (color_id) {
+ case NativeTheme::kColorId_LabelEnabledColor:
+ case NativeTheme::kColorId_TextfieldDefaultColor:
+ return SK_ColorWHITE;
+ case NativeTheme::kColorId_UnfocusedBorderColor:
+ return gfx::kGoogleGrey900;
+ case NativeTheme::kColorId_ButtonEnabledColor:
+ case NativeTheme::kColorId_ButtonHoverColor:
+ return gfx::kGoogleGrey200;
+ default:
+ break;
+ }
+ }
+
// High contrast overrides the normal colors for certain ColorIds to be much
// darker or lighter.
if (base_theme->UsesHighContrastColors()) {
@@ -90,14 +106,6 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
case NativeTheme::kColorId_ButtonEnabledColor:
case NativeTheme::kColorId_ButtonHoverColor:
return kButtonEnabledColor;
- // TODO(estade): remove the BlueButton colors.
- case NativeTheme::kColorId_BlueButtonEnabledColor:
- case NativeTheme::kColorId_BlueButtonDisabledColor:
- case NativeTheme::kColorId_BlueButtonPressedColor:
- case NativeTheme::kColorId_BlueButtonHoverColor:
- return SK_ColorWHITE;
- case NativeTheme::kColorId_BlueButtonShadowColor:
- return SkColorSetRGB(0x53, 0x8C, 0xEA);
case NativeTheme::kColorId_ProminentButtonColor:
return gfx::kGoogleBlue500;
case NativeTheme::kColorId_TextOnProminentButtonColor:
@@ -127,6 +135,12 @@ SkColor GetAuraColor(NativeTheme::ColorId color_id,
return kDisabledTextColor;
case NativeTheme::kColorId_MenuItemMinorTextColor:
return SkColorSetA(SK_ColorBLACK, 0x89);
+ case NativeTheme::kColorId_HighlightedMenuItemBackgroundColor:
+ return gfx::kGoogleGrey050;
+ case NativeTheme::kColorId_HighlightedMenuItemForegroundColor:
+ return gfx::kGoogleGrey900;
+ case NativeTheme::kColorId_FocusedHighlightedMenuItemBackgroundColor:
+ return gfx::kGoogleGrey200;
// Label
case NativeTheme::kColorId_LabelEnabledColor:
diff --git a/chromium/ui/native_theme/native_theme.cc b/chromium/ui/native_theme/native_theme.cc
index 966131853bd..d14f8051798 100644
--- a/chromium/ui/native_theme/native_theme.cc
+++ b/chromium/ui/native_theme/native_theme.cc
@@ -6,6 +6,8 @@
#include <cstring>
+#include "base/command_line.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/native_theme/native_theme_observer.h"
namespace ui {
@@ -47,4 +49,9 @@ NativeTheme::NativeTheme()
NativeTheme::~NativeTheme() {}
+bool NativeTheme::SystemDarkModeEnabled() const {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kForceDarkMode);
+}
+
} // namespace ui
diff --git a/chromium/ui/native_theme/native_theme.h b/chromium/ui/native_theme/native_theme.h
index b2284ad5da7..2796e42e1e9 100644
--- a/chromium/ui/native_theme/native_theme.h
+++ b/chromium/ui/native_theme/native_theme.h
@@ -303,11 +303,6 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_ButtonDisabledColor,
kColorId_ButtonHoverColor,
kColorId_ButtonPressedShade,
- kColorId_BlueButtonEnabledColor,
- kColorId_BlueButtonDisabledColor,
- kColorId_BlueButtonPressedColor,
- kColorId_BlueButtonHoverColor,
- kColorId_BlueButtonShadowColor,
kColorId_ProminentButtonColor,
kColorId_TextOnProminentButtonColor,
// MenuItem
@@ -321,6 +316,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
kColorId_MenuSeparatorColor,
kColorId_MenuBackgroundColor,
kColorId_MenuBorderColor,
+ kColorId_HighlightedMenuItemBackgroundColor,
+ kColorId_HighlightedMenuItemForegroundColor,
+ kColorId_FocusedHighlightedMenuItemBackgroundColor,
// Label
kColorId_LabelEnabledColor,
kColorId_LabelDisabledColor,
@@ -408,6 +406,9 @@ class NATIVE_THEME_EXPORT NativeTheme {
// system accessibility settings and the system theme.
virtual bool UsesHighContrastColors() const = 0;
+ // Whether OS-level dark mode (as in macOS Mojave or Windows 10) is enabled.
+ virtual bool SystemDarkModeEnabled() const;
+
protected:
NativeTheme();
virtual ~NativeTheme();
diff --git a/chromium/ui/native_theme/native_theme_aura.cc b/chromium/ui/native_theme/native_theme_aura.cc
index 4409bb629bb..a6cb8b47139 100644
--- a/chromium/ui/native_theme/native_theme_aura.cc
+++ b/chromium/ui/native_theme/native_theme_aura.cc
@@ -13,7 +13,6 @@
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
#include "ui/base/layout.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
diff --git a/chromium/ui/native_theme/native_theme_dark_aura.cc b/chromium/ui/native_theme/native_theme_dark_aura.cc
index 6ab77cd84e7..712fc0d96ce 100644
--- a/chromium/ui/native_theme/native_theme_dark_aura.cc
+++ b/chromium/ui/native_theme/native_theme_dark_aura.cc
@@ -82,11 +82,6 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
case kColorId_UnfocusedBorderColor:
case kColorId_ButtonDisabledColor:
case kColorId_ButtonHoverColor:
- case kColorId_BlueButtonEnabledColor:
- case kColorId_BlueButtonDisabledColor:
- case kColorId_BlueButtonPressedColor:
- case kColorId_BlueButtonHoverColor:
- case kColorId_BlueButtonShadowColor:
case kColorId_EnabledMenuItemForegroundColor:
case kColorId_DisabledMenuItemForegroundColor:
case kColorId_SelectedMenuItemForegroundColor:
@@ -97,6 +92,9 @@ SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
case kColorId_MenuSeparatorColor:
case kColorId_MenuBackgroundColor:
case kColorId_MenuBorderColor:
+ case kColorId_HighlightedMenuItemBackgroundColor:
+ case kColorId_HighlightedMenuItemForegroundColor:
+ case kColorId_FocusedHighlightedMenuItemBackgroundColor:
case kColorId_LinkDisabled:
case kColorId_TabBottomBorder:
case kColorId_TabTitleColorActive:
diff --git a/chromium/ui/native_theme/native_theme_mac.h b/chromium/ui/native_theme/native_theme_mac.h
index 83007af4466..58bd97b4b81 100644
--- a/chromium/ui/native_theme/native_theme_mac.h
+++ b/chromium/ui/native_theme/native_theme_mac.h
@@ -47,6 +47,7 @@ class NATIVE_THEME_EXPORT NativeThemeMac : public NativeThemeBase {
const gfx::Rect& rect,
const MenuItemExtraParams& menu_item) const override;
bool UsesHighContrastColors() const override;
+ bool SystemDarkModeEnabled() const override;
// Paints the styled button shape used for default controls on Mac. The basic
// style is used for dialog buttons, comboboxes, and tabbed pane tabs.
diff --git a/chromium/ui/native_theme/native_theme_mac.mm b/chromium/ui/native_theme/native_theme_mac.mm
index 17036c74f8f..4f48f0c4178 100644
--- a/chromium/ui/native_theme/native_theme_mac.mm
+++ b/chromium/ui/native_theme/native_theme_mac.mm
@@ -25,6 +25,9 @@
namespace {
const SkColor kMenuPopupBackgroundColor = SK_ColorWHITE;
+// TODO(crbug.com/893598): Finalize dark mode color.
+const SkColor kMenuPopupBackgroundColorDarkMode =
+ SkColorSetRGB(0x2B, 0x2B, 0x2B);
// Helper to make indexing an array by an enum class easier.
template <class KEY, class VALUE>
@@ -123,7 +126,10 @@ SkColor NativeThemeMac::GetSystemColor(ColorId color_id) const {
case kColorId_FocusedMenuItemBackgroundColor:
return UsesHighContrastColors() ? SK_ColorDKGRAY : gfx::kGoogleGrey200;
case kColorId_MenuBackgroundColor:
- return kMenuPopupBackgroundColor;
+ case kColorId_BubbleBackground:
+ case kColorId_DialogBackground:
+ return SystemDarkModeEnabled() ? kMenuPopupBackgroundColorDarkMode
+ : kMenuPopupBackgroundColor;
case kColorId_MenuSeparatorColor:
return UsesHighContrastColors() ? SK_ColorBLACK
: SkColorSetA(SK_ColorBLACK, 0x26);
@@ -160,7 +166,7 @@ void NativeThemeMac::PaintMenuPopupBackground(
const MenuBackgroundExtraParams& menu_background) const {
cc::PaintFlags flags;
flags.setAntiAlias(true);
- flags.setColor(kMenuPopupBackgroundColor);
+ flags.setColor(GetSystemColor(kColorId_MenuBackgroundColor));
const SkScalar radius = SkIntToScalar(menu_background.corner_radius);
SkRect rect = gfx::RectToSkRect(gfx::Rect(size));
canvas->drawRoundRect(rect, radius, radius, flags);
@@ -196,6 +202,17 @@ bool NativeThemeMac::UsesHighContrastColors() const {
return false;
}
+bool NativeThemeMac::SystemDarkModeEnabled() const {
+ if (@available(macOS 10.14, *)) {
+ NSAppearanceName appearance =
+ [[NSApp effectiveAppearance] bestMatchFromAppearancesWithNames:@[
+ NSAppearanceNameAqua, NSAppearanceNameDarkAqua
+ ]];
+ return [appearance isEqual:NSAppearanceNameDarkAqua];
+ }
+ return NativeThemeBase::SystemDarkModeEnabled();
+}
+
NativeThemeMac::NativeThemeMac() {
}
diff --git a/chromium/ui/ozone/common/gpu/ozone_gpu_message_generator.cc b/chromium/ui/ozone/common/gpu/ozone_gpu_message_generator.cc
index d3032ed706a..d2f07ee8ab1 100644
--- a/chromium/ui/ozone/common/gpu/ozone_gpu_message_generator.cc
+++ b/chromium/ui/ozone/common/gpu/ozone_gpu_message_generator.cc
@@ -10,10 +10,6 @@
#include "ipc/struct_constructor_macros.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_generator.h"
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "ui/ozone/common/gpu/ozone_gpu_message_generator.h"
-
// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC {
diff --git a/chromium/ui/ozone/common/linux/BUILD.gn b/chromium/ui/ozone/common/linux/BUILD.gn
index 0d62943e901..2bf3481ffe8 100644
--- a/chromium/ui/ozone/common/linux/BUILD.gn
+++ b/chromium/ui/ozone/common/linux/BUILD.gn
@@ -7,18 +7,29 @@ import("//ui/ozone/ozone.gni")
assert(ozone_platform_gbm || ozone_platform_wayland)
-source_set("linux") {
+source_set("drm") {
sources = [
"drm_util_linux.cc",
"drm_util_linux.h",
+ ]
+
+ deps = [
+ "//base:base",
+ "//build/config/linux/libdrm",
+ "//ui/gfx:buffer_types",
+ ]
+}
+
+source_set("gbm") {
+ sources = [
"gbm_buffer.h",
"gbm_device.h",
"gbm_wrapper.cc",
]
deps = [
+ ":drm",
"//base:base",
- "//third_party/libdrm",
"//third_party/minigbm",
"//ui/gfx:buffer_types",
"//ui/gfx:memory_buffer",
diff --git a/chromium/ui/ozone/common/linux/drm_util_linux.cc b/chromium/ui/ozone/common/linux/drm_util_linux.cc
index b9a26887dff..48648b703d1 100644
--- a/chromium/ui/ozone/common/linux/drm_util_linux.cc
+++ b/chromium/ui/ozone/common/linux/drm_util_linux.cc
@@ -75,19 +75,19 @@ gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format) {
}
bool IsValidBufferFormat(uint32_t current_format) {
- switch (GetBufferFormatFromFourCCFormat(current_format)) {
- case gfx::BufferFormat::R_8:
- case gfx::BufferFormat::RG_88:
- case gfx::BufferFormat::RGBA_8888:
- case gfx::BufferFormat::RGBX_8888:
- case gfx::BufferFormat::BGRA_8888:
- case gfx::BufferFormat::BGRX_8888:
- case gfx::BufferFormat::BGRX_1010102:
- case gfx::BufferFormat::RGBX_1010102:
- case gfx::BufferFormat::BGR_565:
- case gfx::BufferFormat::UYVY_422:
- case gfx::BufferFormat::YUV_420_BIPLANAR:
- case gfx::BufferFormat::YVU_420:
+ switch (current_format) {
+ case DRM_FORMAT_R8:
+ case DRM_FORMAT_GR88:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_YVU420:
return true;
default:
return false;
diff --git a/chromium/ui/ozone/common/linux/gbm_wrapper.cc b/chromium/ui/ozone/common/linux/gbm_wrapper.cc
index ba55b0e5685..15efd7bfeb3 100644
--- a/chromium/ui/ozone/common/linux/gbm_wrapper.cc
+++ b/chromium/ui/ozone/common/linux/gbm_wrapper.cc
@@ -15,6 +15,14 @@
namespace gbm_wrapper {
+namespace {
+
+// Temporary defines while we migrate to GBM_BO_IMPORT_FD_MODIFIER.
+#define GBM_BO_IMPORT_FD_PLANAR_5504 0x5504
+#define GBM_BO_IMPORT_FD_PLANAR_5505 0x5505
+
+} // namespace
+
class Buffer final : public ui::GbmBuffer {
public:
Buffer(struct gbm_bo* bo,
@@ -238,10 +246,17 @@ class Device final : public ui::GbmDevice {
// The fd passed to gbm_bo_import is not ref-counted and need to be
// kept open for the lifetime of the buffer.
- bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_PLANAR, &fd_data, gbm_flags);
+ //
+ // See the comment regarding the GBM_BO_IMPORT_FD_PLANAR_550X above.
+ bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_PLANAR_5505, &fd_data,
+ gbm_flags);
if (!bo) {
- LOG(ERROR) << "nullptr returned from gbm_bo_import";
- return nullptr;
+ bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_PLANAR_5504, &fd_data,
+ gbm_flags);
+ if (!bo) {
+ LOG(ERROR) << "nullptr returned from gbm_bo_import";
+ return nullptr;
+ }
}
return std::make_unique<Buffer>(bo, format, gbm_flags, planes[0].modifier,
diff --git a/chromium/ui/ozone/common/stub_client_native_pixmap_factory.cc b/chromium/ui/ozone/common/stub_client_native_pixmap_factory.cc
index 93e59631666..f5b33302848 100644
--- a/chromium/ui/ozone/common/stub_client_native_pixmap_factory.cc
+++ b/chromium/ui/ozone/common/stub_client_native_pixmap_factory.cc
@@ -15,10 +15,6 @@ class StubClientNativePixmapFactory : public gfx::ClientNativePixmapFactory {
~StubClientNativePixmapFactory() override {}
// ClientNativePixmapFactory:
- bool IsConfigurationSupported(gfx::BufferFormat format,
- gfx::BufferUsage usage) const override {
- return false;
- }
std::unique_ptr<gfx::ClientNativePixmap> ImportFromHandle(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size,
diff --git a/chromium/ui/ozone/demo/demo_window.cc b/chromium/ui/ozone/demo/demo_window.cc
index 38deff0067c..0915cd07bfe 100644
--- a/chromium/ui/ozone/demo/demo_window.cc
+++ b/chromium/ui/ozone/demo/demo_window.cc
@@ -16,7 +16,9 @@
#if defined(OS_FUCHSIA)
#include <fuchsia/ui/policy/cpp/fidl.h>
+#include <lib/zx/eventpair.h>
#include "base/fuchsia/component_context.h"
+#include "base/fuchsia/fuchsia_logging.h"
#endif
namespace ui {
@@ -31,19 +33,22 @@ DemoWindow::DemoWindow(WindowManager* window_manager,
properties.bounds = bounds;
#if defined(OS_FUCHSIA)
- // When using Scenic Ozone platform we need to supply a ViewOwner request to
- // the window. This is not necessary when using the headless ozone platform.
+ // When using Scenic Ozone platform we need to supply a view_token to the
+ // window. This is not necessary when using the headless ozone platform.
if (ui::OzonePlatform::GetInstance()
->GetPlatformProperties()
- .needs_view_owner_request) {
- // Initialize view_owner_request for the new instance.
- fidl::InterfaceHandle<fuchsia::ui::viewsv1token::ViewOwner> view_owner;
- properties.view_owner_request = view_owner.NewRequest();
+ .needs_view_token) {
+ // Create view_token and view_holder_token.
+ zx::eventpair view_holder_token;
+ zx_status_t status = zx::eventpair::create(
+ /*options=*/0, &properties.view_token, &view_holder_token);
+ ZX_CHECK(status == ZX_OK, status) << "zx_eventpair_create";
// Request Presenter to show the view full-screen.
auto presenter = base::fuchsia::ComponentContext::GetDefault()
->ConnectToService<fuchsia::ui::policy::Presenter>();
- presenter->Present(std::move(view_owner), nullptr);
+
+ presenter->Present2(std::move(view_holder_token), nullptr);
}
#endif
diff --git a/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc b/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
index 4aa44c770ba..848098361af 100644
--- a/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
+++ b/chromium/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
@@ -36,12 +36,6 @@ class ClientNativePixmapCast : public gfx::ClientNativePixmap {
class ClientNativePixmapFactoryCast : public gfx::ClientNativePixmapFactory {
public:
// ClientNativePixmapFactoryCast implementation:
- bool IsConfigurationSupported(gfx::BufferFormat format,
- gfx::BufferUsage usage) const override {
- return format == gfx::BufferFormat::BGRA_8888 &&
- usage == gfx::BufferUsage::SCANOUT;
- }
-
std::unique_ptr<gfx::ClientNativePixmap> ImportFromHandle(
const gfx::NativePixmapHandle& handle,
const gfx::Size& size,
diff --git a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc
index 217b28c475a..594d0e63ccb 100644
--- a/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc
+++ b/chromium/ui/ozone/platform/cast/ozone_platform_cast.cc
@@ -102,6 +102,11 @@ class OzonePlatformCast : public OzonePlatform {
// On Cast platform the display is initialized by low-level non-Ozone code.
return nullptr;
}
+ bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage) const override {
+ return format == gfx::BufferFormat::BGRA_8888 &&
+ usage == gfx::BufferUsage::SCANOUT;
+ }
void InitializeUI(const InitParams& params) override {
device_manager_ = CreateDeviceManager();
diff --git a/chromium/ui/ozone/platform/drm/BUILD.gn b/chromium/ui/ozone/platform/drm/BUILD.gn
index e1bfe916873..5af8744a033 100644
--- a/chromium/ui/ozone/platform/drm/BUILD.gn
+++ b/chromium/ui/ozone/platform/drm/BUILD.gn
@@ -3,8 +3,8 @@
# found in the LICENSE file.
import("//build/config/linux/pkg_config.gni")
-import("//ui/ozone/ozone.gni")
import("//gpu/vulkan/features.gni")
+import("//ui/ozone/ozone.gni")
visibility = [ "//ui/ozone/*" ]
@@ -120,13 +120,13 @@ source_set("gbm") {
deps = [
"//base",
+ "//build/config/linux/libdrm",
"//gpu/vulkan:buildflags",
"//ipc",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//services/ws/public/mojom:constants",
"//skia",
- "//third_party/libdrm",
"//third_party/libsync",
"//third_party/minigbm",
"//ui/base",
@@ -144,7 +144,8 @@ source_set("gbm") {
"//ui/gl",
"//ui/ozone:ozone_base",
"//ui/ozone/common",
- "//ui/ozone/common/linux",
+ "//ui/ozone/common/linux:drm",
+ "//ui/ozone/common/linux:gbm",
"//ui/ozone/public/interfaces",
"//ui/platform_window",
]
@@ -185,13 +186,14 @@ source_set("gbm_unittests") {
deps = [
":gbm",
"//base/test:test_support",
+ "//build/config/linux/libdrm",
"//skia",
"//testing/gtest",
- "//third_party/libdrm",
"//ui/gfx",
"//ui/ozone:platform",
"//ui/ozone/common",
- "//ui/ozone/common/linux",
+ "//ui/ozone/common/linux:drm",
+ "//ui/ozone/common/linux:gbm",
]
if (drm_commit_properties_on_page_flip) {
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
index f555f84c1a8..1ad207bccf5 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -20,7 +20,7 @@
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
@@ -205,19 +205,19 @@ class DrmDevice::IOWatcher : public base::MessagePumpLibevent::FdWatcher {
private:
void Register() {
- DCHECK(base::MessageLoopForIO::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForIO::IsSet());
base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
fd_, true, base::MessagePumpForIO::WATCH_READ, &controller_, this);
}
void Unregister() {
- DCHECK(base::MessageLoopForIO::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForIO::IsSet());
controller_.StopWatchingFileDescriptor();
}
// base::MessagePumpLibevent::FdWatcher overrides:
void OnFileCanReadWithoutBlocking(int fd) override {
- DCHECK(base::MessageLoopForIO::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForIO::IsSet());
TRACE_EVENT1("drm", "OnDrmEvent", "socket", fd);
if (!ProcessDrmEvent(
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
index 9764bccbf46..64272d290ee 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -102,17 +102,6 @@ MovableDisplaySnapshots DrmGpuDisplayManager::GetDisplays() {
return params_list;
}
-void DrmGpuDisplayManager::GetScanoutFormats(
- gfx::AcceleratedWidget widget,
- std::vector<gfx::BufferFormat>* scanout_formats) {
- const std::vector<uint32_t>& fourcc_formats =
- drm_device_manager_->GetDrmDevice(widget)
- ->plane_manager()
- ->GetSupportedFormats();
- for (auto& fourcc : fourcc_formats)
- scanout_formats->push_back(GetBufferFormatFromFourCCFormat(fourcc));
-}
-
bool DrmGpuDisplayManager::TakeDisplayControl() {
const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices();
bool status = true;
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
index 25ae9a0b919..8e0a1a88fc3 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -36,11 +36,6 @@ class DrmGpuDisplayManager {
// displays is refreshed.
MovableDisplaySnapshots GetDisplays();
- // Returns all scanout formats for |widget| representing a particular display
- // controller or default display controller for kNullAcceleratedWidget.
- void GetScanoutFormats(gfx::AcceleratedWidget widget,
- std::vector<gfx::BufferFormat>* scanout_formats);
-
// Takes/releases the control of the DRM devices.
bool TakeDisplayControl();
void RelinquishDisplayControl();
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
index 09a96c43baa..472311f097b 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -208,12 +208,6 @@ void DrmThread::CreateBufferFromFds(
*out_framebuffer = std::move(framebuffer);
}
-void DrmThread::GetScanoutFormats(
- gfx::AcceleratedWidget widget,
- std::vector<gfx::BufferFormat>* scanout_formats) {
- display_manager_->GetScanoutFormats(widget, scanout_formats);
-}
-
void DrmThread::SchedulePageFlip(
gfx::AcceleratedWidget widget,
std::vector<DrmOverlayPlane> planes,
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
index c6fcabc3a89..47f09370b15 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -80,8 +80,6 @@ class DrmThread : public base::Thread,
const std::vector<gfx::NativePixmapPlane>& planes,
std::unique_ptr<GbmBuffer>* buffer,
scoped_refptr<DrmFramebuffer>* framebuffer);
- void GetScanoutFormats(gfx::AcceleratedWidget widget,
- std::vector<gfx::BufferFormat>* scanout_formats);
void AddBindingCursorDevice(ozone::mojom::DeviceCursorRequest request);
void AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request);
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index 9a9e415125c..4c97c66af23 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -62,15 +62,6 @@ void DrmThreadProxy::CreateBufferFromFds(
buffer, framebuffer));
}
-void DrmThreadProxy::GetScanoutFormats(
- gfx::AcceleratedWidget widget,
- std::vector<gfx::BufferFormat>* scanout_formats) {
- PostSyncTask(
- drm_thread_.task_runner(),
- base::BindOnce(&DrmThread::GetScanoutFormats,
- base::Unretained(&drm_thread_), widget, scanout_formats));
-}
-
void DrmThreadProxy::AddBindingCursorDevice(
ozone::mojom::DeviceCursorRequest request) {
drm_thread_.task_runner()->PostTask(
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
index 35811051a4d..f16bb1b2634 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
@@ -48,9 +48,6 @@ class DrmThreadProxy {
std::unique_ptr<GbmBuffer>* buffer,
scoped_refptr<DrmFramebuffer>* framebuffer);
- void GetScanoutFormats(gfx::AcceleratedWidget widget,
- std::vector<gfx::BufferFormat>* scanout_formats);
-
void AddBindingCursorDevice(ozone::mojom::DeviceCursorRequest request);
void AddBindingDrmDevice(ozone::mojom::DrmDeviceRequest request);
diff --git a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
index ce35578edd2..d9e6790be02 100644
--- a/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/drm_window_proxy.cc
@@ -4,6 +4,7 @@
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
+#include "base/command_line.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
@@ -12,6 +13,7 @@
#include "ui/ozone/platform/drm/gpu/drm_overlay_plane.h"
#include "ui/ozone/platform/drm/gpu/drm_thread.h"
#include "ui/ozone/platform/drm/gpu/proxy_helpers.h"
+#include "ui/ozone/public/ozone_switches.h"
namespace ui {
@@ -40,7 +42,8 @@ bool DrmWindowProxy::SupportsGpuFences() const {
drm_thread_->task_runner(),
base::BindOnce(&DrmThread::IsDeviceAtomic, base::Unretained(drm_thread_),
widget_, &is_atomic));
- return is_atomic;
+ return is_atomic && !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableExplicitDmaFences);
}
} // namespace ui
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index dffec5db847..6d08b23fed9 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -29,7 +29,6 @@
#if BUILDFLAG(ENABLE_VULKAN)
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "ui/ozone/platform/drm/gpu/vulkan_implementation_gbm.h"
-#if defined(OS_CHROMEOS)
#define VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL 1024
typedef struct VkDmaBufImageCreateInfo_ {
VkStructureType sType;
@@ -47,7 +46,6 @@ typedef VkResult(VKAPI_PTR* PFN_vkCreateDmaBufImageINTEL)(
VkDeviceMemory* pMem,
VkImage* pImage);
#endif
-#endif
namespace ui {
@@ -155,7 +153,6 @@ scoped_refptr<gfx::NativePixmap> GbmSurfaceFactory::CreateNativePixmapForVulkan(
VkDevice vk_device,
VkDeviceMemory* vk_device_memory,
VkImage* vk_image) {
-#if defined(OS_CHROMEOS)
std::unique_ptr<GbmBuffer> buffer;
scoped_refptr<DrmFramebuffer> framebuffer;
@@ -209,9 +206,6 @@ scoped_refptr<gfx::NativePixmap> GbmSurfaceFactory::CreateNativePixmapForVulkan(
return base::MakeRefCounted<GbmPixmap>(this, std::move(buffer),
std::move(framebuffer));
-#else
- return nullptr;
-#endif
}
#endif
@@ -228,13 +222,6 @@ std::unique_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget(
return nullptr;
}
-std::vector<gfx::BufferFormat> GbmSurfaceFactory::GetScanoutFormats(
- gfx::AcceleratedWidget widget) {
- std::vector<gfx::BufferFormat> scanout_formats;
- drm_thread_proxy_->GetScanoutFormats(widget, &scanout_formats);
- return scanout_formats;
-}
-
scoped_refptr<gfx::NativePixmap> GbmSurfaceFactory::CreateNativePixmap(
gfx::AcceleratedWidget widget,
gfx::Size size,
diff --git a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index c12508523b1..028a1687a5d 100644
--- a/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/chromium/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -53,8 +53,6 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone {
std::unique_ptr<OverlaySurface> CreateOverlaySurface(
gfx::AcceleratedWidget window) override;
- std::vector<gfx::BufferFormat> GetScanoutFormats(
- gfx::AcceleratedWidget widget) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index fe898efb2e6..3d1083b89fd 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -118,26 +118,33 @@ bool HardwareDisplayPlaneManagerAtomic::Commit(
// After we perform the atomic commit, and if the caller has requested an
// out-fence, the out_fence_fds vector will contain any provided out-fence
// fds for the crtcs, therefore the scope of out_fence_fds needs to outlive
- // the CommitProperties call.
+ // the CommitProperties call. CommitProperties will write into the Receiver,
+ // and the Receiver's destructor writes into ScopedFD, so we need to ensure
+ // that the Receivers are destructed before we attempt to use their
+ // corresponding ScopedFDs.
std::vector<base::ScopedFD> out_fence_fds;
- if (out_fence) {
- if (!AddOutFencePtrProperties(plane_list->atomic_property_set.get(), crtcs,
- &out_fence_fds)) {
- ResetCurrentPlaneList(plane_list);
- return false;
+ {
+ std::vector<base::ScopedFD::Receiver> out_fence_fd_receivers;
+ if (out_fence) {
+ if (!AddOutFencePtrProperties(plane_list->atomic_property_set.get(),
+ crtcs, &out_fence_fds,
+ &out_fence_fd_receivers)) {
+ ResetCurrentPlaneList(plane_list);
+ return false;
+ }
}
- }
- if (!drm_->CommitProperties(plane_list->atomic_property_set.get(), flags,
- crtcs.size(), page_flip_request)) {
- if (!test_only) {
- PLOG(ERROR) << "Failed to commit properties for page flip.";
- } else {
- VPLOG(2) << "Failed to commit properties for MODE_ATOMIC_TEST_ONLY.";
- }
+ if (!drm_->CommitProperties(plane_list->atomic_property_set.get(), flags,
+ crtcs.size(), page_flip_request)) {
+ if (!test_only) {
+ PLOG(ERROR) << "Failed to commit properties for page flip.";
+ } else {
+ VPLOG(2) << "Failed to commit properties for MODE_ATOMIC_TEST_ONLY.";
+ }
- ResetCurrentPlaneList(plane_list);
- return false;
+ ResetCurrentPlaneList(plane_list);
+ return false;
+ }
}
if (out_fence)
@@ -335,11 +342,14 @@ bool HardwareDisplayPlaneManagerAtomic::CommitGammaCorrection(
bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties(
drmModeAtomicReqPtr property_set,
const std::vector<CrtcController*>& crtcs,
- std::vector<base::ScopedFD>* out_fence_fds) {
+ std::vector<base::ScopedFD>* out_fence_fds,
+ std::vector<base::ScopedFD::Receiver>* out_fence_fd_receivers) {
// Reserve space in vector to ensure no reallocation will take place
// and thus all pointers to elements will remain valid
DCHECK(out_fence_fds->empty());
+ DCHECK(out_fence_fd_receivers->empty());
out_fence_fds->reserve(crtcs.size());
+ out_fence_fd_receivers->reserve(crtcs.size());
for (auto* crtc : crtcs) {
const auto crtc_index = LookupCrtcIndex(crtc->crtc());
@@ -349,6 +359,7 @@ bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties(
if (out_fence_ptr_id > 0) {
out_fence_fds->push_back(base::ScopedFD());
+ out_fence_fd_receivers->emplace_back(out_fence_fds->back());
// Add the OUT_FENCE_PTR property pointing to the memory location
// to save the out-fence fd into for this crtc. Note that
// the out-fence fd is produced only after we perform the atomic
@@ -356,10 +367,11 @@ bool HardwareDisplayPlaneManagerAtomic::AddOutFencePtrProperties(
// until then.
int ret = drmModeAtomicAddProperty(
property_set, crtc->crtc(), out_fence_ptr_id,
- reinterpret_cast<uint64_t>(out_fence_fds->back().receive()));
+ reinterpret_cast<uint64_t>(out_fence_fd_receivers->back().get()));
if (ret < 0) {
LOG(ERROR) << "Failed to set OUT_FENCE_PTR property for crtc="
<< crtc->crtc() << " error=" << -ret;
+ out_fence_fd_receivers->pop_back();
out_fence_fds->pop_back();
return false;
}
diff --git a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
index ae44ee124c8..b3196146234 100644
--- a/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
+++ b/chromium/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
@@ -45,9 +45,11 @@ class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
std::unique_ptr<HardwareDisplayPlane> CreatePlane(uint32_t plane_id) override;
bool CommitColorMatrix(const CrtcProperties& crtc_props) override;
bool CommitGammaCorrection(const CrtcProperties& crtc_props) override;
- bool AddOutFencePtrProperties(drmModeAtomicReqPtr property_set,
- const std::vector<CrtcController*>& crtcs,
- std::vector<base::ScopedFD>* out_fence_fds);
+ bool AddOutFencePtrProperties(
+ drmModeAtomicReqPtr property_set,
+ const std::vector<CrtcController*>& crtcs,
+ std::vector<base::ScopedFD>* out_fence_fds,
+ std::vector<base::ScopedFD::Receiver>* out_fence_fd_receivers);
DISALLOW_COPY_AND_ASSIGN(HardwareDisplayPlaneManagerAtomic);
};
diff --git a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
index 8ffc06b4c05..3b8e789c501 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -49,6 +49,8 @@ void DrmCursor::SetDrmCursorProxy(std::unique_ptr<DrmCursorProxy> proxy) {
DCHECK(thread_checker_.CalledOnValidThread());
base::AutoLock lock(lock_);
proxy_ = std::move(proxy);
+ if (window_ != gfx::kNullAcceleratedWidget)
+ SendCursorShowLocked();
}
void DrmCursor::ResetDrmCursorProxy() {
diff --git a/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc b/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
index 2cca2697bb9..3f7ec9f7d1a 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -39,7 +39,7 @@ DrmDeviceHandle::DrmDeviceHandle() {
DrmDeviceHandle::~DrmDeviceHandle() {
if (file_.is_valid())
- base::AssertBlockingAllowed();
+ base::AssertBlockingAllowedDeprecated();
}
bool DrmDeviceHandle::Initialize(const base::FilePath& dev_path,
@@ -48,7 +48,7 @@ bool DrmDeviceHandle::Initialize(const base::FilePath& dev_path,
// expected path, so use a CHECK instead of a DCHECK. The sys_path is only
// used a label and is otherwise unvalidated.
CHECK(dev_path.DirName() == base::FilePath("/dev/dri"));
- base::AssertBlockingAllowed();
+ base::AssertBlockingAllowedDeprecated();
int num_auth_attempts = 0;
bool logged_warning = false;
diff --git a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
index 8adf3febb61..7e6862e7212 100644
--- a/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
+++ b/chromium/ui/ozone/platform/drm/host/drm_gpu_platform_support_host.cc
@@ -78,9 +78,8 @@ void CursorIPC::Send(IPC::Message* message) {
FROM_HERE, base::BindOnce(send_callback_, message)))
return;
- // Drop disconnected updates. DrmWindowHost will call
- // CommitBoundsChange() when we connect to initialize the cursor
- // location.
+ // Drop disconnected updates. The cursor will get set once we connect, via
+ // SetDrmCursorProxy().
delete message;
}
diff --git a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
index f3e5c12e016..a2e555d874e 100644
--- a/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/chromium/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -23,6 +23,7 @@
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
@@ -61,9 +62,8 @@ namespace {
class OzonePlatformGbm : public OzonePlatform {
public:
- OzonePlatformGbm()
- : using_mojo_(false), single_process_(false), weak_factory_(this) {}
- ~OzonePlatformGbm() override {}
+ OzonePlatformGbm() = default;
+ ~OzonePlatformGbm() override = default;
// OzonePlatform:
ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
@@ -172,6 +172,12 @@ class OzonePlatformGbm : public OzonePlatform {
return std::make_unique<DrmNativeDisplayDelegate>(display_manager_.get());
}
+ bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage) const override {
+ return gfx::ClientNativePixmapDmaBuf::IsConfigurationSupported(format,
+ usage);
+ }
+
void InitializeUI(const InitParams& args) override {
// Ozone drm can operate in four modes configured at
// runtime. Three process modes:
@@ -185,12 +191,13 @@ class OzonePlatformGbm : public OzonePlatform {
//
// and 2 connection modes
// a. Viz is launched via content::GpuProcessHost and it notifies the
- // ozone host when Viz becomes available. b. The ozone host uses a service
- // manager to launch and connect to Viz.
+ // ozone host when Viz becomes available. b. The ozone host uses a
+ // service manager to launch and connect to Viz.
//
// Combinations 1a, 2b, and 3a, and 3b are supported and expected to work.
// Combination 1a will hopefully be deprecated and replaced with 3a.
- // Combination 2b adds undesirable code-debt and the intent is to remove it.
+ // Combination 2b adds undesirable code-debt and the intent is to remove
+ // it.
single_process_ = args.single_process;
using_mojo_ = args.using_mojo || args.connector != nullptr;
@@ -199,6 +206,7 @@ class OzonePlatformGbm : public OzonePlatform {
device_manager_ = CreateDeviceManager();
window_manager_.reset(new DrmWindowHostManager());
cursor_.reset(new DrmCursor(window_manager_.get()));
+
#if BUILDFLAG(USE_XKBCOMMON)
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
std::make_unique<XkbKeyboardLayoutEngine>(xkb_evdev_code_converter_));
@@ -291,8 +299,8 @@ class OzonePlatformGbm : public OzonePlatform {
}
private:
- bool using_mojo_;
- bool single_process_;
+ bool using_mojo_ = false;
+ bool single_process_ = false;
// Objects in the GPU process.
std::unique_ptr<DrmThreadProxy> drm_thread_proxy_;
@@ -304,7 +312,7 @@ class OzonePlatformGbm : public OzonePlatform {
// running in single process mode.
std::vector<ozone::mojom::DeviceCursorRequest> pending_cursor_requests_;
std::vector<ozone::mojom::DrmDeviceRequest> pending_gpu_adapter_requests_;
- bool drm_thread_started_;
+ bool drm_thread_started_ = false;
// gpu_platform_support_host_ is the IPC bridge to the GPU process while
// host_drm_device_ is the mojo bridge to the Viz process. Only one can be in
@@ -333,7 +341,7 @@ class OzonePlatformGbm : public OzonePlatform {
XkbEvdevCodes xkb_evdev_code_converter_;
#endif
- base::WeakPtrFactory<OzonePlatformGbm> weak_factory_;
+ base::WeakPtrFactory<OzonePlatformGbm> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
};
diff --git a/chromium/ui/ozone/platform/scenic/BUILD.gn b/chromium/ui/ozone/platform/scenic/BUILD.gn
index 3722c13aa84..565b80d8b5e 100644
--- a/chromium/ui/ozone/platform/scenic/BUILD.gn
+++ b/chromium/ui/ozone/platform/scenic/BUILD.gn
@@ -14,10 +14,12 @@ source_set("scenic") {
"client_native_pixmap_factory_scenic.h",
"ozone_platform_scenic.cc",
"ozone_platform_scenic.h",
+ "scenic_gpu_host.cc",
+ "scenic_gpu_host.h",
+ "scenic_gpu_service.cc",
+ "scenic_gpu_service.h",
"scenic_screen.cc",
"scenic_screen.h",
- "scenic_session.cc",
- "scenic_session.h",
"scenic_surface_factory.cc",
"scenic_surface_factory.h",
"scenic_window.cc",
@@ -32,11 +34,14 @@ source_set("scenic") {
deps = [
"//base",
+ "//mojo/public/cpp/system",
+ "//services/service_manager/public/cpp",
"//skia",
"//third_party/fuchsia-sdk/sdk:gfx",
"//third_party/fuchsia-sdk/sdk:images",
"//third_party/fuchsia-sdk/sdk:mem",
"//third_party/fuchsia-sdk/sdk:scenic",
+ "//third_party/fuchsia-sdk/sdk:scenic_cpp",
"//third_party/fuchsia-sdk/sdk:viewsv1",
"//third_party/fuchsia-sdk/sdk:viewsv1token",
"//ui/base",
@@ -46,6 +51,7 @@ source_set("scenic") {
"//ui/gfx/geometry",
"//ui/ozone:ozone_base",
"//ui/ozone/common",
+ "//ui/ozone/public/interfaces",
"//ui/platform_window",
]
diff --git a/chromium/ui/ozone/platform/scenic/DEPS b/chromium/ui/ozone/platform/scenic/DEPS
index defb45e8062..1f7f0de1953 100644
--- a/chromium/ui/ozone/platform/scenic/DEPS
+++ b/chromium/ui/ozone/platform/scenic/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+mojo/public",
"+third_party/skia/include",
"+ui/base/ime",
]
diff --git a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
index fde7eea29c9..9a044347006 100644
--- a/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/ozone_platform_scenic.cc
@@ -19,6 +19,8 @@
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/system_input_injector.h"
#include "ui/ozone/common/stub_overlay_manager.h"
+#include "ui/ozone/platform/scenic/scenic_gpu_host.h"
+#include "ui/ozone/platform/scenic/scenic_gpu_service.h"
#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
@@ -26,6 +28,7 @@
#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_service.mojom.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -34,12 +37,11 @@ namespace ui {
namespace {
-const OzonePlatform::PlatformProperties kScenicPlatformProperties(
- /*needs_view_owner_request=*/true,
+constexpr OzonePlatform::PlatformProperties kScenicPlatformProperties{
+ /*needs_view_token=*/true,
/*custom_frame_pref_default=*/false,
/*use_system_title_bar=*/false,
- /*requires_mojo=*/false,
- std::vector<gfx::BufferFormat>());
+ /*requires_mojo=*/true};
class ScenicPlatformEventSource : public ui::PlatformEventSource {
public:
@@ -55,14 +57,12 @@ class OzonePlatformScenic
: public OzonePlatform,
public base::MessageLoopCurrent::DestructionObserver {
public:
- OzonePlatformScenic()
- : window_manager_(std::make_unique<ScenicWindowManager>()),
- surface_factory_(window_manager_.get()) {}
+ OzonePlatformScenic() {}
~OzonePlatformScenic() override = default;
// OzonePlatform implementation.
ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
- return &surface_factory_;
+ return surface_factory_.get();
}
OverlayManagerOzone* GetOverlayManager() override {
@@ -78,7 +78,7 @@ class OzonePlatformScenic
}
GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
- return gpu_platform_support_host_.get();
+ return scenic_gpu_host_.get();
}
std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
@@ -89,13 +89,12 @@ class OzonePlatformScenic
std::unique_ptr<PlatformWindow> CreatePlatformWindow(
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties) override {
- if (!properties.view_owner_request) {
+ if (!properties.view_token) {
NOTREACHED();
return nullptr;
}
- return std::make_unique<ScenicWindow>(
- window_manager_.get(), delegate,
- std::move(properties.view_owner_request));
+ return std::make_unique<ScenicWindow>(window_manager_.get(), delegate,
+ std::move(properties.view_token));
}
const PlatformProperties& GetPlatformProperties() override {
@@ -118,15 +117,36 @@ class OzonePlatformScenic
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
std::make_unique<StubKeyboardLayoutEngine>());
+ window_manager_ = std::make_unique<ScenicWindowManager>();
overlay_manager_ = std::make_unique<StubOverlayManager>();
input_controller_ = CreateStubInputController();
cursor_factory_ozone_ = std::make_unique<BitmapCursorFactoryOzone>();
- gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
base::MessageLoopCurrent::Get()->AddDestructionObserver(this);
+
+ surface_factory_ =
+ std::make_unique<ScenicSurfaceFactory>(window_manager_.get());
+
+ scenic_gpu_host_ = std::make_unique<ScenicGpuHost>(window_manager_.get());
+ }
+
+ void InitializeGPU(const InitParams& params) override {
+ scenic_gpu_service_ = std::make_unique<ScenicGpuService>();
+ DCHECK(!surface_factory_);
+ surface_factory_ =
+ std::make_unique<ScenicSurfaceFactory>(scenic_gpu_service_.get());
}
- void InitializeGPU(const InitParams& params) override {}
+ base::MessageLoop::Type GetMessageLoopTypeForGpu() override {
+ // Scenic FIDL calls require async dispatcher.
+ return base::MessageLoop::TYPE_IO;
+ }
+
+ void AddInterfaces(service_manager::BinderRegistry* registry) override {
+ registry->AddInterface<mojom::ScenicGpuService>(
+ scenic_gpu_service_->GetBinderCallback(),
+ base::ThreadTaskRunnerHandle::Get());
+ }
private:
// Performs graceful cleanup tasks on main message loop teardown.
@@ -136,13 +156,14 @@ class OzonePlatformScenic
void WillDestroyCurrentMessageLoop() override { Shutdown(); }
std::unique_ptr<ScenicWindowManager> window_manager_;
- ScenicSurfaceFactory surface_factory_;
std::unique_ptr<PlatformEventSource> platform_event_source_;
std::unique_ptr<CursorFactoryOzone> cursor_factory_ozone_;
std::unique_ptr<InputController> input_controller_;
- std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
std::unique_ptr<OverlayManagerOzone> overlay_manager_;
+ std::unique_ptr<ScenicGpuHost> scenic_gpu_host_;
+ std::unique_ptr<ScenicGpuService> scenic_gpu_service_;
+ std::unique_ptr<ScenicSurfaceFactory> surface_factory_;
DISALLOW_COPY_AND_ASSIGN(OzonePlatformScenic);
};
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc
new file mode 100644
index 00000000000..afb7c6ee210
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.cc
@@ -0,0 +1,101 @@
+// 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/ozone/platform/scenic/scenic_gpu_host.h"
+
+#include <inttypes.h>
+
+#include "base/callback.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "ui/ozone/platform/scenic/scenic_window.h"
+#include "ui/ozone/platform/scenic/scenic_window_manager.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_host.mojom.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_service.mojom.h"
+
+namespace {
+
+using BinderCallback =
+ base::RepeatingCallback<void(const std::string&,
+ mojo::ScopedMessagePipeHandle)>;
+
+template <typename Interface>
+void BindInterface(mojo::InterfaceRequest<Interface> request,
+ const BinderCallback& binder_callback) {
+ binder_callback.Run(Interface::Name_, request.PassMessagePipe());
+}
+
+} // namespace
+
+namespace ui {
+
+ScenicGpuHost::ScenicGpuHost(ScenicWindowManager* scenic_window_manager)
+ : scenic_window_manager_(scenic_window_manager),
+ binding_(this),
+ ui_thread_runner_(base::ThreadTaskRunnerHandle::Get()),
+ weak_ptr_factory_(this) {
+ DETACH_FROM_THREAD(io_thread_checker_);
+}
+
+ScenicGpuHost::~ScenicGpuHost() {
+ DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+}
+
+void ScenicGpuHost::ExportParent(int32_t surface_handle,
+ mojo::ScopedHandle export_token_mojo) {
+ DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+ ScenicWindow* scenic_window =
+ scenic_window_manager_->GetWindow(surface_handle);
+ if (!scenic_window)
+ return;
+ zx::eventpair export_token(
+ mojo::UnwrapPlatformHandle(std::move(export_token_mojo)).TakeHandle());
+ scenic_window->ExportRenderingEntity(std::move(export_token));
+}
+
+void ScenicGpuHost::OnGpuProcessLaunched(
+ int host_id,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ const base::RepeatingCallback<void(IPC::Message*)>& send_callback) {
+ NOTREACHED();
+}
+
+void ScenicGpuHost::OnChannelDestroyed(int host_id) {}
+
+void ScenicGpuHost::OnGpuServiceLaunched(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+ GpuHostBindInterfaceCallback binder,
+ GpuHostTerminateCallback terminate_callback) {
+ DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+
+ mojom::ScenicGpuServicePtr scenic_gpu_service;
+ BindInterface(mojo::MakeRequest(&scenic_gpu_service), binder);
+ ui_thread_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&ScenicGpuHost::OnGpuServiceLaunchedOnUI,
+ weak_ptr_factory_.GetWeakPtr(),
+ scenic_gpu_service.PassInterface()));
+}
+
+void ScenicGpuHost::OnGpuServiceLaunchedOnUI(
+ mojo::InterfacePtrInfo<mojom::ScenicGpuService> gpu_service_ptr_info) {
+ DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+
+ mojom::ScenicGpuHostPtr gpu_host;
+ binding_.Close();
+ binding_.Bind(mojo::MakeRequest(&gpu_host));
+
+ gpu_service_.Bind(std::move(gpu_service_ptr_info));
+ gpu_service_->Initialize(std::move(gpu_host));
+}
+
+void ScenicGpuHost::OnMessageReceived(const IPC::Message& message) {
+ NOTREACHED();
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h
new file mode 100644
index 00000000000..5c0cdeab043
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_host.h
@@ -0,0 +1,76 @@
+// 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_OZONE_PLATFORM_SCENIC_SCENIC_GPU_HOST_H_
+#define UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_HOST_H_
+
+#include <inttypes.h>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_host.mojom.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_service.mojom.h"
+
+namespace ui {
+class ScenicWindowManager;
+
+// Browser process object which supports a GPU process host.
+//
+// Once a GPU process starts, this objects binds to it over mojo and
+// enables exchange of Scenic resources with it. In particular, we must
+// exchange export tokens for each view surface, so that the surface can
+// present to Scenic views managed by the browser.
+class ScenicGpuHost : public mojom::ScenicGpuHost,
+ public GpuPlatformSupportHost {
+ public:
+ ScenicGpuHost(ScenicWindowManager* scenic_window_manager);
+ ~ScenicGpuHost() override;
+
+ // mojom::ScenicGpuHost:
+ void ExportParent(int32_t surface_handle,
+ mojo::ScopedHandle export_token_mojo) override;
+
+ // GpuPlatformSupportHost:
+ void OnGpuProcessLaunched(
+ int host_id,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+ const base::RepeatingCallback<void(IPC::Message*)>& send_callback)
+ override;
+ void OnChannelDestroyed(int host_id) override;
+ void OnMessageReceived(const IPC::Message& message) override;
+ void OnGpuServiceLaunched(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner,
+ GpuHostBindInterfaceCallback binder,
+ GpuHostTerminateCallback terminate_callback) override;
+
+ private:
+ void OnGpuServiceLaunchedOnUI(
+ mojo::InterfacePtrInfo<mojom::ScenicGpuService> gpu_service_ptr_info);
+ void UpdateBinding(uint32_t service_launch_count,
+ mojom::ScenicGpuHostRequest scenic_gpu_host_request);
+
+ ScenicWindowManager* const scenic_window_manager_;
+ mojo::Binding<mojom::ScenicGpuHost> binding_;
+
+ mojom::ScenicGpuServicePtr gpu_service_;
+ scoped_refptr<base::SingleThreadTaskRunner> ui_thread_runner_;
+
+ THREAD_CHECKER(ui_thread_checker_);
+ THREAD_CHECKER(io_thread_checker_);
+
+ base::WeakPtrFactory<ScenicGpuHost> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScenicGpuHost);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_HOST_H_
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc
new file mode 100644
index 00000000000..2d10d52533b
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.cc
@@ -0,0 +1,52 @@
+// 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/ozone/platform/scenic/scenic_gpu_service.h"
+
+#include "mojo/public/c/system/message_pipe.h"
+
+namespace ui {
+
+namespace {
+
+// Fulfills an InterfaceRequest<T> using an InterfacePtr<T>.
+//
+// Messages queued on the InterfaceRequest's message pipe are preserved and will
+// be eventually delivered to the remote end of InterfacePtr<T>'s.
+//
+// InterfacePtr<T> must be a brand new interface; i.e., it not have been
+// previously used to send a message.
+template <typename Interface>
+void FulfillInterfaceRequest(
+ mojo::InterfaceRequest<Interface> interface_request,
+ mojo::InterfacePtr<Interface> interface_ptr) {
+ MojoResult result =
+ mojo::FuseMessagePipes(interface_ptr.PassInterface().PassHandle(),
+ interface_request.PassMessagePipe());
+ DCHECK_EQ(result, MOJO_RESULT_OK);
+}
+
+} // namespace
+
+ScenicGpuService::ScenicGpuService()
+ : gpu_host_request_(mojo::MakeRequest(&gpu_host_)),
+ weak_ptr_factory_(this) {}
+
+ScenicGpuService::~ScenicGpuService() {}
+
+base::RepeatingCallback<void(mojom::ScenicGpuServiceRequest)>
+ScenicGpuService::GetBinderCallback() {
+ return base::BindRepeating(&ScenicGpuService::AddBinding,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+void ScenicGpuService::Initialize(mojom::ScenicGpuHostPtr gpu_host) {
+ FulfillInterfaceRequest(std::move(gpu_host_request_), std::move(gpu_host));
+}
+
+void ScenicGpuService::AddBinding(mojom::ScenicGpuServiceRequest request) {
+ binding_set_.AddBinding(this, std::move(request));
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h
new file mode 100644
index 00000000000..8bb67458052
--- /dev/null
+++ b/chromium/ui/ozone/platform/scenic/scenic_gpu_service.h
@@ -0,0 +1,51 @@
+// 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_OZONE_PLATFORM_SCENIC_SCENIC_GPU_SERVICE_H_
+#define UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_SERVICE_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_host.mojom.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_service.mojom.h"
+
+namespace ui {
+
+// GPU process service that enables presentation to Scenic.
+//
+// This object exposes a mojo service to the browser process from the GPU
+// process. The browser binds it to enable exchange of Scenic resources.
+// In particular, we must exchange export tokens for each view surface,
+// so that surfaces can present to Scenic views managed by the browser.
+class ScenicGpuService : public mojom::ScenicGpuService {
+ public:
+ ScenicGpuService();
+ ~ScenicGpuService() override;
+
+ mojom::ScenicGpuHost* gpu_host() { return gpu_host_.get(); }
+
+ base::RepeatingCallback<void(mojom::ScenicGpuServiceRequest)>
+ GetBinderCallback();
+
+ // mojom::ScenicGpuService:
+ void Initialize(mojom::ScenicGpuHostPtr gpu_host) override;
+
+ private:
+ void AddBinding(mojom::ScenicGpuServiceRequest request);
+
+ mojom::ScenicGpuHostPtr gpu_host_;
+ mojom::ScenicGpuHostRequest gpu_host_request_;
+
+ mojo::BindingSet<mojom::ScenicGpuService> binding_set_;
+
+ base::WeakPtrFactory<ScenicGpuService> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScenicGpuService);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_GPU_SERVICE_H_
diff --git a/chromium/ui/ozone/platform/scenic/scenic_session.cc b/chromium/ui/ozone/platform/scenic/scenic_session.cc
deleted file mode 100644
index c29bc82cc3e..00000000000
--- a/chromium/ui/ozone/platform/scenic/scenic_session.cc
+++ /dev/null
@@ -1,309 +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.
-
-#include "ui/ozone/platform/scenic/scenic_session.h"
-
-#include "base/fuchsia/fuchsia_logging.h"
-
-namespace ui {
-
-namespace {
-
-// Max number of commands that will fit in a single message.
-//
-// TODO(sergeyu): Improve this logic when FIDL provides a mechanism to estimate
-// message size, see https://fuchsia.atlassian.net/browse/FIDL-212 .
-constexpr size_t kCommandsPerMessage =
- std::max(static_cast<size_t>(ZX_CHANNEL_MAX_MSG_HANDLES),
- (ZX_CHANNEL_MAX_MSG_BYTES - sizeof(fidl_message_header_t) -
- sizeof(fidl_vector_t)) /
- sizeof(fuchsia::ui::gfx::Command));
-
-// Helper function for all resource creation functions.
-fuchsia::ui::gfx::Command NewCreateResourceCommand(
- ScenicSession::ResourceId resource_id,
- fuchsia::ui::gfx::ResourceArgs resource) {
- fuchsia::ui::gfx::CreateResourceCmd create_resource;
- create_resource.id = resource_id;
- create_resource.resource = std::move(resource);
-
- fuchsia::ui::gfx::Command command;
- command.set_create_resource(std::move(create_resource));
-
- return command;
-}
-
-fuchsia::ui::gfx::Command NewReleaseResourceCommand(
- ScenicSession::ResourceId resource_id) {
- fuchsia::ui::gfx::ReleaseResourceCmd release_resource;
- release_resource.id = resource_id;
-
- fuchsia::ui::gfx::Command command;
- command.set_release_resource(std::move(release_resource));
-
- return command;
-}
-
-} // namespace
-
-ScenicSession::ScenicSession(fuchsia::ui::scenic::Scenic* scenic,
- ScenicSessionListener* listener)
- : listener_(listener), session_listener_binding_(this) {
- scenic->CreateSession(session_.NewRequest(),
- session_listener_binding_.NewBinding());
- session_.set_error_handler([this]() {
- Close();
- listener_->OnScenicError("ScenicSession disconnected unexpectedly.");
- });
-}
-
-ScenicSession::~ScenicSession() {
- DCHECK_EQ(resource_count_, 0);
-}
-
-void ScenicSession::ReleaseResource(ResourceId resource_id) {
- resource_count_--;
- EnqueueGfxCommand(NewReleaseResourceCommand(resource_id));
-}
-
-ScenicSession::ResourceId ScenicSession::CreateMemory(
- base::SharedMemoryHandle vmo,
- fuchsia::images::MemoryType memory_type) {
- DCHECK(vmo.IsValid());
-
- fuchsia::ui::gfx::MemoryArgs memory;
- memory.vmo = zx::vmo(vmo.GetHandle());
- memory.memory_type = memory_type;
-
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_memory(std::move(memory));
-
- ResourceId memory_id = AllocateResourceId();
- EnqueueGfxCommand(NewCreateResourceCommand(memory_id, std::move(resource)));
-
- return memory_id;
-}
-
-ScenicSession::ResourceId ScenicSession::CreateImage(
- ResourceId memory_id,
- ResourceId memory_offset,
- fuchsia::images::ImageInfo info) {
- fuchsia::ui::gfx::ImageArgs image;
- image.memory_id = memory_id;
- image.memory_offset = memory_offset;
- image.info = std::move(info);
-
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_image(std::move(image));
-
- ResourceId image_id = AllocateResourceId();
- EnqueueGfxCommand(NewCreateResourceCommand(image_id, std::move(resource)));
-
- return image_id;
-}
-
-ScenicSession::ResourceId ScenicSession::CreateImagePipe(
- fidl::InterfaceRequest<fuchsia::images::ImagePipe> request) {
- fuchsia::ui::gfx::ImagePipeArgs image_pipe;
- image_pipe.image_pipe_request = std::move(request);
-
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_image_pipe(std::move(image_pipe));
-
- ResourceId image_pipe_id = AllocateResourceId();
- EnqueueGfxCommand(
- NewCreateResourceCommand(image_pipe_id, std::move(resource)));
-
- return image_pipe_id;
-}
-
-ScenicSession::ResourceId ScenicSession::ImportResource(
- fuchsia::ui::gfx::ImportSpec spec,
- zx::eventpair import_token) {
- DCHECK(import_token);
-
- ResourceId resource_id = AllocateResourceId();
- fuchsia::ui::gfx::ImportResourceCmd import_resource;
- import_resource.id = resource_id;
- import_resource.token = std::move(import_token);
- import_resource.spec = spec;
-
- fuchsia::ui::gfx::Command command;
- command.set_import_resource(std::move(import_resource));
- EnqueueGfxCommand(std::move(command));
-
- return resource_id;
-}
-
-ScenicSession::ResourceId ScenicSession::CreateEntityNode() {
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_entity_node(fuchsia::ui::gfx::EntityNodeArgs());
-
- ResourceId node_id = AllocateResourceId();
- EnqueueGfxCommand(NewCreateResourceCommand(node_id, std::move(resource)));
-
- return node_id;
-}
-
-ScenicSession::ResourceId ScenicSession::CreateShapeNode() {
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_shape_node(fuchsia::ui::gfx::ShapeNodeArgs());
-
- ResourceId node_id = AllocateResourceId();
- EnqueueGfxCommand(NewCreateResourceCommand(node_id, std::move(resource)));
-
- return node_id;
-}
-
-void ScenicSession::AddNodeChild(ResourceId node_id, ResourceId child_id) {
- fuchsia::ui::gfx::AddChildCmd add_child;
- add_child.node_id = node_id;
- add_child.child_id = child_id;
-
- fuchsia::ui::gfx::Command command;
- command.set_add_child(std::move(add_child));
- EnqueueGfxCommand(std::move(command));
-}
-
-void ScenicSession::SetNodeTranslation(ResourceId node_id,
- const float translation[3]) {
- fuchsia::ui::gfx::SetTranslationCmd set_translation;
- set_translation.id = node_id;
- set_translation.value.variable_id = 0;
- set_translation.value.value.x = translation[0];
- set_translation.value.value.y = translation[1];
- set_translation.value.value.z = translation[2];
-
- fuchsia::ui::gfx::Command command;
- command.set_set_translation(std::move(set_translation));
- EnqueueGfxCommand(std::move(command));
-}
-
-ScenicSession::ResourceId ScenicSession::CreateRectangle(float width,
- float height) {
- fuchsia::ui::gfx::Value width_value;
- width_value.set_vector1(width);
-
- fuchsia::ui::gfx::Value height_value;
- height_value.set_vector1(height);
-
- fuchsia::ui::gfx::RectangleArgs rectangle;
- rectangle.width = std::move(width_value);
- rectangle.height = std::move(height_value);
-
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_rectangle(std::move(rectangle));
-
- ResourceId rectangle_id = AllocateResourceId();
- EnqueueGfxCommand(
- NewCreateResourceCommand(rectangle_id, std::move(resource)));
-
- return rectangle_id;
-}
-
-ScenicSession::ResourceId ScenicSession::CreateMaterial() {
- fuchsia::ui::gfx::ResourceArgs resource;
- resource.set_material(fuchsia::ui::gfx::MaterialArgs());
-
- ResourceId material_id = AllocateResourceId();
- EnqueueGfxCommand(NewCreateResourceCommand(material_id, std::move(resource)));
- return material_id;
-}
-
-void ScenicSession::SetNodeMaterial(ResourceId node_id,
- ResourceId material_id) {
- fuchsia::ui::gfx::SetMaterialCmd set_material;
- set_material.node_id = node_id;
- set_material.material_id = material_id;
-
- fuchsia::ui::gfx::Command command;
- command.set_set_material(std::move(set_material));
- EnqueueGfxCommand(std::move(command));
-}
-
-void ScenicSession::SetNodeShape(ResourceId node_id, ResourceId shape_id) {
- fuchsia::ui::gfx::SetShapeCmd set_shape;
- set_shape.node_id = node_id;
- set_shape.shape_id = shape_id;
-
- fuchsia::ui::gfx::Command command;
- command.set_set_shape(std::move(set_shape));
- EnqueueGfxCommand(std::move(command));
-}
-
-void ScenicSession::SetMaterialTexture(ResourceId material_id,
- ResourceId texture_id) {
- fuchsia::ui::gfx::SetTextureCmd set_texture;
- set_texture.material_id = material_id;
- set_texture.texture_id = texture_id;
-
- fuchsia::ui::gfx::Command command;
- command.set_set_texture(std::move(set_texture));
- EnqueueGfxCommand(std::move(command));
-}
-
-void ScenicSession::SetEventMask(ResourceId resource_id, uint32_t event_mask) {
- fuchsia::ui::gfx::SetEventMaskCmd set_event_mask;
- set_event_mask.id = resource_id;
- set_event_mask.event_mask = event_mask;
-
- fuchsia::ui::gfx::Command command;
- command.set_set_event_mask(std::move(set_event_mask));
- EnqueueGfxCommand(std::move(command));
-}
-
-void ScenicSession::AddAcquireFence(zx::event fence) {
- acquire_fences_.push_back(std::move(fence));
-}
-
-void ScenicSession::AddReleaseFence(zx::event fence) {
- release_fences_.push_back(std::move(fence));
-}
-
-void ScenicSession::Present() {
- Flush();
-
- session_->Present(/*flags=*/0,
- fidl::VectorPtr<zx::event>(std::move(acquire_fences_)),
- fidl::VectorPtr<zx::event>(std::move(release_fences_)),
- [](fuchsia::images::PresentationInfo info) {});
-}
-
-void ScenicSession::Close() {
- session_.set_error_handler(nullptr);
- session_.Unbind();
- session_listener_binding_.Unbind();
-}
-
-void ScenicSession::OnScenicError(fidl::StringPtr error) {
- Close();
- listener_->OnScenicError(error);
-}
-
-void ScenicSession::OnScenicEvent(
- fidl::VectorPtr<fuchsia::ui::scenic::Event> events) {
- listener_->OnScenicEvents(events.get());
-}
-
-ScenicSession::ResourceId ScenicSession::AllocateResourceId() {
- resource_count_++;
- return next_resource_id_++;
-}
-
-void ScenicSession::EnqueueGfxCommand(fuchsia::ui::gfx::Command command) {
- fuchsia::ui::scenic::Command scenic_command;
- scenic_command.set_gfx(std::move(command));
- queued_commands_.push_back(std::move(scenic_command));
-
- DCHECK_LE(queued_commands_->size(), kCommandsPerMessage);
- if (queued_commands_->size() == kCommandsPerMessage)
- Flush();
-}
-
-void ScenicSession::Flush() {
- if (!queued_commands_->empty())
- session_->Enqueue(std::move(queued_commands_));
-}
-
-} // namespace ui
diff --git a/chromium/ui/ozone/platform/scenic/scenic_session.h b/chromium/ui/ozone/platform/scenic/scenic_session.h
deleted file mode 100644
index ad81b47a523..00000000000
--- a/chromium/ui/ozone/platform/scenic/scenic_session.h
+++ /dev/null
@@ -1,127 +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_OZONE_PLATFORM_SCENIC_SCENIC_SESSION_H_
-#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SESSION_H_
-
-#include <string>
-#include <vector>
-
-#include <fuchsia/ui/gfx/cpp/fidl.h>
-#include <fuchsia/ui/scenic/cpp/fidl.h>
-#include <lib/fidl/cpp/binding.h>
-#include <lib/zx/event.h>
-#include <lib/zx/eventpair.h>
-
-#include "base/macros.h"
-#include "base/memory/shared_memory_handle.h"
-
-namespace ui {
-
-// Interface used to receive events and error notifications from ScenicSession.
-class ScenicSessionListener {
- public:
- ScenicSessionListener() = default;
-
- virtual void OnScenicError(const std::string& error) = 0;
- virtual void OnScenicEvents(
- const std::vector<fuchsia::ui::scenic::Event>& events) = 0;
-
- protected:
- virtual ~ScenicSessionListener() = default;
-
- DISALLOW_COPY_AND_ASSIGN(ScenicSessionListener);
-};
-
-// ScenicSession represents a session used to interact with Scenic. It sends
-// commands to Scenic via fuchsia::ui::scenic::Session interface. ScenicWindow
-// creates a separate session for each window.
-class ScenicSession : public fuchsia::ui::scenic::SessionListener {
- public:
- using ResourceId = uint32_t;
-
- // Creates and wraps a new session for |scenic_service|. |listener| must
- // outlive ScenicSession.
- ScenicSession(fuchsia::ui::scenic::Scenic* scenic_service,
- ScenicSessionListener* listener);
-
- ~ScenicSession() override;
-
- // Following functions enqueue various Scenic commands. See
- // https://fuchsia.googlesource.com/garnet/+/master/public/lib/ui/gfx/fidl/commands.fidl
- // for descriptions of the commands and the fields. Create*() methods return
- // ID of the created resource. Resource IDs are only valid within context of
- // the session.
- void ReleaseResource(ResourceId resource_id);
- ResourceId CreateMemory(base::SharedMemoryHandle vmo,
- fuchsia::images::MemoryType memory_type);
- ResourceId CreateImage(ResourceId memory_id,
- ResourceId memory_offset,
- fuchsia::images::ImageInfo info);
- ResourceId CreateImagePipe(
- fidl::InterfaceRequest<fuchsia::images::ImagePipe> request);
- ResourceId ImportResource(fuchsia::ui::gfx::ImportSpec spec,
- zx::eventpair import_token);
- ResourceId CreateEntityNode();
- ResourceId CreateShapeNode();
- void AddNodeChild(ResourceId node_id, ResourceId child_id);
- void SetNodeTranslation(ResourceId node_id, const float translation[3]);
- ResourceId CreateRectangle(float width, float height);
- ResourceId CreateMaterial();
- void SetNodeMaterial(ResourceId node_id, ResourceId material_id);
- void SetNodeShape(ResourceId node_id, ResourceId shape_id);
- void SetMaterialTexture(ResourceId material_id, ResourceId texture_id);
- void SetEventMask(ResourceId resource_id, uint32_t event_mask);
-
- // Enqueue acquire or release fences for the next Present() call. See
- // Scenic documentation for description on how these should be used:
- // https://fuchsia.googlesource.com/garnet/+/master/public/lib/ui/scenic/fidl/session.fidl
- void AddAcquireFence(zx::event fence);
- void AddReleaseFence(zx::event fence);
-
- // Flushes queued commands and presents the resulting frame.
- void Present();
-
- private:
- // fuchsia::ui::scenic::SessionListener interface.
- void OnScenicError(fidl::StringPtr error) override;
- void OnScenicEvent(
- fidl::VectorPtr<fuchsia::ui::scenic::Event> events) override;
-
- // Allocates a new unique resource id.
- ResourceId AllocateResourceId();
-
- // Enqueues a scenic |command|.
- void EnqueueGfxCommand(fuchsia::ui::gfx::Command command);
-
- // Flushes |queued_commands_|.
- void Flush();
-
- // Unbinds |session_| and |session_listener_binding_|, which frees the
- // resources used for the session in Scenic and guarantees that we wont
- // receive SessionListener events.
- void Close();
-
- ScenicSessionListener* const listener_;
-
- fuchsia::ui::scenic::SessionPtr session_;
- fidl::Binding<fuchsia::ui::scenic::SessionListener> session_listener_binding_;
-
- ResourceId next_resource_id_ = 1u;
-
- // Used to verify that all resources are freed when the session is closed.
- int resource_count_ = 0u;
-
- fidl::VectorPtr<fuchsia::ui::scenic::Command> queued_commands_;
-
- // Pending acquire and release fences passed in the next Present() call.
- std::vector<zx::event> acquire_fences_;
- std::vector<zx::event> release_fences_;
-
- DISALLOW_COPY_AND_ASSIGN(ScenicSession);
-};
-
-} // namespace ui
-
-#endif // UI_OZONE_PLATFORM_SCENIC_SCENIC_SESSION_H_
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
index 7b444c46bdd..d104ae08484 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.cc
@@ -6,11 +6,17 @@
#include <lib/zx/event.h>
+#include "base/fuchsia/component_context.h"
+#include "base/fuchsia/fuchsia_logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/ozone/common/egl_util.h"
+#include "ui/ozone/common/gl_ozone_egl.h"
+#include "ui/ozone/platform/scenic/scenic_gpu_service.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_canvas.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
@@ -23,6 +29,37 @@ namespace ui {
namespace {
+class GLOzoneEGLScenic : public GLOzoneEGL {
+ public:
+ GLOzoneEGLScenic() = default;
+ ~GLOzoneEGLScenic() override = default;
+
+ // GLOzone:
+ scoped_refptr<gl::GLSurface> CreateViewGLSurface(
+ gfx::AcceleratedWidget window) override {
+ NOTIMPLEMENTED();
+ return nullptr;
+ }
+
+ scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface(
+ const gfx::Size& size) override {
+ return gl::InitializeGLSurface(
+ base::MakeRefCounted<gl::PbufferGLSurfaceEGL>(size));
+ }
+
+ EGLNativeDisplayType GetNativeDisplay() override {
+ return EGL_DEFAULT_DISPLAY;
+ }
+
+ protected:
+ bool LoadGLES2Bindings(gl::GLImplementation implementation) override {
+ return LoadDefaultEGLGLES2Bindings(implementation);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GLOzoneEGLScenic);
+};
+
// TODO(crbug.com/852011): Implement this class - currently it's just a stub.
class ScenicPixmap : public gfx::NativePixmap {
public:
@@ -69,31 +106,49 @@ class ScenicPixmap : public gfx::NativePixmap {
} // namespace
ScenicSurfaceFactory::ScenicSurfaceFactory(ScenicWindowManager* window_manager)
- : window_manager_(window_manager) {}
+ : window_manager_(window_manager),
+ egl_implementation_(std::make_unique<GLOzoneEGLScenic>()) {}
+
+ScenicSurfaceFactory::ScenicSurfaceFactory(ScenicGpuService* scenic_gpu_service)
+ : scenic_gpu_service_(scenic_gpu_service),
+ egl_implementation_(std::make_unique<GLOzoneEGLScenic>()) {}
ScenicSurfaceFactory::~ScenicSurfaceFactory() = default;
+fuchsia::ui::scenic::Scenic* ScenicSurfaceFactory::GetScenic() {
+ if (!scenic_) {
+ scenic_ = base::fuchsia::ComponentContext::GetDefault()
+ ->ConnectToService<fuchsia::ui::scenic::Scenic>();
+ scenic_.set_error_handler([](zx_status_t status) {
+ ZX_LOG(FATAL, status) << "Scenic connection failed";
+ });
+ }
+ return scenic_.get();
+}
+
std::vector<gl::GLImplementation>
ScenicSurfaceFactory::GetAllowedGLImplementations() {
- return std::vector<gl::GLImplementation>{};
+ // TODO(spang): Remove this after crbug.com/897208 is fixed.
+ return std::vector<gl::GLImplementation>{gl::kGLImplementationSwiftShaderGL};
}
GLOzone* ScenicSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
- NOTREACHED();
- return nullptr;
+ switch (implementation) {
+ case gl::kGLImplementationSwiftShaderGL:
+ return egl_implementation_.get();
+ default:
+ return nullptr;
+ }
}
std::unique_ptr<SurfaceOzoneCanvas> ScenicSurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget) {
+ if (!window_manager_)
+ LOG(FATAL) << "Software output not supported from GPU process";
ScenicWindow* window = window_manager_->GetWindow(widget);
if (!window)
return nullptr;
- return std::make_unique<ScenicWindowCanvas>(window);
-}
-
-std::vector<gfx::BufferFormat> ScenicSurfaceFactory::GetScanoutFormats(
- gfx::AcceleratedWidget widget) {
- return std::vector<gfx::BufferFormat>{gfx::BufferFormat::RGBA_8888};
+ return std::make_unique<ScenicWindowCanvas>(GetScenic(), window);
}
scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
@@ -107,7 +162,11 @@ scoped_refptr<gfx::NativePixmap> ScenicSurfaceFactory::CreateNativePixmap(
#if BUILDFLAG(ENABLE_VULKAN)
std::unique_ptr<gpu::VulkanImplementation>
ScenicSurfaceFactory::CreateVulkanImplementation() {
- return std::make_unique<ui::VulkanImplementationScenic>(window_manager_);
+ if (!scenic_gpu_service_)
+ LOG(FATAL) << "Vulkan implementation requires InitializeForGPU";
+
+ return std::make_unique<ui::VulkanImplementationScenic>(
+ scenic_gpu_service_->gpu_host(), GetScenic());
}
#endif
diff --git a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
index 016b09f2378..9a34b1003f4 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_surface_factory.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_FACTORY_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_SURFACE_FACTORY_H_
+#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <memory>
#include <vector>
@@ -16,10 +17,12 @@
namespace ui {
class ScenicWindowManager;
+class ScenicGpuService;
class ScenicSurfaceFactory : public SurfaceFactoryOzone {
public:
explicit ScenicSurfaceFactory(ScenicWindowManager* window_manager);
+ explicit ScenicSurfaceFactory(ScenicGpuService* scenic_gpu_service);
~ScenicSurfaceFactory() override;
// SurfaceFactoryOzone implementation.
@@ -27,8 +30,6 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget) override;
- std::vector<gfx::BufferFormat> GetScanoutFormats(
- gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
gfx::Size size,
@@ -40,7 +41,12 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
#endif
private:
- ScenicWindowManager* const window_manager_;
+ fuchsia::ui::scenic::Scenic* GetScenic();
+
+ ScenicWindowManager* const window_manager_ = nullptr;
+ ScenicGpuService* scenic_gpu_service_ = nullptr;
+ std::unique_ptr<GLOzone> egl_implementation_;
+ fuchsia::ui::scenic::ScenicPtr scenic_;
DISALLOW_COPY_AND_ASSIGN(ScenicSurfaceFactory);
};
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.cc b/chromium/ui/ozone/platform/scenic/scenic_window.cc
index c8622cd46ad..804ef7b5ae5 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.cc
@@ -22,51 +22,54 @@
namespace ui {
-ScenicWindow::ScenicWindow(
- ScenicWindowManager* window_manager,
- PlatformWindowDelegate* delegate,
- fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner>
- view_owner_request)
+ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
+ PlatformWindowDelegate* delegate,
+ zx::eventpair view_token)
: manager_(window_manager),
delegate_(delegate),
window_id_(manager_->AddWindow(this)),
event_dispatcher_(this),
view_listener_binding_(this),
- scenic_session_(manager_->GetScenic(), this),
+ scenic_session_(manager_->GetScenic()),
+ parent_node_(&scenic_session_),
+ node_(&scenic_session_),
+ input_node_(&scenic_session_),
+ render_node_(&scenic_session_),
input_listener_binding_(this) {
- // Create event pair to import parent view node to Scenic. One end is passed
- // directly to Scenic in ImportResource command and the second one is passed
- // to ViewManager::CreateView(). ViewManager will passes it to Scenic when the
- // view is added to a container.
- zx::eventpair parent_export_token;
- zx::eventpair parent_import_token;
- zx_status_t status =
- zx::eventpair::create(0u, &parent_import_token, &parent_export_token);
- ZX_CHECK(status == ZX_OK, status) << "zx_eventpair_create()";
+ scenic_session_.set_error_handler(
+ fit::bind_member(this, &ScenicWindow::OnScenicError));
+ scenic_session_.set_event_handler(
+ fit::bind_member(this, &ScenicWindow::OnScenicEvents));
- // Create a new node and add it as a child to the parent.
- parent_node_id_ = scenic_session_.ImportResource(
- fuchsia::ui::gfx::ImportSpec::NODE, std::move(parent_import_token));
- node_id_ = scenic_session_.CreateEntityNode();
- scenic_session_.AddNodeChild(parent_node_id_, node_id_);
+ // Import parent node and create event pair to pass to the ViewManager.
+ zx::eventpair parent_export_token;
+ parent_node_.BindAsRequest(&parent_export_token);
// Subscribe to metrics events from the parent node. These events are used to
// get the device pixel ratio for the screen.
- scenic_session_.SetEventMask(parent_node_id_,
- fuchsia::ui::gfx::kMetricsEventMask);
+ parent_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
+ parent_node_.AddChild(node_);
+
+ // Add input shape.
+ input_node_.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
+ node_.AddChild(input_node_);
+
+ // Add rendering subtree. Hit testing is disabled to prevent GPU process from
+ // receiving input.
+ render_node_.SetHitTestBehavior(fuchsia::ui::gfx::HitTestBehavior::kSuppress);
+ node_.AddChild(render_node_);
// Create the view.
- manager_->GetViewManager()->CreateView(
- view_.NewRequest(), std::move(view_owner_request),
+ manager_->GetViewManager()->CreateView2(
+ view_.NewRequest(), std::move(view_token),
view_listener_binding_.NewBinding(), std::move(parent_export_token),
"Chromium");
view_.set_error_handler(fit::bind_member(this, &ScenicWindow::OnViewError));
view_listener_binding_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnViewError));
- // Setup input event listener.
- // TODO(crbug.com/881591): Migrate off InputConnection and use IMEService
- // for receiving keyboard input instead.
+ // Setup ViewsV1 input event listener.
+ // TODO(crbug.com/881591): Remove this when ViewsV1 deprecation is complete.
fuchsia::sys::ServiceProviderPtr view_service_provider;
view_->GetServiceProvider(view_service_provider.NewRequest());
view_service_provider->ConnectToService(
@@ -74,31 +77,27 @@ ScenicWindow::ScenicWindow(
input_connection_.NewRequest().TakeChannel());
input_connection_->SetEventListener(input_listener_binding_.NewBinding());
- // Add shape node for window.
- shape_id_ = scenic_session_.CreateShapeNode();
- scenic_session_.AddNodeChild(node_id_, shape_id_);
- material_id_ = scenic_session_.CreateMaterial();
- scenic_session_.SetNodeMaterial(shape_id_, material_id_);
-
// Call Present() to ensure that the scenic session commands are processed,
// which is necessary to receive metrics event from Scenic.
- scenic_session_.Present();
+ scenic_session_.Present(
+ /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
delegate_->OnAcceleratedWidgetAvailable(window_id_);
}
ScenicWindow::~ScenicWindow() {
- scenic_session_.ReleaseResource(node_id_);
- scenic_session_.ReleaseResource(parent_node_id_);
- scenic_session_.ReleaseResource(shape_id_);
- scenic_session_.ReleaseResource(material_id_);
-
manager_->RemoveWindow(window_id_, this);
- view_.Unbind();
}
-void ScenicWindow::SetTexture(ScenicSession::ResourceId texture) {
- scenic_session_.SetMaterialTexture(material_id_, texture);
+void ScenicWindow::ExportRenderingEntity(zx::eventpair export_token) {
+ scenic::EntityNode export_node(&scenic_session_);
+
+ render_node_.DetachChildren();
+ render_node_.AddChild(export_node);
+
+ export_node.Export(std::move(export_token));
+ scenic_session_.Present(
+ /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
}
gfx::Rect ScenicWindow::GetBounds() {
@@ -115,15 +114,16 @@ void ScenicWindow::SetTitle(const base::string16& title) {
}
void ScenicWindow::Show() {
- NOTIMPLEMENTED();
+ parent_node_.AddChild(node_);
}
void ScenicWindow::Hide() {
- NOTIMPLEMENTED();
+ node_.Detach();
}
void ScenicWindow::Close() {
- NOTIMPLEMENTED();
+ Hide();
+ delegate_->OnClosed();
}
void ScenicWindow::PrepareForShutdown() {
@@ -201,16 +201,16 @@ void ScenicWindow::UpdateSize() {
// Translate the node by half of the view dimensions to put it in the center
// of the view.
- const float translation[] = {size_dips_.width() / 2.0,
- size_dips_.height() / 2.0, 0.f};
+ node_.SetTranslation(size_dips_.width() / 2.0, size_dips_.height() / 2.0,
+ 0.f);
- // Set node shape to rectangle that matches size of the view.
- ScenicSession::ResourceId rect_id =
- scenic_session_.CreateRectangle(size_dips_.width(), size_dips_.height());
- scenic_session_.SetNodeShape(shape_id_, rect_id);
- scenic_session_.SetNodeTranslation(shape_id_, translation);
- scenic_session_.ReleaseResource(rect_id);
- scenic_session_.Present();
+ // Scale the node so that surface rect can always be 1x1.
+ node_.SetScale(size_dips_.width(), size_dips_.height(), 1.f);
+
+ // This is necessary when using vulkan because ImagePipes are presented
+ // separately and we need to make sure our sizes change is committed.
+ scenic_session_.Present(
+ /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
delegate_->OnBoundsChanged(size_rect);
}
@@ -228,30 +228,41 @@ void ScenicWindow::OnPropertiesChanged(
callback();
}
-void ScenicWindow::OnScenicError(const std::string& error) {
- LOG(ERROR) << "ScenicSession failed: " << error;
+void ScenicWindow::OnScenicError(zx_status_t status) {
+ LOG(ERROR) << "scenic::Session failed with code " << status << ".";
delegate_->OnClosed();
}
void ScenicWindow::OnScenicEvents(
- const std::vector<fuchsia::ui::scenic::Event>& events) {
- for (const auto& event : events) {
- if (!event.is_gfx() || !event.gfx().is_metrics())
- continue;
-
- auto& metrics = event.gfx().metrics();
- if (metrics.node_id != parent_node_id_)
- continue;
-
- device_pixel_ratio_ =
- std::max(metrics.metrics.scale_x, metrics.metrics.scale_y);
-
- ScenicScreen* screen = manager_->screen();
- if (screen)
- screen->OnWindowMetrics(window_id_, device_pixel_ratio_);
-
- if (!size_dips_.IsEmpty())
- UpdateSize();
+ fidl::VectorPtr<fuchsia::ui::scenic::Event> events) {
+ for (const auto& event : *events) {
+ if (event.is_gfx()) {
+ if (!event.gfx().is_metrics())
+ continue;
+
+ auto& metrics = event.gfx().metrics();
+ if (metrics.node_id != parent_node_.id())
+ continue;
+
+ device_pixel_ratio_ =
+ std::max(metrics.metrics.scale_x, metrics.metrics.scale_y);
+
+ ScenicScreen* screen = manager_->screen();
+ if (screen)
+ screen->OnWindowMetrics(window_id_, device_pixel_ratio_);
+
+ if (!size_dips_.IsEmpty())
+ UpdateSize();
+ } else if (event.is_input()) {
+ auto& input_event = event.input();
+ if (input_event.is_focus()) {
+ delegate_->OnActivationChanged(input_event.focus().focused);
+ } else {
+ // Scenic doesn't care if the input event was handled, so ignore the
+ // "handled" status.
+ ignore_result(event_dispatcher_.ProcessEvent(input_event));
+ }
+ }
}
}
@@ -269,8 +280,8 @@ void ScenicWindow::OnEvent(fuchsia::ui::input::InputEvent event,
callback(result);
}
-void ScenicWindow::OnViewError() {
- VLOG(1) << "viewsv1::View connection was closed.";
+void ScenicWindow::OnViewError(zx_status_t status) {
+ VLOG(1) << "viewsv1::View connection was closed with code " << status << ".";
delegate_->OnClosed();
}
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window.h b/chromium/ui/ozone/platform/scenic/scenic_window.h
index 9dba22b7e9b..9bb57b78e0b 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window.h
@@ -7,6 +7,8 @@
#include <fuchsia/ui/input/cpp/fidl.h>
#include <fuchsia/ui/viewsv1/cpp/fidl.h>
+#include <lib/ui/scenic/cpp/resources.h>
+#include <lib/ui/scenic/cpp/session.h>
#include <string>
#include <vector>
@@ -18,7 +20,6 @@
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/ozone_export.h"
-#include "ui/ozone/platform/scenic/scenic_session.h"
#include "ui/platform_window/platform_window.h"
namespace ui {
@@ -27,26 +28,20 @@ class ScenicWindowManager;
class PlatformWindowDelegate;
class OZONE_EXPORT ScenicWindow : public PlatformWindow,
- public ScenicSessionListener,
public fuchsia::ui::viewsv1::ViewListener,
public fuchsia::ui::input::InputListener,
public InputEventDispatcherDelegate {
public:
// Both |window_manager| and |delegate| must outlive the ScenicWindow.
- // |view_owner_request| is passed to the view managed when creating the
- // underlying view. In order for the View to be displayed the ViewOwner must
- // be used to add the view to a ViewContainer.
+ // |view_token| is passed to Scenic to attach the view to the view tree.
ScenicWindow(ScenicWindowManager* window_manager,
PlatformWindowDelegate* delegate,
- fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner>
- view_owner_request);
+ zx::eventpair view_token);
~ScenicWindow() override;
- ScenicSession* scenic_session() { return &scenic_session_; }
- ScenicSession::ResourceId node_id() const { return node_id_; }
+ scenic::Session* scenic_session() { return &scenic_session_; }
- // Sets texture of the window to a scenic resource.
- void SetTexture(ScenicSession::ResourceId texture);
+ void ExportRenderingEntity(zx::eventpair export_token);
// PlatformWindow implementation.
gfx::Rect GetBounds() override;
@@ -77,20 +72,20 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow,
OnPropertiesChangedCallback callback) override;
// fuchsia::ui::input::InputListener interface.
+ // TODO(crbug.com/881591): Remove this when ViewsV1 deprecation is complete.
void OnEvent(fuchsia::ui::input::InputEvent event,
OnEventCallback callback) override;
- // ScenicSessionListener interface.
- void OnScenicError(const std::string& error) override;
- void OnScenicEvents(
- const std::vector<fuchsia::ui::scenic::Event>& events) override;
+ // Callbacks for |scenic_session_|.
+ void OnScenicError(zx_status_t status);
+ void OnScenicEvents(fidl::VectorPtr<fuchsia::ui::scenic::Event> events);
// InputEventDispatcher::Delegate interface.
void DispatchEvent(ui::Event* event) override;
// Error handler for |view_|. This error normally indicates the View was
// destroyed (e.g. dropping ViewOwner).
- void OnViewError();
+ void OnViewError(zx_status_t status);
void UpdateSize();
@@ -106,23 +101,23 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow,
fidl::Binding<fuchsia::ui::viewsv1::ViewListener> view_listener_binding_;
// Scenic session used for all drawing operations in this View.
- ScenicSession scenic_session_;
+ scenic::Session scenic_session_;
- // Node ID in |scenic_session_| for the parent view.
- ScenicSession::ResourceId parent_node_id_;
+ // Node in |scenic_session_| for the parent view.
+ scenic::ImportNode parent_node_;
- // Node ID in |scenic_session_| for the view.
- ScenicSession::ResourceId node_id_;
+ // Node in |scenic_session_| for the parent view.
+ scenic::EntityNode node_;
- // Shape and material resource ids for the view in the context of the scenic
- // session for the window. They are used to set shape and texture for the view
- // node.
- ScenicSession::ResourceId shape_id_;
- ScenicSession::ResourceId material_id_;
+ // Node in |scenic_session_| for receiving input that hits within our View.
+ scenic::ShapeNode input_node_;
+
+ // Node in |scenic_session_| for rendering (hit testing disabled).
+ scenic::EntityNode render_node_;
// The ratio used for translating device-independent coordinates to absolute
// pixel coordinates.
- float device_pixel_ratio_;
+ float device_pixel_ratio_ = 0.f;
// Current view size in DIPs.
gfx::SizeF size_dips_;
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc
index 623208d1d93..439e73ea33d 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.cc
@@ -5,6 +5,8 @@
#include "ui/ozone/platform/scenic/scenic_window_canvas.h"
#include "base/fuchsia/fuchsia_logging.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/writable_shared_memory_region.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
@@ -20,30 +22,41 @@ ScenicWindowCanvas::Frame::Frame() = default;
ScenicWindowCanvas::Frame::~Frame() = default;
void ScenicWindowCanvas::Frame::Initialize(gfx::Size size,
- ScenicSession* scenic) {
- memory.Unmap();
+ scenic::Session* scenic) {
+ size_t bytes_per_row =
+ size.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
+ size_t buffer_size = bytes_per_row * size.height();
- int bytes_per_row = size.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
- int buffer_size = bytes_per_row * size.height();
- if (!memory.CreateAndMapAnonymous(buffer_size)) {
+ base::WritableSharedMemoryRegion memory_region =
+ base::WritableSharedMemoryRegion::Create(buffer_size);
+ memory_mapping = memory_region.Map();
+
+ if (!memory_mapping.IsValid()) {
LOG(WARNING) << "Failed to map memory for ScenicWindowCanvas.";
- memory.Unmap();
+ memory_mapping = base::WritableSharedMemoryMapping();
surface.reset();
- } else {
- memory_id = scenic->CreateMemory(memory.GetReadOnlyHandle(),
- fuchsia::images::MemoryType::HOST_MEMORY);
- surface = SkSurface::MakeRasterDirect(
- SkImageInfo::MakeN32Premul(size.width(), size.height()),
- memory.memory(), bytes_per_row);
- dirty_region.setRect(gfx::RectToSkIRect(gfx::Rect(size)));
+ return;
}
+
+ auto read_only_memory = base::WritableSharedMemoryRegion::ConvertToReadOnly(
+ std::move(memory_region));
+ auto memory_handle =
+ base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
+ std::move(read_only_memory));
+ scenic_memory = std::make_unique<scenic::Memory>(
+ scenic, memory_handle.PassPlatformHandle(), buffer_size,
+ fuchsia::images::MemoryType::HOST_MEMORY);
+ surface = SkSurface::MakeRasterDirect(
+ SkImageInfo::MakeN32Premul(size.width(), size.height()),
+ memory_mapping.memory(), bytes_per_row);
+ dirty_region.setRect(gfx::RectToSkIRect(gfx::Rect(size)));
}
void ScenicWindowCanvas::Frame::CopyDirtyRegionFrom(const Frame& frame) {
int stride = surface->width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
for (SkRegion::Iterator i(dirty_region); !i.done(); i.next()) {
uint8_t* dst_ptr =
- static_cast<uint8_t*>(memory.memory()) +
+ static_cast<uint8_t*>(memory_mapping.memory()) +
i.rect().x() * SkColorTypeBytesPerPixel(kN32_SkColorType) +
i.rect().y() * stride;
frame.surface->readPixels(
@@ -53,28 +66,31 @@ void ScenicWindowCanvas::Frame::CopyDirtyRegionFrom(const Frame& frame) {
dirty_region.setEmpty();
}
-ScenicWindowCanvas::ScenicWindowCanvas(ScenicWindow* window) : window_(window) {
+ScenicWindowCanvas::ScenicWindowCanvas(fuchsia::ui::scenic::Scenic* scenic,
+ ScenicWindow* window)
+ : window_(window),
+ scenic_session_(scenic),
+ parent_(&scenic_session_),
+ material_(&scenic_session_) {
+ scenic::ShapeNode shape(&scenic_session_);
+ shape.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
+ shape.SetMaterial(material_);
+
+ zx::eventpair export_token;
+ parent_.BindAsRequest(&export_token);
+ parent_.AddChild(shape);
+ window_->ExportRenderingEntity(std::move(export_token));
}
-ScenicWindowCanvas::~ScenicWindowCanvas() {
- ScenicSession* scenic = window_->scenic_session();
- for (int i = 0; i < kNumBuffers; ++i) {
- if (!frames_[i].is_empty())
- scenic->ReleaseResource(frames_[i].memory_id);
- }
-}
+ScenicWindowCanvas::~ScenicWindowCanvas() = default;
void ScenicWindowCanvas::ResizeCanvas(const gfx::Size& viewport_size) {
viewport_size_ = viewport_size;
viewport_size_.SetToMax(gfx::Size(1, 1));
- ScenicSession* scenic = window_->scenic_session();
-
// Allocate new buffers with the new size.
for (int i = 0; i < kNumBuffers; ++i) {
- if (!frames_[i].is_empty())
- scenic->ReleaseResource(frames_[i].memory_id);
- frames_[i].Initialize(viewport_size_, scenic);
+ frames_[i].Initialize(viewport_size_, &scenic_session_);
}
}
@@ -128,17 +144,14 @@ void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) {
}
// Create image that wraps the buffer and attach it as texture for the node.
- ScenicSession* scenic = window_->scenic_session();
fuchsia::images::ImageInfo info;
info.width = viewport_size_.width();
info.height = viewport_size_.height();
info.stride =
viewport_size_.width() * SkColorTypeBytesPerPixel(kN32_SkColorType);
- ScenicSession::ResourceId image_id = scenic->CreateImage(
- frames_[current_frame_].memory_id, 0, std::move(info));
-
- window_->SetTexture(image_id);
- scenic->ReleaseResource(image_id);
+ scenic::Image image(*frames_[current_frame_].scenic_memory, 0,
+ std::move(info));
+ material_.SetTexture(image);
// Create release fence for the current buffer or reset it if it already
// exists.
@@ -159,10 +172,9 @@ void ScenicWindowCanvas::PresentCanvas(const gfx::Rect& damage) {
auto status = frames_[current_frame_].release_fence.duplicate(
ZX_RIGHT_SAME_RIGHTS, &release_fence_dup);
ZX_CHECK(status == ZX_OK, status);
- scenic->AddReleaseFence(std::move(release_fence_dup));
-
- // Present the frame.
- scenic->Present();
+ scenic_session_.EnqueueReleaseFence(std::move(release_fence_dup));
+ scenic_session_.Present(/*presentation_time=*/0,
+ [](fuchsia::images::PresentationInfo info) {});
// Move to the next buffer.
current_frame_ = (current_frame_ + 1) % kNumBuffers;
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h
index 57013c2e326..8d366fbc06e 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h
+++ b/chromium/ui/ozone/platform/scenic/scenic_window_canvas.h
@@ -5,14 +5,20 @@
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_CANVAS_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_CANVAS_H_
+#include <lib/ui/scenic/cpp/resources.h>
+
#include "base/macros.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_mapping.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/ozone/platform/scenic/scenic_session.h"
+#include "ui/ozone/platform/scenic/scenic_surface_factory.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
+namespace scenic {
+class Session;
+} // namespace scenic
+
namespace ui {
class ScenicWindow;
@@ -21,9 +27,10 @@ class ScenicWindow;
// ScenicWindow.
class ScenicWindowCanvas : public SurfaceOzoneCanvas {
public:
- // |window| must outlive the surface. ScenicWindow owns the ScenicSession used
- // in this class for all drawing operations.
- explicit ScenicWindowCanvas(ScenicWindow* window);
+ // |window| must outlive the surface. ScenicWindow owns the scenic::Session
+ // used in this class for all drawing operations.
+ explicit ScenicWindowCanvas(fuchsia::ui::scenic::Scenic* scenic,
+ ScenicWindow* window);
~ScenicWindowCanvas() override;
// SurfaceOzoneCanvas implementation.
@@ -43,23 +50,23 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas {
// Allocates and maps memory for a frame of |size| (in physical in pixels)
// and then registers it with |scenic|.
- void Initialize(gfx::Size size, ScenicSession* scenic);
+ void Initialize(gfx::Size size, scenic::Session* scenic);
// Copies pixels covered by |dirty_region| from another |frame|.
void CopyDirtyRegionFrom(const Frame& frame);
- bool is_empty() { return memory.mapped_size() == 0; }
+ bool is_empty() { return !surface; }
// Shared memory for the buffer.
- base::SharedMemory memory;
+ base::WritableSharedMemoryMapping memory_mapping;
- // SkSurface that wraps |memory|.
- sk_sp<SkSurface> surface;
+ // Scenic Memory resource for |memory_region|.
+ std::unique_ptr<scenic::Memory> scenic_memory;
- // Valid only when |memory| is set.
- ScenicSession::ResourceId memory_id;
+ // SkSurface that wraps |memory_mapping|.
+ sk_sp<SkSurface> surface;
- // Fence that will be release by Scenic when it stops using this frame.
+ // Fence that will be released by Scenic when it stops using this frame.
zx::event release_fence;
// The region of the frame that's not up-to-date.
@@ -76,6 +83,10 @@ class ScenicWindowCanvas : public SurfaceOzoneCanvas {
// View size in device pixels.
gfx::Size viewport_size_;
+ scenic::Session scenic_session_;
+ scenic::ImportNode parent_;
+ scenic::Material material_;
+
DISALLOW_COPY_AND_ASSIGN(ScenicWindowCanvas);
};
diff --git a/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc b/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc
index cf900feccd1..cbb3ba49026 100644
--- a/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc
+++ b/chromium/ui/ozone/platform/scenic/scenic_window_manager.cc
@@ -23,8 +23,10 @@ fuchsia::ui::viewsv1::ViewManager* ScenicWindowManager::GetViewManager() {
if (!view_manager_) {
view_manager_ = base::fuchsia::ComponentContext::GetDefault()
->ConnectToService<fuchsia::ui::viewsv1::ViewManager>();
- view_manager_.set_error_handler([this]() {
- LOG(ERROR) << "The ViewManager channel was unexpectedly terminated.";
+ view_manager_.set_error_handler([](zx_status_t status) {
+ LOG(ERROR)
+ << "The ViewManager channel was unexpectedly terminated with status "
+ << status << ".";
});
}
@@ -33,8 +35,9 @@ fuchsia::ui::viewsv1::ViewManager* ScenicWindowManager::GetViewManager() {
fuchsia::ui::scenic::Scenic* ScenicWindowManager::GetScenic() {
if (!scenic_) {
- GetViewManager()->GetScenic(scenic_.NewRequest());
- scenic_.set_error_handler([this]() {
+ scenic_ = base::fuchsia::ComponentContext::GetDefault()
+ ->ConnectToService<fuchsia::ui::scenic::Scenic>();
+ scenic_.set_error_handler([](zx_status_t status) {
LOG(ERROR) << "The Scenic channel was unexpectedly terminated.";
});
}
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
index a8af3f8b847..27a79babbbe 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.cc
@@ -4,14 +4,19 @@
#include "ui/ozone/platform/scenic/vulkan_implementation_scenic.h"
+#include <lib/ui/scenic/cpp/commands.h>
+#include <lib/ui/scenic/cpp/session.h>
#include <lib/zx/channel.h>
+#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/fuchsia/fuchsia_logging.h"
+#include "base/macros.h"
#include "base/native_library.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_instance.h"
#include "gpu/vulkan/vulkan_surface.h"
+#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/ozone/platform/scenic/scenic_window.h"
#include "ui/ozone/platform/scenic/scenic_window_manager.h"
@@ -19,9 +24,71 @@
namespace ui {
+namespace {
+
+// Holds resources necessary for presenting to a View using a VkSurfaceKHR.
+class ScenicSurface {
+ public:
+ ScenicSurface(fuchsia::ui::scenic::Scenic* scenic,
+ mojom::ScenicGpuHost* gpu_host,
+ gfx::AcceleratedWidget window)
+ : scenic_(scenic),
+ parent_(&scenic_),
+ shape_(&scenic_),
+ material_(&scenic_),
+ gpu_host_(gpu_host),
+ window_(window) {
+ shape_.SetShape(scenic::Rectangle(&scenic_, 1.f, 1.f));
+ shape_.SetMaterial(material_);
+ }
+
+ // Sets the texture of the surface to a new image pipe.
+ void SetTextureToNewImagePipe(
+ fidl::InterfaceRequest<fuchsia::images::ImagePipe> image_pipe_request) {
+ uint32_t image_pipe_id = scenic_.AllocResourceId();
+ scenic_.Enqueue(scenic::NewCreateImagePipeCmd(
+ image_pipe_id, std::move(image_pipe_request)));
+ material_.SetTexture(image_pipe_id);
+ scenic_.ReleaseResource(image_pipe_id);
+ }
+
+ // Links the surface to the window in the browser process.
+ //
+ // Scenic does not care about order here; it's totally fine for imports to
+ // cause exports, and that's what's done here.
+ void LinkToParent() {
+ zx::eventpair export_token;
+ parent_.BindAsRequest(&export_token);
+ parent_.AddChild(shape_);
+ gpu_host_->ExportParent(window_,
+ mojo::WrapPlatformHandle(
+ mojo::PlatformHandle(std::move(export_token))));
+ }
+
+ // Flushes commands to scenic & executes them.
+ void Commit() {
+ scenic_.Present(
+ /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
+ }
+
+ private:
+ scenic::Session scenic_;
+ scenic::ImportNode parent_;
+ scenic::ShapeNode shape_;
+ scenic::Material material_;
+
+ mojom::ScenicGpuHost* gpu_host_ = nullptr;
+ gfx::AcceleratedWidget window_ = gfx::kNullAcceleratedWidget;
+
+ DISALLOW_COPY_AND_ASSIGN(ScenicSurface);
+};
+
+} // namespace
+
VulkanImplementationScenic::VulkanImplementationScenic(
- ScenicWindowManager* scenic_window_manager)
- : scenic_window_manager_(scenic_window_manager) {}
+ mojom::ScenicGpuHost* scenic_gpu_host,
+ fuchsia::ui::scenic::Scenic* scenic)
+ : scenic_gpu_host_(scenic_gpu_host), scenic_(scenic) {}
VulkanImplementationScenic::~VulkanImplementationScenic() = default;
@@ -72,16 +139,14 @@ VkInstance VulkanImplementationScenic::GetVulkanInstance() {
std::unique_ptr<gpu::VulkanSurface>
VulkanImplementationScenic::CreateViewSurface(gfx::AcceleratedWidget window) {
- ScenicWindow* scenic_window = scenic_window_manager_->GetWindow(window);
- if (!scenic_window)
- return nullptr;
- ScenicSession* scenic_session = scenic_window->scenic_session();
+ auto scenic_surface =
+ std::make_unique<ScenicSurface>(scenic_, scenic_gpu_host_, window);
+
+ // Attach the surface to the window.
+ scenic_surface->LinkToParent();
+
fuchsia::images::ImagePipePtr image_pipe;
- ScenicSession::ResourceId image_pipe_id =
- scenic_session->CreateImagePipe(image_pipe.NewRequest());
- scenic_window->SetTexture(image_pipe_id);
- scenic_session->ReleaseResource(image_pipe_id);
- scenic_session->Present();
+ scenic_surface->SetTextureToNewImagePipe(image_pipe.NewRequest());
VkSurfaceKHR surface;
VkMagmaSurfaceCreateInfoKHR surface_create_info = {};
@@ -98,7 +163,17 @@ VulkanImplementationScenic::CreateViewSurface(gfx::AcceleratedWidget window) {
LOG(FATAL) << "vkCreateMagmaSurfaceKHR failed: " << result;
}
- return std::make_unique<gpu::VulkanSurface>(GetVulkanInstance(), surface);
+ // Execute the initialization commands. Once this is done we won't need to
+ // make any further changes to ScenicSurface other than to keep it alive; the
+ // texture can be replaced through the vulkan swapchain API.
+ scenic_surface->Commit();
+
+ auto destruction_callback =
+ base::BindOnce(base::DoNothing::Once<std::unique_ptr<ScenicSurface>>(),
+ std::move(scenic_surface));
+
+ return std::make_unique<gpu::VulkanSurface>(GetVulkanInstance(), surface,
+ std::move(destruction_callback));
}
bool VulkanImplementationScenic::GetPhysicalDevicePresentationSupport(
diff --git a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
index ecd61cd04f6..3f859adfee2 100644
--- a/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
+++ b/chromium/ui/ozone/platform/scenic/vulkan_implementation_scenic.h
@@ -5,18 +5,19 @@
#ifndef UI_OZONE_PLATFORM_SCENIC_VULKAN_IMPLEMENTATION_SCENIC_H_
#define UI_OZONE_PLATFORM_SCENIC_VULKAN_IMPLEMENTATION_SCENIC_H_
+#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <memory>
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_instance.h"
+#include "ui/ozone/public/interfaces/scenic_gpu_host.mojom.h"
namespace ui {
-class ScenicWindowManager;
-
class VulkanImplementationScenic : public gpu::VulkanImplementation {
public:
- VulkanImplementationScenic(ScenicWindowManager* scenic_window_manager);
+ VulkanImplementationScenic(mojom::ScenicGpuHost* scenic_gpu_host,
+ fuchsia::ui::scenic::Scenic* scenic);
~VulkanImplementationScenic() override;
// VulkanImplementation:
@@ -35,7 +36,8 @@ class VulkanImplementationScenic : public gpu::VulkanImplementation {
VkFence vk_fence) override;
private:
- ScenicWindowManager* const scenic_window_manager_;
+ mojom::ScenicGpuHost* const scenic_gpu_host_;
+ fuchsia::ui::scenic::Scenic* const scenic_;
gpu::VulkanInstance vulkan_instance_;
PFN_vkVoidFunction vkCreateMagmaSurfaceKHR_ = nullptr;
diff --git a/chromium/ui/ozone/platform/wayland/BUILD.gn b/chromium/ui/ozone/platform/wayland/BUILD.gn
index 9740ad91b26..d3d30fc8787 100644
--- a/chromium/ui/ozone/platform/wayland/BUILD.gn
+++ b/chromium/ui/ozone/platform/wayland/BUILD.gn
@@ -88,9 +88,9 @@ source_set("wayland") {
deps = [
"//base",
+ "//build/config/linux/libdrm",
"//mojo/public/cpp/bindings",
"//skia",
- "//third_party/libdrm",
"//third_party/minigbm",
"//third_party/wayland:wayland_client",
"//third_party/wayland-protocols:linux_dmabuf_protocol",
@@ -113,7 +113,7 @@ source_set("wayland") {
"//ui/gfx/geometry",
"//ui/ozone:ozone_base",
"//ui/ozone/common",
- "//ui/ozone/common/linux",
+ "//ui/ozone/common/linux:drm",
"//ui/ozone/public/interfaces/wayland:wayland_interfaces",
"//ui/platform_window",
"//ui/platform_window/platform_window_handler",
@@ -135,10 +135,9 @@ source_set("wayland") {
]
deps += [
- "//third_party/libdrm",
- "//third_party/minigbm",
+ "//build/config/linux/libdrm",
"//ui/gfx:memory_buffer",
- "//ui/ozone/common/linux",
+ "//ui/ozone/common/linux:gbm",
]
}
diff --git a/chromium/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc b/chromium/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
index 110dc9f3ab2..7f839c822a6 100644
--- a/chromium/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
@@ -4,49 +4,15 @@
#include "ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.h"
-#include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
#include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h"
#include "ui/ozone/common/stub_client_native_pixmap_factory.h"
#include "ui/ozone/public/ozone_platform.h"
namespace ui {
-// Implements ClientNativePixmapFactory to provide a more accurate buffer format
-// support when Wayland dmabuf is used.
-class ClientNativePixmapFactoryWayland : public gfx::ClientNativePixmapFactory {
- public:
- ClientNativePixmapFactoryWayland() {
- dmabuf_factory_.reset(gfx::CreateClientNativePixmapFactoryDmabuf());
- }
- ~ClientNativePixmapFactoryWayland() override {}
-
- // ClientNativePixmapFactory overrides:
- bool IsConfigurationSupported(gfx::BufferFormat format,
- gfx::BufferUsage usage) const override {
- OzonePlatform::PlatformProperties properties =
- OzonePlatform::GetInstance()->GetPlatformProperties();
- for (auto buffer_format : properties.supported_buffer_formats) {
- if (buffer_format == format)
- return dmabuf_factory_->IsConfigurationSupported(format, usage);
- }
- return false;
- }
-
- std::unique_ptr<gfx::ClientNativePixmap> ImportFromHandle(
- const gfx::NativePixmapHandle& handle,
- const gfx::Size& size,
- gfx::BufferUsage usage) override {
- return dmabuf_factory_->ImportFromHandle(handle, size, usage);
- }
-
- private:
- std::unique_ptr<ClientNativePixmapFactory> dmabuf_factory_;
- DISALLOW_COPY_AND_ASSIGN(ClientNativePixmapFactoryWayland);
-};
-
gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryWayland() {
#if defined(WAYLAND_GBM)
- return new ClientNativePixmapFactoryWayland();
+ return gfx::CreateClientNativePixmapFactoryDmabuf();
#else
return CreateStubClientNativePixmapFactory();
#endif
diff --git a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index c08798ab0f5..62d42fcc06f 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -58,13 +58,7 @@ bool GbmPixmapWayland::InitializeBuffer(gfx::Size size,
break;
case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
- // mmap cannot be used with gbm buffers on a different process. That is,
- // Linux disallows this and "permission denied" is returned. To overcome
- // this and make software rasterization working, buffers must be created
- // on the browser process and gbm_bo_map must be used.
- // TODO(msisov): add support fir these two buffer usage cases.
- // https://crbug.com/864914
- LOG(FATAL) << "This scenario is not supported in Wayland now";
+ flags = GBM_BO_USE_LINEAR;
break;
default:
NOTREACHED() << "Not supported buffer format";
diff --git a/chromium/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h b/chromium/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
index f06f9b9aada..7c3d0725e5f 100644
--- a/chromium/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
+++ b/chromium/ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h
@@ -15,7 +15,7 @@
#include "ui/ozone/public/interfaces/wayland/wayland_connection.mojom.h"
#if defined(WAYLAND_GBM)
-#include "ui/ozone/common/linux/gbm_device.h"
+#include "ui/ozone/common/linux/gbm_device.h" // nogncheck
#endif
struct wl_shm;
diff --git a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index ddddd861527..0bba90d5b5d 100644
--- a/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/chromium/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -10,6 +10,7 @@
#include "ui/display/manager/fake_display_delegate.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/system_input_injector.h"
+#include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
@@ -21,7 +22,6 @@
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/platform_screen.h"
#include "ui/platform_window/platform_window_init_properties.h"
#if BUILDFLAG(USE_XKBCOMMON)
@@ -42,21 +42,25 @@ namespace ui {
namespace {
-class OzonePlatformWayland : public OzonePlatform {
- public:
- OzonePlatformWayland() {
+constexpr OzonePlatform::PlatformProperties kWaylandPlatformProperties = {
+ /*needs_view_token=*/false,
+
// Supporting server-side decorations requires a support of xdg-decorations.
// But this protocol has been accepted into the upstream recently, and it
// will take time before it is taken by compositors. For now, always use
// custom frames and disallow switching to server-side frames.
// https://github.com/wayland-project/wayland-protocols/commit/76d1ae8c65739eff3434ef219c58a913ad34e988
- properties_.custom_frame_pref_default = true;
- properties_.use_system_title_bar = false;
+ /*custom_frame_pref_default=*/true,
+ /*use_system_title_bar=*/false,
+
// Ozone/Wayland relies on the mojo communication when running in
// !single_process.
// TODO(msisov, rjkroege): Remove after http://crbug.com/806092.
- properties_.requires_mojo = true;
- }
+ /*requires_mojo=*/true};
+
+class OzonePlatformWayland : public OzonePlatform {
+ public:
+ OzonePlatformWayland() {}
~OzonePlatformWayland() override {}
// OzonePlatform
@@ -114,6 +118,18 @@ class OzonePlatformWayland : public OzonePlatform {
return connection_->wayland_output_manager()->CreateWaylandScreen();
}
+ bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage) const override {
+ if (std::find(supported_buffer_formats_.begin(),
+ supported_buffer_formats_.end(),
+ format) == supported_buffer_formats_.end()) {
+ return false;
+ }
+
+ return gfx::ClientNativePixmapDmaBuf::IsConfigurationSupported(format,
+ usage);
+ }
+
void InitializeUI(const InitParams& args) override {
#if BUILDFLAG(USE_XKBCOMMON)
KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
@@ -136,6 +152,7 @@ class OzonePlatformWayland : public OzonePlatform {
overlay_manager_.reset(new StubOverlayManager);
input_controller_ = CreateStubInputController();
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
+ supported_buffer_formats_ = connection_->GetSupportedBufferFormats();
}
void InitializeGPU(const InitParams& args) override {
@@ -164,11 +181,7 @@ class OzonePlatformWayland : public OzonePlatform {
}
const PlatformProperties& GetPlatformProperties() override {
- if (connection_ && properties_.supported_buffer_formats.empty()) {
- properties_.supported_buffer_formats =
- connection_->GetSupportedBufferFormats();
- }
- return properties_;
+ return kWaylandPlatformProperties;
}
void AddInterfaces(service_manager::BinderRegistry* registry) override {
@@ -200,7 +213,7 @@ class OzonePlatformWayland : public OzonePlatform {
std::unique_ptr<WaylandConnectionProxy> proxy_;
std::unique_ptr<WaylandConnectionConnector> connector_;
- PlatformProperties properties_;
+ std::vector<gfx::BufferFormat> supported_buffer_formats_;
DISALLOW_COPY_AND_ASSIGN(OzonePlatformWayland);
};
diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc
index 59f2b128297..393336d1371 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.cc
@@ -313,7 +313,11 @@ void WaylandBufferManager::CreateSucceededInternal(
}
}
- DCHECK(buffer);
+ // It can happen that buffer was destroyed by a client while the Wayland
+ // compositor was processing a request to create a wl_buffer.
+ if (!buffer)
+ return;
+
buffer->wl_buffer.reset(new_buffer);
buffer->params = nullptr;
zwp_linux_buffer_params_v1_destroy(params);
@@ -328,6 +332,21 @@ void WaylandBufferManager::OnBufferSwapped(Buffer* buffer) {
.Run(buffer->swap_result, std::move(buffer->feedback));
}
+void WaylandBufferManager::AddSupportedFourCCFormat(uint32_t fourcc_format) {
+ // Return on not the supported fourcc format.
+ if (!IsValidBufferFormat(fourcc_format))
+ return;
+
+ // It can happen that ::Format or ::Modifiers call can have already added such
+ // a format. Thus, we can ignore that format.
+ gfx::BufferFormat format = GetBufferFormatFromFourCCFormat(fourcc_format);
+ auto it = std::find(supported_buffer_formats_.begin(),
+ supported_buffer_formats_.end(), format);
+ if (it != supported_buffer_formats_.end())
+ return;
+ supported_buffer_formats_.push_back(format);
+}
+
// static
void WaylandBufferManager::Modifiers(
void* data,
@@ -335,7 +354,9 @@ void WaylandBufferManager::Modifiers(
uint32_t format,
uint32_t modifier_hi,
uint32_t modifier_lo) {
- NOTIMPLEMENTED();
+ WaylandBufferManager* self = static_cast<WaylandBufferManager*>(data);
+ if (self)
+ self->AddSupportedFourCCFormat(format);
}
// static
@@ -343,11 +364,8 @@ void WaylandBufferManager::Format(void* data,
struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf,
uint32_t format) {
WaylandBufferManager* self = static_cast<WaylandBufferManager*>(data);
- // Return on not the supported ARGB format.
- if (format == DRM_FORMAT_ARGB2101010)
- return;
- self->supported_buffer_formats_.push_back(
- GetBufferFormatFromFourCCFormat(format));
+ if (self)
+ self->AddSupportedFourCCFormat(format);
}
// static
@@ -356,7 +374,6 @@ void WaylandBufferManager::CreateSucceeded(
struct zwp_linux_buffer_params_v1* params,
struct wl_buffer* new_buffer) {
WaylandBufferManager* self = static_cast<WaylandBufferManager*>(data);
-
DCHECK(self);
self->CreateSucceededInternal(params, new_buffer);
}
diff --git a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.h b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.h
index f2917fd47e7..482b98a7333 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_buffer_manager.h
@@ -151,6 +151,8 @@ class WaylandBufferManager {
void OnBufferSwapped(Buffer* buffer);
+ void AddSupportedFourCCFormat(uint32_t fourcc_format);
+
// zwp_linux_dmabuf_v1_listener
static void Modifiers(void* data,
struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf,
diff --git a/chromium/ui/ozone/platform/wayland/wayland_connection.cc b/chromium/ui/ozone/platform/wayland/wayland_connection.cc
index d4ce8fb5668..72c8d8b527d 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_connection.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_connection.cc
@@ -27,7 +27,7 @@ namespace ui {
namespace {
constexpr uint32_t kMaxCompositorVersion = 4;
-constexpr uint32_t kMaxLinuxDmabufVersion = 1;
+constexpr uint32_t kMaxLinuxDmabufVersion = 3;
constexpr uint32_t kMaxSeatVersion = 4;
constexpr uint32_t kMaxShmVersion = 1;
constexpr uint32_t kMaxXdgShellVersion = 1;
@@ -98,7 +98,7 @@ bool WaylandConnection::StartProcessingEvents() {
DCHECK(display_);
wl_display_flush(display_.get());
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
if (!base::MessageLoopCurrentForUI::Get()->WatchFileDescriptor(
wl_display_get_fd(display_.get()), true,
base::MessagePumpLibevent::WATCH_READ, &controller_, this))
@@ -111,7 +111,7 @@ bool WaylandConnection::StartProcessingEvents() {
void WaylandConnection::ScheduleFlush() {
if (scheduled_flush_ || !watching_)
return;
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&WaylandConnection::Flush, base::Unretained(this)));
@@ -176,7 +176,7 @@ void WaylandConnection::CreateZwpLinuxDmabuf(
const std::vector<uint64_t>& modifiers,
uint32_t planes_count,
uint32_t buffer_id) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
if (!buffer_manager_->CreateBuffer(std::move(file), width, height, strides,
offsets, format, modifiers, planes_count,
buffer_id)) {
@@ -185,7 +185,7 @@ void WaylandConnection::CreateZwpLinuxDmabuf(
}
void WaylandConnection::DestroyZwpLinuxDmabuf(uint32_t buffer_id) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
if (!buffer_manager_->DestroyBuffer(buffer_id)) {
TerminateGpuProcess(buffer_manager_->error_message());
}
@@ -196,7 +196,7 @@ void WaylandConnection::ScheduleBufferSwap(
uint32_t buffer_id,
const gfx::Rect& damage_region,
ScheduleBufferSwapCallback callback) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
if (!buffer_manager_->ScheduleBufferSwap(widget, buffer_id, damage_region,
std::move(callback))) {
TerminateGpuProcess(buffer_manager_->error_message());
diff --git a/chromium/ui/ozone/platform/wayland/wayland_surface_factory.cc b/chromium/ui/ozone/platform/wayland/wayland_surface_factory.cc
index a5b1dec0d3b..83fb59de100 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_surface_factory.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_surface_factory.cc
@@ -11,6 +11,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory.h"
#include "third_party/skia/include/core/SkSurface.h"
+#include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h"
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.cc b/chromium/ui/ozone/platform/wayland/wayland_window.cc
index 27ddd18e8cd..3c3a59001ac 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_window.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/base/hit_test.h"
#include "ui/events/event.h"
@@ -74,13 +75,22 @@ WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
: delegate_(delegate),
connection_(connection),
xdg_shell_objects_factory_(new XDGShellObjectFactory()),
- state_(PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL) {
+ state_(PlatformWindowState::PLATFORM_WINDOW_STATE_NORMAL),
+ pending_state_(PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN) {
// Set a class property key, which allows |this| to be used for interactive
// events, e.g. move or resize.
SetWmMoveResizeHandler(this, AsWmMoveResizeHandler());
+
+ // Set a class property key, which allows |this| to be used for drag action.
+ SetWmDragHandler(this, this);
}
WaylandWindow::~WaylandWindow() {
+ if (drag_closed_callback_) {
+ std::move(drag_closed_callback_)
+ .Run(DragDropTypes::DragOperation::DRAG_NONE);
+ }
+
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
connection_->RemoveWindow(surface_.id());
@@ -215,6 +225,15 @@ void WaylandWindow::DispatchHostWindowDragMovement(
connection_->ScheduleFlush();
}
+void WaylandWindow::StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ base::OnceCallback<void(int)> callback) {
+ DCHECK(!drag_closed_callback_);
+ drag_closed_callback_ = std::move(callback);
+ connection_->StartDrag(data, operation);
+}
+
void WaylandWindow::Show() {
if (!is_tooltip_) // Tooltip windows should not get keyboard focus
set_keyboard_focus(true);
@@ -296,6 +315,17 @@ bool WaylandWindow::HasCapture() const {
void WaylandWindow::ToggleFullscreen() {
DCHECK(xdg_surface_);
+ // There are some cases, when Chromium triggers a fullscreen state change
+ // before the surface is activated. In such cases, Wayland may ignore state
+ // changes and such flags as --kiosk or --start-fullscreen will be ignored.
+ // To overcome this, set a pending state, and once the surface is activated,
+ // trigger the change.
+ if (!is_active_) {
+ DCHECK(!IsFullscreen());
+ pending_state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN;
+ return;
+ }
+
// TODO(msisov, tonikitoo): add multiscreen support. As the documentation says
// if xdg_surface_set_fullscreen() is not provided with wl_output, it's up to
// the compositor to choose which display will be used to map this surface.
@@ -468,7 +498,7 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
// Ensure that manually handled state changes to fullscreen correspond to the
// configuration events from a compositor.
- DCHECK(is_fullscreen == IsFullscreen());
+ DCHECK_EQ(is_fullscreen, IsFullscreen());
// There are two cases, which must be handled for the minimized state.
// The first one is the case, when the surface goes into the minimized state
@@ -525,6 +555,8 @@ void WaylandWindow::HandleSurfaceConfigure(int32_t width,
if (did_active_change)
delegate_->OnActivationChanged(is_active_);
+
+ MaybeTriggerPendingStateChange();
}
void WaylandWindow::OnCloseRequest() {
@@ -556,7 +588,7 @@ void WaylandWindow::OnDragLeave() {
}
void WaylandWindow::OnDragSessionClose(uint32_t dnd_action) {
- NOTIMPLEMENTED_LOG_ONCE();
+ std::move(drag_closed_callback_).Run(dnd_action);
}
bool WaylandWindow::IsMinimized() const {
@@ -571,6 +603,16 @@ bool WaylandWindow::IsFullscreen() const {
return state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN;
}
+void WaylandWindow::MaybeTriggerPendingStateChange() {
+ if (pending_state_ == PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN ||
+ !is_active_)
+ return;
+ DCHECK_EQ(pending_state_,
+ PlatformWindowState::PLATFORM_WINDOW_STATE_FULLSCREEN);
+ pending_state_ = PlatformWindowState::PLATFORM_WINDOW_STATE_UNKNOWN;
+ ToggleFullscreen();
+}
+
WaylandWindow* WaylandWindow::GetParentWindow(
gfx::AcceleratedWidget parent_widget) {
WaylandWindow* parent_window = connection_->GetWindow(parent_widget);
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window.h b/chromium/ui/ozone/platform/wayland/wayland_window.h
index e1cb0f6b85d..7e54fb49f11 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window.h
+++ b/chromium/ui/ozone/platform/wayland/wayland_window.h
@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/geometry/rect.h"
@@ -12,6 +13,7 @@
#include "ui/ozone/platform/wayland/wayland_object.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
+#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
#include "ui/platform_window/platform_window_handler/wm_move_resize_handler.h"
namespace gfx {
@@ -35,7 +37,8 @@ class XDGShellObjectFactory;
class WaylandWindow : public PlatformWindow,
public PlatformEventDispatcher,
- public WmMoveResizeHandler {
+ public WmMoveResizeHandler,
+ public WmDragHandler {
public:
WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection);
@@ -81,6 +84,12 @@ class WaylandWindow : public PlatformWindow,
int hittest,
const gfx::Point& pointer_location) override;
+ // WmDragHandler
+ void StartDrag(const ui::OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ base::OnceCallback<void(int)> callback) override;
+
// PlatformWindow
void Show() override;
void Hide() override;
@@ -129,6 +138,8 @@ class WaylandWindow : public PlatformWindow,
bool IsMaximized() const;
bool IsFullscreen() const;
+ void MaybeTriggerPendingStateChange();
+
// Creates a popup window, which is visible as a menu window.
void CreateXdgPopup();
// Creates a surface window, which is visible as a main window.
@@ -160,6 +171,8 @@ class WaylandWindow : public PlatformWindow,
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
+ base::OnceCallback<void(int)> drag_closed_callback_;
+
gfx::Rect bounds_;
gfx::Rect pending_bounds_;
// The bounds of our window before we were maximized or fullscreen.
@@ -171,6 +184,9 @@ class WaylandWindow : public PlatformWindow,
// Stores current states of the window.
ui::PlatformWindowState state_;
+ // Stores a pending state of the window, which is used before the surface is
+ // activated.
+ ui::PlatformWindowState pending_state_;
bool is_active_ = false;
bool is_minimizing_ = false;
diff --git a/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc b/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc
index a97b92ebc94..abc14e67394 100644
--- a/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc
+++ b/chromium/ui/ozone/platform/wayland/wayland_window_unittest.cc
@@ -219,6 +219,8 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
EXPECT_EQ(PLATFORM_WINDOW_STATE_NORMAL, window_->GetPlatformWindowState());
ScopedWlArray states = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 1, states.get());
+ Sync();
AddStateToWlArray(XDG_SURFACE_STATE_FULLSCREEN, states.get());
@@ -230,7 +232,7 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
// comment in the WaylandWindow::ToggleFullscreen.
EXPECT_EQ(window_->GetPlatformWindowState(),
PLATFORM_WINDOW_STATE_FULLSCREEN);
- SendConfigureEvent(0, 0, 1, states.get());
+ SendConfigureEvent(0, 0, 2, states.get());
Sync();
EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen());
@@ -240,7 +242,45 @@ TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
EXPECT_EQ(window_->GetPlatformWindowState(), PLATFORM_WINDOW_STATE_UNKNOWN);
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 3, states.get());
+ Sync();
+}
+
+TEST_P(WaylandWindowTest, StartWithFullscreen) {
+ // Make sure the window is initialized to normal state from the beginning.
+ EXPECT_EQ(PLATFORM_WINDOW_STATE_NORMAL, window_->GetPlatformWindowState());
+
+ // The state must not be changed to the fullscreen before the surface is
+ // activated.
+ EXPECT_CALL(*GetXdgSurface(), SetFullscreen()).Times(0);
+ EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
+ window_->ToggleFullscreen();
+ // The state of the window must still be a normal one.
+ EXPECT_EQ(window_->GetPlatformWindowState(), PLATFORM_WINDOW_STATE_NORMAL);
+
+ Sync();
+
+ // Once the surface will be activated, the window will automatically trigger
+ // the state change.
+ EXPECT_CALL(*GetXdgSurface(), SetFullscreen());
+ EXPECT_CALL(delegate_,
+ OnWindowStateChanged(Eq(PLATFORM_WINDOW_STATE_FULLSCREEN)));
+
+ // Activate the surface.
+ ScopedWlArray states = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 1, states.get());
+
+ Sync();
+
+ // The wayland window manually handles the fullscreen state changes, and it
+ // must change to a fullscreen before the state change is confirmed by the
+ // wayland. See comment in the WaylandWindow::ToggleFullscreen.
+ EXPECT_EQ(window_->GetPlatformWindowState(),
+ PLATFORM_WINDOW_STATE_FULLSCREEN);
+
+ AddStateToWlArray(XDG_SURFACE_STATE_FULLSCREEN, states.get());
SendConfigureEvent(0, 0, 2, states.get());
+
Sync();
}
@@ -314,6 +354,8 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
const gfx::Rect current_bounds = window_->GetBounds();
ScopedWlArray states = InitializeWlArrayWithActivatedState();
+ SendConfigureEvent(0, 0, 1, states.get());
+ Sync();
gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
EXPECT_EQ(restored_bounds, gfx::Rect());
@@ -323,7 +365,7 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
window_->ToggleFullscreen();
AddStateToWlArray(XDG_SURFACE_STATE_FULLSCREEN, states.get());
- SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 1,
+ SendConfigureEvent(fullscreen_bounds.width(), fullscreen_bounds.height(), 2,
states.get());
Sync();
restored_bounds = window_->GetRestoredBoundsInPixels();
@@ -338,7 +380,7 @@ TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
window_->Restore();
// Reinitialize wl_array, which removes previous old states.
states = InitializeWlArrayWithActivatedState();
- SendConfigureEvent(0, 0, 2, states.get());
+ SendConfigureEvent(0, 0, 3, states.get());
Sync();
bounds = window_->GetBounds();
EXPECT_EQ(bounds, restored_bounds);
diff --git a/chromium/ui/ozone/platform/x11/BUILD.gn b/chromium/ui/ozone/platform/x11/BUILD.gn
index 5de8d7166c1..4910fe34e0a 100644
--- a/chromium/ui/ozone/platform/x11/BUILD.gn
+++ b/chromium/ui/ozone/platform/x11/BUILD.gn
@@ -24,6 +24,10 @@ source_set("x11") {
"x11_cursor_factory_ozone.h",
"x11_cursor_ozone.cc",
"x11_cursor_ozone.h",
+ "x11_display_fetcher_ozone.cc",
+ "x11_display_fetcher_ozone.h",
+ "x11_screen_ozone.cc",
+ "x11_screen_ozone.h",
"x11_surface_factory.cc",
"x11_surface_factory.h",
"x11_window_manager_ozone.cc",
@@ -59,7 +63,10 @@ source_set("x11") {
deps += [ "//gpu/vulkan/x" ]
}
- configs += [ "//build/config/linux:x11" ]
+ configs += [
+ "//build/config/linux:x11",
+ "//build/config/linux:xrandr",
+ ]
public_configs = [ "//third_party/khronos:khronos_headers" ]
}
@@ -68,6 +75,7 @@ source_set("x11_unittests") {
testonly = true
sources = [
"x11_cursor_factory_ozone_unittest.cc",
+ "x11_screen_ozone_unittest.cc",
"x11_window_ozone_unittest.cc",
]
diff --git a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
index 944206ff68f..ea33369f2e3 100644
--- a/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/chromium/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -17,6 +17,7 @@
#include "ui/gfx/x/x11.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h"
+#include "ui/ozone/platform/x11/x11_screen_ozone.h"
#include "ui/ozone/platform/x11/x11_surface_factory.h"
#include "ui/ozone/platform/x11/x11_window_manager_ozone.h"
#include "ui/ozone/platform/x11/x11_window_ozone.h"
@@ -76,6 +77,10 @@ class OzonePlatformX11 : public OzonePlatform {
return std::make_unique<display::FakeDisplayDelegate>();
}
+ std::unique_ptr<PlatformScreen> CreateScreen() override {
+ return std::make_unique<X11ScreenOzone>();
+ }
+
void InitializeUI(const InitParams& params) override {
InitializeCommon(params);
CreatePlatformEventSource();
diff --git a/chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.cc b/chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.cc
new file mode 100644
index 00000000000..6e6e277d40e
--- /dev/null
+++ b/chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.cc
@@ -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.
+
+#include "ui/ozone/platform/x11/x11_display_fetcher_ozone.h"
+
+#include <dlfcn.h>
+
+#include "base/logging.h"
+#include "base/memory/protected_memory_cfi.h"
+#include "ui/base/x/x11_display_util.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/display/display.h"
+#include "ui/display/util/display_util.h"
+#include "ui/display/util/x11/edid_parser_x11.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/gfx/x/x11.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_types.h"
+
+namespace ui {
+
+namespace {
+
+constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3.
+
+float GetDeviceScaleFactor() {
+ float device_scale_factor = 1.0f;
+ // TODO(jkim) : https://crbug.com/891175
+ // Get device scale factor using scale factor and resolution like
+ // 'GtkUi::GetRawDeviceScaleFactor'.
+ if (display::Display::HasForceDeviceScaleFactor())
+ device_scale_factor = display::Display::GetForcedDeviceScaleFactor();
+ return device_scale_factor;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// X11DisplayFetcherOzone, public:
+
+X11DisplayFetcherOzone::X11DisplayFetcherOzone(
+ X11DisplayFetcherOzone::Delegate* delegate)
+ : xdisplay_(gfx::GetXDisplay()),
+ x_root_window_(DefaultRootWindow(xdisplay_)),
+ xrandr_version_(GetXrandrVersion(xdisplay_)),
+ delegate_(delegate) {
+ DCHECK(delegate_);
+
+ float scale = GetDeviceScaleFactor();
+ std::vector<display::Display> displays;
+ // Need at least xrandr version 1.3.
+ if (xrandr_version_ >= kMinVersionXrandr) {
+ int error_base_ignored = 0;
+ XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
+
+ if (PlatformEventSource::GetInstance())
+ PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
+ XRRSelectInput(xdisplay_, x_root_window_,
+ RRScreenChangeNotifyMask | RROutputChangeNotifyMask |
+ RRCrtcChangeNotifyMask);
+
+ displays = BuildDisplaysFromXRandRInfo(xrandr_version_, scale,
+ &primary_display_index_);
+ } else {
+ displays = GetFallbackDisplayList(scale);
+ }
+ for (auto& display : displays)
+ delegate_->AddDisplay(display, display.id() == primary_display_index_);
+}
+
+X11DisplayFetcherOzone::~X11DisplayFetcherOzone() {
+ if (xrandr_version_ >= kMinVersionXrandr &&
+ PlatformEventSource::GetInstance()) {
+ PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+ }
+}
+
+bool X11DisplayFetcherOzone::CanDispatchEvent(const ui::PlatformEvent& event) {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+uint32_t X11DisplayFetcherOzone::DispatchEvent(const ui::PlatformEvent& event) {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return ui::POST_DISPATCH_NONE;
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.h b/chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.h
new file mode 100644
index 00000000000..f8391832e67
--- /dev/null
+++ b/chromium/ui/ozone/platform/x11/x11_display_fetcher_ozone.h
@@ -0,0 +1,59 @@
+// 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_OZONE_PLATFORM_X11_X11_DISPLAY_FETCHER_OZONE_H_
+#define UI_OZONE_PLATFORM_X11_X11_DISPLAY_FETCHER_OZONE_H_
+
+#include <stdint.h>
+
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/x/x11_types.h"
+
+namespace display {
+class Display;
+} // namespace display
+
+namespace ui {
+
+// X11DisplayFetcherOzone talks to xrandr to get the information of the outputs
+// for a screen and updates Display to X11DisplayFetcherOzone::Delegate. The
+// minimum required version of xrandr is 1.3.
+class X11DisplayFetcherOzone : public ui::PlatformEventDispatcher {
+ public:
+ class Delegate {
+ public:
+ virtual void AddDisplay(const display::Display& display,
+ bool is_primary) = 0;
+ virtual void RemoveDisplay(const display::Display& display) = 0;
+ };
+
+ explicit X11DisplayFetcherOzone(X11DisplayFetcherOzone::Delegate* delegate);
+ ~X11DisplayFetcherOzone() override;
+
+ // ui::PlatformEventDispatcher:
+ bool CanDispatchEvent(const ui::PlatformEvent& event) override;
+ uint32_t DispatchEvent(const ui::PlatformEvent& event) override;
+
+ private:
+ int64_t primary_display_index_ = 0;
+
+ XDisplay* const xdisplay_;
+ XID x_root_window_;
+
+ // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present.
+ const int xrandr_version_;
+
+ // The base of the event numbers used to represent XRandr events used in
+ // decoding events regarding output add/remove.
+ int xrandr_event_base_ = 0;
+
+ Delegate* const delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11DisplayFetcherOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_X11_X11_DISPLAY_FETCHER_OZONE_H_
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
new file mode 100644
index 00000000000..39426b20f05
--- /dev/null
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -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.
+
+#include "ui/ozone/platform/x11/x11_screen_ozone.h"
+
+#include "ui/display/display.h"
+#include "ui/display/display_finder.h"
+#include "ui/display/display_observer.h"
+#include "ui/gfx/font_render_params.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+X11ScreenOzone::X11ScreenOzone() {
+ // Creates |display_fetcher_| instead of adding it to a member initializer
+ // list as it requires |this|.
+ display_fetcher_ = std::make_unique<X11DisplayFetcherOzone>(this);
+}
+
+X11ScreenOzone::~X11ScreenOzone() = default;
+
+const std::vector<display::Display>& X11ScreenOzone::GetAllDisplays() const {
+ return display_list_.displays();
+}
+
+display::Display X11ScreenOzone::GetPrimaryDisplay() const {
+ auto iter = display_list_.GetPrimaryDisplayIterator();
+ if (iter == display_list_.displays().end())
+ return display::Display::GetDefaultDisplay();
+ return *iter;
+}
+
+display::Display X11ScreenOzone::GetDisplayForAcceleratedWidget(
+ gfx::AcceleratedWidget widget) const {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return GetPrimaryDisplay();
+}
+
+gfx::Point X11ScreenOzone::GetCursorScreenPoint() const {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return gfx::Point();
+}
+
+gfx::AcceleratedWidget X11ScreenOzone::GetAcceleratedWidgetAtScreenPoint(
+ const gfx::Point& point) const {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return gfx::kNullAcceleratedWidget;
+}
+
+display::Display X11ScreenOzone::GetDisplayNearestPoint(
+ const gfx::Point& point) const {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return GetPrimaryDisplay();
+}
+
+display::Display X11ScreenOzone::GetDisplayMatching(
+ const gfx::Rect& match_rect) const {
+ // TODO(jkim): https://crbug.com/891175
+ NOTIMPLEMENTED_LOG_ONCE();
+ return GetPrimaryDisplay();
+}
+
+void X11ScreenOzone::AddObserver(display::DisplayObserver* observer) {
+ display_list_.AddObserver(observer);
+}
+
+void X11ScreenOzone::RemoveObserver(display::DisplayObserver* observer) {
+ display_list_.RemoveObserver(observer);
+}
+
+void X11ScreenOzone::AddDisplay(const display::Display& display,
+ bool is_primary) {
+ display_list_.AddDisplay(
+ display, is_primary ? display::DisplayList::Type::PRIMARY
+ : display::DisplayList::Type::NOT_PRIMARY);
+
+ if (is_primary) {
+ gfx::SetFontRenderParamsDeviceScaleFactor(
+ GetPrimaryDisplay().device_scale_factor());
+ }
+}
+
+void X11ScreenOzone::RemoveDisplay(const display::Display& display) {
+ display_list_.RemoveDisplay(display.id());
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone.h b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
new file mode 100644
index 00000000000..cd16a1c909c
--- /dev/null
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -0,0 +1,57 @@
+// 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_OZONE_PLATFORM_X11_X11_SCREEN_OZONE_H_
+#define UI_OZONE_PLATFORM_X11_X11_SCREEN_OZONE_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "ui/display/display_list.h"
+#include "ui/ozone/platform/x11/x11_display_fetcher_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/platform_screen.h"
+
+namespace ui {
+
+// A PlatformScreen implementation for X11.
+class X11ScreenOzone : public PlatformScreen,
+ public X11DisplayFetcherOzone::Delegate {
+ public:
+ X11ScreenOzone();
+ ~X11ScreenOzone() override;
+
+ // PlatformScreen implementation.
+ const std::vector<display::Display>& GetAllDisplays() const override;
+ display::Display GetPrimaryDisplay() const override;
+ display::Display GetDisplayForAcceleratedWidget(
+ gfx::AcceleratedWidget widget) const override;
+ gfx::Point GetCursorScreenPoint() const override;
+ gfx::AcceleratedWidget GetAcceleratedWidgetAtScreenPoint(
+ const gfx::Point& point) const override;
+ display::Display GetDisplayNearestPoint(
+ const gfx::Point& point) const override;
+ display::Display GetDisplayMatching(
+ const gfx::Rect& match_rect) const override;
+ void AddObserver(display::DisplayObserver* observer) override;
+ void RemoveObserver(display::DisplayObserver* observer) override;
+
+ // X11DisplayFetcherOzone::Delegate overrides:
+ void AddDisplay(const display::Display& display, bool is_primary) override;
+ void RemoveDisplay(const display::Display& display) override;
+
+ private:
+ display::DisplayList display_list_;
+
+ base::ObserverList<display::DisplayObserver> observers_;
+
+ std::unique_ptr<X11DisplayFetcherOzone> display_fetcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11ScreenOzone);
+};
+
+} // namespace ui
+
+#endif // UI_OZONE_PLATFORM_X11_X11_SCREEN_OZONE_H_
diff --git a/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc b/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
new file mode 100644
index 00000000000..6086f084a46
--- /dev/null
+++ b/chromium/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
@@ -0,0 +1,24 @@
+// 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/ozone/platform/x11/x11_screen_ozone.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/display.h"
+
+namespace ui {
+
+// This test ensures that PlatformScreen fetches display.
+TEST(X11ScreenOzoneTest, FetchDisplay) {
+ constexpr uint32_t kNumberOfDisplays = 1;
+
+ std::unique_ptr<X11ScreenOzone> platform_screen =
+ std::make_unique<X11ScreenOzone>();
+
+ // Ensure there is only one display, which is the primary one.
+ auto& all_displays = platform_screen->GetAllDisplays();
+ EXPECT_EQ(all_displays.size(), kNumberOfDisplays);
+}
+
+} // namespace ui
diff --git a/chromium/ui/ozone/public/cursor_factory_ozone.cc b/chromium/ui/ozone/public/cursor_factory_ozone.cc
index 7efc26c22bf..01b80c66d5d 100644
--- a/chromium/ui/ozone/public/cursor_factory_ozone.cc
+++ b/chromium/ui/ozone/public/cursor_factory_ozone.cc
@@ -4,37 +4,30 @@
#include "ui/ozone/public/cursor_factory_ozone.h"
-#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/threading/thread_local.h"
namespace ui {
namespace {
-// TODO(mfomitchev): crbug.com/741106
-// Until the above bug is fixed, CursorFactoryOzone singleton needs to be
-// thread-local, because Ash creates its own instance.
-base::LazyInstance<base::ThreadLocalPointer<CursorFactoryOzone>>::Leaky
- lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+CursorFactoryOzone* g_instance = nullptr;
} // namespace
CursorFactoryOzone::CursorFactoryOzone() {
- DCHECK(!lazy_tls_ptr.Pointer()->Get())
+ DCHECK(!g_instance)
<< "There should only be a single CursorFactoryOzone per thread.";
- lazy_tls_ptr.Pointer()->Set(this);
+ g_instance = this;
}
CursorFactoryOzone::~CursorFactoryOzone() {
- DCHECK_EQ(lazy_tls_ptr.Pointer()->Get(), this);
- lazy_tls_ptr.Pointer()->Set(nullptr);
+ DCHECK_EQ(g_instance, this);
+ g_instance = nullptr;
}
CursorFactoryOzone* CursorFactoryOzone::GetInstance() {
- CursorFactoryOzone* result = lazy_tls_ptr.Pointer()->Get();
- DCHECK(result) << "No CursorFactoryOzone implementation set.";
- return result;
+ DCHECK(g_instance);
+ return g_instance;
}
PlatformCursor CursorFactoryOzone::GetDefaultCursor(CursorType type) {
diff --git a/chromium/ui/ozone/public/interfaces/BUILD.gn b/chromium/ui/ozone/public/interfaces/BUILD.gn
index ec7f11f2836..5b2966cd911 100644
--- a/chromium/ui/ozone/public/interfaces/BUILD.gn
+++ b/chromium/ui/ozone/public/interfaces/BUILD.gn
@@ -9,6 +9,8 @@ mojom("interfaces") {
"device_cursor.mojom",
"drm_device.mojom",
"overlay_surface_candidate.mojom",
+ "scenic_gpu_host.mojom",
+ "scenic_gpu_service.mojom",
]
public_deps = [
diff --git a/chromium/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc b/chromium/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
index a8d8c5b6c70..95ac7fa550d 100644
--- a/chromium/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
+++ b/chromium/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
@@ -12,16 +12,7 @@
namespace ui {
-namespace {
-
-class OverlaySurfaceCandidateStructTraitsTest : public testing::Test {
- public:
- OverlaySurfaceCandidateStructTraitsTest() {}
-};
-
-} // namespace
-
-TEST_F(OverlaySurfaceCandidateStructTraitsTest, FieldsEqual) {
+TEST(OverlaySurfaceCandidateStructTraitsTest, FieldsEqual) {
ui::OverlaySurfaceCandidate input;
input.transform = gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
@@ -52,7 +43,7 @@ TEST_F(OverlaySurfaceCandidateStructTraitsTest, FieldsEqual) {
EXPECT_EQ(input.overlay_handled, output.overlay_handled);
}
-TEST_F(OverlaySurfaceCandidateStructTraitsTest, FalseBools) {
+TEST(OverlaySurfaceCandidateStructTraitsTest, FalseBools) {
ui::OverlaySurfaceCandidate input;
input.is_clipped = false;
@@ -68,7 +59,7 @@ TEST_F(OverlaySurfaceCandidateStructTraitsTest, FalseBools) {
EXPECT_EQ(input.overlay_handled, output.overlay_handled);
}
-TEST_F(OverlaySurfaceCandidateStructTraitsTest, OverlayStatus) {
+TEST(OverlaySurfaceCandidateStructTraitsTest, OverlayStatus) {
using OverlayStatusTraits =
mojo::EnumTraits<ui::ozone::mojom::OverlayStatus, ui::OverlayStatus>;
diff --git a/chromium/ui/ozone/public/interfaces/scenic_gpu_host.mojom b/chromium/ui/ozone/public/interfaces/scenic_gpu_host.mojom
new file mode 100644
index 00000000000..0736e928592
--- /dev/null
+++ b/chromium/ui/ozone/public/interfaces/scenic_gpu_host.mojom
@@ -0,0 +1,11 @@
+// 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.
+
+module ui.mojom;
+
+// Browser process interface that enables the GPU process to present to Scenic.
+interface ScenicGpuHost {
+ // Exports the surface's parent node in the scene graph using |export_token|.
+ ExportParent(int32 surface_handle, handle export_token);
+};
diff --git a/chromium/ui/ozone/public/interfaces/scenic_gpu_service.mojom b/chromium/ui/ozone/public/interfaces/scenic_gpu_service.mojom
new file mode 100644
index 00000000000..4a85bfbafd0
--- /dev/null
+++ b/chromium/ui/ozone/public/interfaces/scenic_gpu_service.mojom
@@ -0,0 +1,19 @@
+// 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.
+
+module ui.mojom;
+
+import "ui/ozone/public/interfaces/scenic_gpu_host.mojom";
+
+// GPU process service that enables presentation to Scenic.
+interface ScenicGpuService {
+ // Initializes the GPU service for presenting to scenic.
+ //
+ // This looks a bit backward because right now we only expose an API for the
+ // browser to bind services in the GPU, but we want the opposite here.
+ //
+ // TODO(spang): Consider providing a way for GPU to request ScenicGpuHost from
+ // service manager instead of returning one from a callback.
+ Initialize(ScenicGpuHost scenic_gpu_host);
+};
diff --git a/chromium/ui/ozone/public/ozone_platform.cc b/chromium/ui/ozone/public/ozone_platform.cc
index ec543bc9c10..d9c531079cf 100644
--- a/chromium/ui/ozone/public/ozone_platform.cc
+++ b/chromium/ui/ozone/public/ozone_platform.cc
@@ -35,25 +35,6 @@ base::Lock& GetOzoneInstanceLock() {
} // namespace
-OzonePlatform::PlatformProperties::PlatformProperties() = default;
-
-OzonePlatform::PlatformProperties::PlatformProperties(
- bool needs_request,
- bool custom_frame_default,
- bool can_use_system_title_bar,
- bool requires_mojo_for_ipc,
- std::vector<gfx::BufferFormat> buffer_formats)
- : needs_view_owner_request(needs_request),
- custom_frame_pref_default(custom_frame_default),
- use_system_title_bar(can_use_system_title_bar),
- requires_mojo(requires_mojo_for_ipc),
- supported_buffer_formats(buffer_formats) {}
-
-OzonePlatform::PlatformProperties::~PlatformProperties() = default;
-
-OzonePlatform::PlatformProperties::PlatformProperties(
- const PlatformProperties& other) = default;
-
OzonePlatform::OzonePlatform() {
GetOzoneInstanceLock().AssertAcquired();
DCHECK(!g_instance) << "There should only be a single OzonePlatform.";
@@ -141,6 +122,13 @@ std::unique_ptr<PlatformScreen> OzonePlatform::CreateScreen() {
return nullptr;
}
+bool OzonePlatform::IsNativePixmapConfigSupported(
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage) const {
+ // Platform that support NativePixmap must override this method.
+ return false;
+}
+
const OzonePlatform::PlatformProperties&
OzonePlatform::GetPlatformProperties() {
static const base::NoDestructor<OzonePlatform::PlatformProperties> properties;
diff --git a/chromium/ui/ozone/public/ozone_platform.h b/chromium/ui/ozone/public/ozone_platform.h
index f1058530501..ceb287245bd 100644
--- a/chromium/ui/ozone/public/ozone_platform.h
+++ b/chromium/ui/ozone/public/ozone_platform.h
@@ -87,19 +87,9 @@ class OZONE_EXPORT OzonePlatform {
// Struct used to indicate platform properties.
struct PlatformProperties {
- PlatformProperties();
- PlatformProperties(bool needs_request,
- bool custom_frame_default,
- bool can_use_system_title_bar,
- bool requires_mojo_for_ipc,
- std::vector<gfx::BufferFormat> buffer_formats);
- ~PlatformProperties();
- PlatformProperties(const PlatformProperties& other);
-
- // Fuchsia only: set to true when the platforms requires
- // |view_owner_request| field in PlatformWindowInitProperties when creating
- // a window.
- bool needs_view_owner_request = false;
+ // Fuchsia only: set to true when the platforms requires |view_token| field
+ // in PlatformWindowInitProperties when creating a window.
+ bool needs_view_token = false;
// Determine whether we should default to native decorations or the custom
// frame based on the currently-running window manager.
@@ -112,9 +102,6 @@ class OZONE_EXPORT OzonePlatform {
// Determines if the platform requires mojo communication for the IPC.
// Currently used only by the Ozone/Wayland platform.
bool requires_mojo = false;
-
- // Wayland only: carries buffer formats supported by a Wayland server.
- std::vector<gfx::BufferFormat> supported_buffer_formats;
};
using StartupCallback = base::OnceCallback<void(OzonePlatform*)>;
@@ -162,6 +149,10 @@ class OZONE_EXPORT OzonePlatform {
CreateNativeDisplayDelegate() = 0;
virtual std::unique_ptr<PlatformScreen> CreateScreen();
+ // Returns true if the specified buffer format is supported.
+ virtual bool IsNativePixmapConfigSupported(gfx::BufferFormat format,
+ gfx::BufferUsage usage) const;
+
// Returns a struct that contains configuration and requirements for the
// current platform implementation.
virtual const PlatformProperties& GetPlatformProperties();
diff --git a/chromium/ui/ozone/public/ozone_switches.cc b/chromium/ui/ozone/public/ozone_switches.cc
index 7bec0b7ef22..46c48204470 100644
--- a/chromium/ui/ozone/public/ozone_switches.cc
+++ b/chromium/ui/ozone/public/ozone_switches.cc
@@ -15,4 +15,7 @@ const char kOzoneDumpFile[] = "ozone-dump-file";
// Try to enable wayland input method editor.
const char kEnableWaylandIme[] = "enable-wayland-ime";
+// Disable explicit DMA-fences
+const char kDisableExplicitDmaFences[] = "disable-explicit-dma-fences";
+
} // namespace switches
diff --git a/chromium/ui/ozone/public/ozone_switches.h b/chromium/ui/ozone/public/ozone_switches.h
index d7e7d8a9256..24d30c19eea 100644
--- a/chromium/ui/ozone/public/ozone_switches.h
+++ b/chromium/ui/ozone/public/ozone_switches.h
@@ -16,6 +16,8 @@ OZONE_BASE_EXPORT extern const char kOzoneDumpFile[];
OZONE_BASE_EXPORT extern const char kEnableWaylandIme[];
+OZONE_BASE_EXPORT extern const char kDisableExplicitDmaFences[];
+
} // namespace switches
#endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.cc b/chromium/ui/ozone/public/surface_factory_ozone.cc
index 4d99ecb01c8..ea7fa8b6453 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.cc
+++ b/chromium/ui/ozone/public/surface_factory_ozone.cc
@@ -61,11 +61,6 @@ std::unique_ptr<SurfaceOzoneCanvas> SurfaceFactoryOzone::CreateCanvasForWidget(
return nullptr;
}
-std::vector<gfx::BufferFormat> SurfaceFactoryOzone::GetScanoutFormats(
- gfx::AcceleratedWidget widget) {
- return std::vector<gfx::BufferFormat>();
-}
-
scoped_refptr<gfx::NativePixmap> SurfaceFactoryOzone::CreateNativePixmap(
gfx::AcceleratedWidget widget,
gfx::Size size,
diff --git a/chromium/ui/ozone/public/surface_factory_ozone.h b/chromium/ui/ozone/public/surface_factory_ozone.h
index af51cfaefde..4c4c0e767e8 100644
--- a/chromium/ui/ozone/public/surface_factory_ozone.h
+++ b/chromium/ui/ozone/public/surface_factory_ozone.h
@@ -105,11 +105,6 @@ class OZONE_BASE_EXPORT SurfaceFactoryOzone {
virtual std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget);
- // Returns all scanout formats for |widget| representing a particular display
- // controller or default display controller for kNullAcceleratedWidget.
- virtual std::vector<gfx::BufferFormat> GetScanoutFormats(
- gfx::AcceleratedWidget widget);
-
// Create a single native buffer to be used for overlay planes or zero copy
// for |widget| representing a particular display controller or default
// display controller for kNullAcceleratedWidget.
diff --git a/chromium/ui/platform_window/BUILD.gn b/chromium/ui/platform_window/BUILD.gn
index af5ef67e875..efa50832393 100644
--- a/chromium/ui/platform_window/BUILD.gn
+++ b/chromium/ui/platform_window/BUILD.gn
@@ -23,8 +23,14 @@ source_set("platform_window") {
]
if (is_fuchsia) {
+ sources += [
+ "fuchsia/initialize_presenter_api_view.cc",
+ "fuchsia/initialize_presenter_api_view.h",
+ ]
+
public_deps = [
- "//third_party/fuchsia-sdk/sdk:viewsv1token",
+ "//third_party/fuchsia-sdk/sdk:policy",
+ "//third_party/fuchsia-sdk/sdk:zx",
]
}
}
diff --git a/chromium/ui/platform_window/fuchsia/OWNERS b/chromium/ui/platform_window/fuchsia/OWNERS
new file mode 100644
index 00000000000..e7034eabb1e
--- /dev/null
+++ b/chromium/ui/platform_window/fuchsia/OWNERS
@@ -0,0 +1 @@
+file://build/fuchsia/OWNERS
diff --git a/chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.cc b/chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.cc
new file mode 100644
index 00000000000..af7be030526
--- /dev/null
+++ b/chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
+
+#include <fuchsia/ui/policy/cpp/fidl.h>
+#include <lib/zx/eventpair.h>
+
+#include "base/fuchsia/component_context.h"
+#include "base/fuchsia/fuchsia_logging.h"
+
+namespace ui {
+namespace fuchsia {
+
+void InitializeViewTokenAndPresentView(
+ ui::PlatformWindowInitProperties* window_properties_out) {
+ DCHECK(window_properties_out);
+
+ // Generate and set the view tokens for the |window_properties_out| and the
+ // Presenter API.
+ zx::eventpair view_holder_token;
+ zx_status_t status = zx::eventpair::create(
+ /* options = */ 0, &window_properties_out->view_token,
+ &view_holder_token);
+ ZX_CHECK(status == ZX_OK, status) << "zx_eventpair_create";
+
+ // Request Presenter to show the view full-screen.
+ auto presenter = base::fuchsia::ComponentContext::GetDefault()
+ ->ConnectToService<::fuchsia::ui::policy::Presenter>();
+
+ presenter->Present2(std::move(view_holder_token), nullptr);
+}
+
+} // namespace fuchsia
+} // namespace ui
diff --git a/chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.h b/chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.h
new file mode 100644
index 00000000000..a31f3612134
--- /dev/null
+++ b/chromium/ui/platform_window/fuchsia/initialize_presenter_api_view.h
@@ -0,0 +1,21 @@
+// 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_PLATFORM_WINDOW_FUCHSIA_INITIALIZE_PRESENTER_API_VIEW_H_
+#define UI_PLATFORM_WINDOW_FUCHSIA_INITIALIZE_PRESENTER_API_VIEW_H_
+
+#include "ui/platform_window/platform_window_init_properties.h"
+
+namespace ui {
+namespace fuchsia {
+
+// Generates and sets the view tokens that are required to utilize the
+// Presenter API. |window_properties_out| must be a valid value.
+void InitializeViewTokenAndPresentView(
+ ui::PlatformWindowInitProperties* window_properties_out);
+
+} // namespace fuchsia
+} // namespace ui
+
+#endif // UI_PLATFORM_WINDOW_FUCHSIA_INITIALIZE_PRESENTER_API_VIEW_H_
diff --git a/chromium/ui/platform_window/platform_window_handler/BUILD.gn b/chromium/ui/platform_window/platform_window_handler/BUILD.gn
index be75a75c702..65ea155a800 100644
--- a/chromium/ui/platform_window/platform_window_handler/BUILD.gn
+++ b/chromium/ui/platform_window/platform_window_handler/BUILD.gn
@@ -8,6 +8,8 @@ jumbo_component("platform_window_handler") {
output_name = "platform_window_handler_libs"
sources = [
+ "wm_drag_handler.cc",
+ "wm_drag_handler.h",
"wm_move_resize_handler.cc",
"wm_move_resize_handler.h",
"wm_platform_export.h",
diff --git a/chromium/ui/platform_window/platform_window_handler/wm_drag_handler.cc b/chromium/ui/platform_window/platform_window_handler/wm_drag_handler.cc
new file mode 100644
index 00000000000..74a6d2da810
--- /dev/null
+++ b/chromium/ui/platform_window/platform_window_handler/wm_drag_handler.cc
@@ -0,0 +1,25 @@
+// 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/platform_window/platform_window_handler/wm_drag_handler.h"
+
+#include "ui/base/class_property.h"
+#include "ui/platform_window/platform_window.h"
+
+DEFINE_UI_CLASS_PROPERTY_TYPE(ui::WmDragHandler*)
+
+namespace ui {
+
+DEFINE_UI_CLASS_PROPERTY_KEY(WmDragHandler*, kWmDragHandlerKey, nullptr);
+
+void SetWmDragHandler(PlatformWindow* platform_window,
+ WmDragHandler* drag_handler) {
+ platform_window->SetProperty(kWmDragHandlerKey, drag_handler);
+}
+
+WmDragHandler* GetWmDragHandler(const PlatformWindow& platform_window) {
+ return platform_window.GetProperty(kWmDragHandlerKey);
+}
+
+} // namespace ui
diff --git a/chromium/ui/platform_window/platform_window_handler/wm_drag_handler.h b/chromium/ui/platform_window/platform_window_handler/wm_drag_handler.h
new file mode 100644
index 00000000000..1fc3af3fa82
--- /dev/null
+++ b/chromium/ui/platform_window/platform_window_handler/wm_drag_handler.h
@@ -0,0 +1,39 @@
+// 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_PLATFORM_WINDOW_PLATFORM_WINDOW_HANDLER_WM_DRAG_HANDLER_H_
+#define UI_PLATFORM_WINDOW_PLATFORM_WINDOW_HANDLER_WM_DRAG_HANDLER_H_
+
+#include "base/bind.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/platform_window/platform_window_handler/wm_platform_export.h"
+
+namespace ui {
+class OSExchangeData;
+class PlatformWindow;
+
+class WM_PLATFORM_EXPORT WmDragHandler {
+ public:
+ // Starts dragging with |data| which it wants to deliver to the destination.
+ // |operation| is the suggested operation which is bitmask of DRAG_NONE,
+ // DRAG_MOVE, DRAG_COPY and DRAG_LINK in DragDropTypes::DragOperation to the
+ // destination and the destination sets the final operation when the drop
+ // action is performed.
+ virtual void StartDrag(const OSExchangeData& data,
+ int operation,
+ gfx::NativeCursor cursor,
+ base::OnceCallback<void(int)> callback) = 0;
+
+ protected:
+ virtual ~WmDragHandler() {}
+};
+
+WM_PLATFORM_EXPORT void SetWmDragHandler(PlatformWindow* platform_window,
+ WmDragHandler* drag_handler);
+WM_PLATFORM_EXPORT WmDragHandler* GetWmDragHandler(
+ const PlatformWindow& platform_window);
+
+} // namespace ui
+
+#endif // UI_PLATFORM_WINDOW_PLATFORM_WINDOW_HANDLER_WM_DRAG_HANDLER_H_
diff --git a/chromium/ui/platform_window/platform_window_init_properties.h b/chromium/ui/platform_window/platform_window_init_properties.h
index 55aff1ac87d..384f835860f 100644
--- a/chromium/ui/platform_window/platform_window_init_properties.h
+++ b/chromium/ui/platform_window/platform_window_init_properties.h
@@ -12,7 +12,7 @@
#include "ui/gfx/native_widget_types.h"
#if defined(OS_FUCHSIA)
-#include <fuchsia/ui/viewsv1token/cpp/fidl.h>
+#include <lib/zx/eventpair.h>
#endif
namespace ui {
@@ -45,8 +45,7 @@ struct PlatformWindowInitProperties {
gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget;
#if defined(OS_FUCHSIA)
- fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner>
- view_owner_request;
+ zx::eventpair view_token;
#endif
};
diff --git a/chromium/ui/resources/default_100_percent/common/menu_hierarchy_arrow.png b/chromium/ui/resources/default_100_percent/common/menu_hierarchy_arrow.png
deleted file mode 100644
index e77afae21bb..00000000000
--- a/chromium/ui/resources/default_100_percent/common/menu_hierarchy_arrow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png b/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png
deleted file mode 100644
index f5a7faeaa7b..00000000000
--- a/chromium/ui/resources/default_100_percent/common/menu_overflow_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png b/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png
deleted file mode 100644
index d356baf2076..00000000000
--- a/chromium/ui/resources/default_100_percent/common/menu_overflow_up.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_close.png b/chromium/ui/resources/default_100_percent/common/notification_close.png
deleted file mode 100644
index 02e1f91ee0b..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_close.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_close_hover.png b/chromium/ui/resources/default_100_percent/common/notification_close_hover.png
deleted file mode 100644
index aeafd962eb7..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_close_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_close_pressed.png b/chromium/ui/resources/default_100_percent/common/notification_close_pressed.png
deleted file mode 100644
index 1c4ad59f6c4..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_close_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_settings_button.png b/chromium/ui/resources/default_100_percent/common/notification_settings_button.png
deleted file mode 100644
index 741241e3319..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_settings_button.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_settings_button_hover.png b/chromium/ui/resources/default_100_percent/common/notification_settings_button_hover.png
deleted file mode 100644
index fcd210f931e..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_settings_button_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/common/notification_settings_button_pressed.png b/chromium/ui/resources/default_100_percent/common/notification_settings_button_pressed.png
deleted file mode 100644
index a5194b191b6..00000000000
--- a/chromium/ui/resources/default_100_percent/common/notification_settings_button_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/cros/menu_droparrow.png b/chromium/ui/resources/default_100_percent/cros/menu_droparrow.png
deleted file mode 100644
index 2103f5f2f51..00000000000
--- a/chromium/ui/resources/default_100_percent/cros/menu_droparrow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/legacy/throbber.png b/chromium/ui/resources/default_100_percent/legacy/throbber.png
deleted file mode 100644
index 4d2525c1de4..00000000000
--- a/chromium/ui/resources/default_100_percent/legacy/throbber.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/win/notification_close.png b/chromium/ui/resources/default_100_percent/win/notification_close.png
deleted file mode 100644
index 064d51d7bef..00000000000
--- a/chromium/ui/resources/default_100_percent/win/notification_close.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/win/notification_close_hover.png b/chromium/ui/resources/default_100_percent/win/notification_close_hover.png
deleted file mode 100644
index 1af2c59e06c..00000000000
--- a/chromium/ui/resources/default_100_percent/win/notification_close_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_100_percent/win/notification_close_pressed.png b/chromium/ui/resources/default_100_percent/win/notification_close_pressed.png
deleted file mode 100644
index 981546c30db..00000000000
--- a/chromium/ui/resources/default_100_percent/win/notification_close_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/menu_hierarchy_arrow.png b/chromium/ui/resources/default_200_percent/common/menu_hierarchy_arrow.png
deleted file mode 100644
index 58a00077eea..00000000000
--- a/chromium/ui/resources/default_200_percent/common/menu_hierarchy_arrow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png b/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png
deleted file mode 100644
index 659dab6ae7e..00000000000
--- a/chromium/ui/resources/default_200_percent/common/menu_overflow_down.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/menu_overflow_up.png b/chromium/ui/resources/default_200_percent/common/menu_overflow_up.png
deleted file mode 100644
index 6202dbf7935..00000000000
--- a/chromium/ui/resources/default_200_percent/common/menu_overflow_up.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_close.png b/chromium/ui/resources/default_200_percent/common/notification_close.png
deleted file mode 100644
index 80f4b9c2533..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_close.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_close_hover.png b/chromium/ui/resources/default_200_percent/common/notification_close_hover.png
deleted file mode 100644
index 743d005ee4e..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_close_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_close_pressed.png b/chromium/ui/resources/default_200_percent/common/notification_close_pressed.png
deleted file mode 100644
index 07b69ccdbe1..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_close_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_settings_button.png b/chromium/ui/resources/default_200_percent/common/notification_settings_button.png
deleted file mode 100644
index e6623dae713..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_settings_button.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_settings_button_hover.png b/chromium/ui/resources/default_200_percent/common/notification_settings_button_hover.png
deleted file mode 100644
index c316bd4dcb9..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_settings_button_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/common/notification_settings_button_pressed.png b/chromium/ui/resources/default_200_percent/common/notification_settings_button_pressed.png
deleted file mode 100644
index 56e40823e85..00000000000
--- a/chromium/ui/resources/default_200_percent/common/notification_settings_button_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/cros/menu_droparrow.png b/chromium/ui/resources/default_200_percent/cros/menu_droparrow.png
deleted file mode 100644
index 20e0e47dfb8..00000000000
--- a/chromium/ui/resources/default_200_percent/cros/menu_droparrow.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/legacy/throbber.png b/chromium/ui/resources/default_200_percent/legacy/throbber.png
deleted file mode 100644
index fdd5f7acc85..00000000000
--- a/chromium/ui/resources/default_200_percent/legacy/throbber.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/win/notification_close.png b/chromium/ui/resources/default_200_percent/win/notification_close.png
deleted file mode 100644
index 627afbcac19..00000000000
--- a/chromium/ui/resources/default_200_percent/win/notification_close.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/win/notification_close_hover.png b/chromium/ui/resources/default_200_percent/win/notification_close_hover.png
deleted file mode 100644
index 196d6dcbe69..00000000000
--- a/chromium/ui/resources/default_200_percent/win/notification_close_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/default_200_percent/win/notification_close_pressed.png b/chromium/ui/resources/default_200_percent/win/notification_close_pressed.png
deleted file mode 100644
index 3b32dd026cb..00000000000
--- a/chromium/ui/resources/default_200_percent/win/notification_close_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/resources/ui_resources.grd b/chromium/ui/resources/ui_resources.grd
index 6d38ed3f886..3eec9da09e1 100644
--- a/chromium/ui/resources/ui_resources.grd
+++ b/chromium/ui/resources/ui_resources.grd
@@ -111,29 +111,8 @@
<structure type="chrome_scaled_image" name="IDR_EMOJI_FAVICON" file="common/emoji_menu_item.png" />
<structure type="chrome_scaled_image" name="IDR_FOLDER_CLOSED" file="common/folder_closed.png" />
<structure type="chrome_scaled_image" name="IDR_FOLDER_CLOSED_RTL" file="common/folder_closed_rtl.png" />
- <if expr="is_macosx">
- <structure type="chrome_scaled_image" name="IDR_MENU_OVERFLOW_UP" file="common/menu_overflow_up.png" />
- <structure type="chrome_scaled_image" name="IDR_MENU_OVERFLOW_DOWN" file="common/menu_overflow_down.png" />
- </if>
- <if expr="is_macosx or is_ios">
- <structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW" file="mac/menu_hierarchy_arrow.png" />
- </if>
- <structure type="chrome_scaled_image" name="IDR_MENU_DROPARROW" file="cros/menu_droparrow.png" />
- <if expr="toolkit_views or is_ios">
- <if expr="is_win">
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="win/notification_close.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="win/notification_close_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_PRESSED" file="win/notification_close_pressed.png"/>
- </if>
- <if expr="not is_win">
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE" file="common/notification_close.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_HOVER" file="common/notification_close_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLOSE_PRESSED" file="common/notification_close_pressed.png"/>
- </if>
+ <if expr="toolkit_views and not is_macosx">
<structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS" file="common/notification_settings.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_BUTTON_ICON" file="common/notification_settings_button.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_BUTTON_ICON_HOVER" file="common/notification_settings_button_hover.png"/>
- <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_BUTTON_ICON_PRESSED" file="common/notification_settings_button_pressed.png"/>
</if>
<if expr="not is_android and not is_ios">
<structure type="chrome_scaled_image" name="IDR_NTP_DEFAULT_FAVICON" file="common/ntp_default_favicon.png" />
@@ -160,9 +139,6 @@
<structure type="chrome_scaled_image" name="IDR_TEXT_SELECTION_HANDLE_LEFT" file="common/text_selection_handle_left.png" />
<structure type="chrome_scaled_image" name="IDR_TEXT_SELECTION_HANDLE_RIGHT" file="common/text_selection_handle_right.png" />
</if>
- <if expr="is_macosx">
- <structure type="chrome_scaled_image" name="IDR_THROBBER" file="legacy/throbber.png" />
- </if>
<if expr="toolkit_views">
<structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_COPY" file="common/drag_tip_copy.png" />
<structure type="chrome_scaled_image" name="IDR_TOUCH_DRAG_TIP_MOVE" file="common/drag_tip_move.png" />
diff --git a/chromium/ui/shell_dialogs/BUILD.gn b/chromium/ui/shell_dialogs/BUILD.gn
index 80b4c176b1c..bd4d92a194b 100644
--- a/chromium/ui/shell_dialogs/BUILD.gn
+++ b/chromium/ui/shell_dialogs/BUILD.gn
@@ -18,6 +18,8 @@ jumbo_component("shell_dialogs") {
"base_shell_dialog.h",
"base_shell_dialog_win.cc",
"base_shell_dialog_win.h",
+ "execute_select_file_win.cc",
+ "execute_select_file_win.h",
"select_file_dialog.cc",
"select_file_dialog.h",
"select_file_dialog_factory.cc",
@@ -103,6 +105,7 @@ if (is_mac) {
test("shell_dialogs_unittests") {
testonly = true
sources = [
+ "execute_select_file_win_unittest.cc",
"run_all_unittests.cc",
"select_file_dialog_mac_unittest.mm",
"select_file_dialog_unittest.cc",
@@ -114,7 +117,9 @@ test("shell_dialogs_unittests") {
"//base",
"//base/test:test_support",
"//testing/gtest",
- "//ui/base:base",
+ "//ui/base",
+ "//ui/resources:ui_test_pak_data",
+ "//ui/strings",
]
if (is_mac) {
diff --git a/chromium/ui/shell_dialogs/OWNERS b/chromium/ui/shell_dialogs/OWNERS
index 68dadb1824a..0423b7258de 100644
--- a/chromium/ui/shell_dialogs/OWNERS
+++ b/chromium/ui/shell_dialogs/OWNERS
@@ -1,2 +1,4 @@
per-file *android*=miguelg@chromium.org
per-file *android*=qinmin@chromium.org
+
+per-file *win*=robliao@chromium.org
diff --git a/chromium/ui/shell_dialogs/base_shell_dialog_win.cc b/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
index a61a9e7f953..3099fbc643e 100644
--- a/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/base_shell_dialog_win.cc
@@ -25,13 +25,17 @@ scoped_refptr<base::SingleThreadTaskRunner> CreateDialogTaskRunner() {
base::SingleThreadTaskRunnerThreadMode::DEDICATED);
}
+// Enables the window |owner|. Can only be run from the UI thread.
+void SetOwnerEnabled(HWND owner, bool enabled) {
+ if (IsWindow(owner))
+ EnableWindow(owner, enabled);
+}
+
} // namespace
BaseShellDialogImpl::RunState::RunState() = default;
BaseShellDialogImpl::RunState::~RunState() = default;
-BaseShellDialogImpl::RunState::RunState(const RunState& run_state) = default;
-
// static
BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
int BaseShellDialogImpl::instance_count_ = 0;
@@ -46,15 +50,21 @@ BaseShellDialogImpl::~BaseShellDialogImpl() {
DCHECK(owners_.empty());
}
-BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
+// static
+void BaseShellDialogImpl::DisableOwner(HWND owner) {
+ SetOwnerEnabled(owner, false);
+}
+
+std::unique_ptr<BaseShellDialogImpl::RunState> BaseShellDialogImpl::BeginRun(
+ HWND owner) {
// Cannot run a modal shell dialog if one is already running for this owner.
DCHECK(!IsRunningDialogForOwner(owner));
// The owner must be a top level window, otherwise we could end up with two
// entries in our map for the same top level window.
DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
- RunState run_state;
- run_state.dialog_task_runner = CreateDialogTaskRunner();
- run_state.owner = owner;
+ auto run_state = std::make_unique<RunState>();
+ run_state->dialog_task_runner = CreateDialogTaskRunner();
+ run_state->owner = owner;
if (owner) {
owners_.insert(owner);
DisableOwner(owner);
@@ -62,12 +72,12 @@ BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
return run_state;
}
-void BaseShellDialogImpl::EndRun(RunState run_state) {
- if (run_state.owner) {
- DCHECK(IsRunningDialogForOwner(run_state.owner));
- EnableOwner(run_state.owner);
- DCHECK(owners_.find(run_state.owner) != owners_.end());
- owners_.erase(run_state.owner);
+void BaseShellDialogImpl::EndRun(std::unique_ptr<RunState> run_state) {
+ if (run_state->owner) {
+ DCHECK(IsRunningDialogForOwner(run_state->owner));
+ SetOwnerEnabled(run_state->owner, true);
+ DCHECK(owners_.find(run_state->owner) != owners_.end());
+ owners_.erase(run_state->owner);
}
}
@@ -75,14 +85,4 @@ bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
return (owner && owners_.find(owner) != owners_.end());
}
-void BaseShellDialogImpl::DisableOwner(HWND owner) {
- if (IsWindow(owner))
- EnableWindow(owner, FALSE);
-}
-
-void BaseShellDialogImpl::EnableOwner(HWND owner) {
- if (IsWindow(owner))
- EnableWindow(owner, TRUE);
-}
-
} // namespace ui
diff --git a/chromium/ui/shell_dialogs/base_shell_dialog_win.h b/chromium/ui/shell_dialogs/base_shell_dialog_win.h
index 37959ba6c8a..ac66957f325 100644
--- a/chromium/ui/shell_dialogs/base_shell_dialog_win.h
+++ b/chromium/ui/shell_dialogs/base_shell_dialog_win.h
@@ -6,6 +6,8 @@
#define UI_SHELL_DIALOGS_BASE_SHELL_DIALOG_WIN_H_
#include <shlobj.h>
+
+#include <memory>
#include <set>
#include "base/macros.h"
@@ -27,53 +29,50 @@ class SHELL_DIALOGS_EXPORT BaseShellDialogImpl {
BaseShellDialogImpl();
virtual ~BaseShellDialogImpl();
+ // Disables the window |owner|. Can be run from either the ui or the dialog
+ // thread. This function is called on the dialog thread after the modal
+ // Windows Common dialog functions return because Windows automatically
+ // re-enables the owning window when those functions return, but we don't
+ // actually want them to be re-enabled until the response of the dialog
+ // propagates back to the UI thread, so we disable the owner manually after
+ // the Common dialog function returns.
+ static void DisableOwner(HWND owner);
+
protected:
// Represents a run of a dialog.
- struct SHELL_DIALOGS_EXPORT RunState {
+ class SHELL_DIALOGS_EXPORT RunState {
+ public:
RunState();
~RunState();
- RunState(const RunState& run_state);
-
// Owning HWND, may be null.
HWND owner;
// Dedicated sequence on which the dialog runs.
scoped_refptr<base::SingleThreadTaskRunner> dialog_task_runner;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RunState);
};
// Called at the beginning of a modal dialog run. Disables the owner window
// and tracks it. Returns the dedicated single-threaded sequence that the
// dialog will be run on.
- RunState BeginRun(HWND owner);
+ std::unique_ptr<RunState> BeginRun(HWND owner);
// Cleans up after a dialog run. If the run_state has a valid HWND this makes
// sure that the window is enabled. This is essential because BeginRun
// aggressively guards against multiple modal dialogs per HWND. Must be called
// on the UI thread after the result of the dialog has been determined.
- //
- // In addition this deletes the Thread in RunState.
- void EndRun(RunState run_state);
+ void EndRun(std::unique_ptr<RunState> run_state);
// Returns true if a modal shell dialog is currently active for the specified
// owner. Must be called on the UI thread.
bool IsRunningDialogForOwner(HWND owner) const;
- // Disables the window |owner|. Can be run from either the ui or the dialog
- // thread. This function is called on the dialog thread after the modal
- // Windows Common dialog functions return because Windows automatically
- // re-enables the owning window when those functions return, but we don't
- // actually want them to be re-enabled until the response of the dialog
- // propagates back to the UI thread, so we disable the owner manually after
- // the Common dialog function returns.
- void DisableOwner(HWND owner);
-
private:
typedef std::set<HWND> Owners;
- // Enables the window |owner_|. Can only be run from the ui thread.
- void EnableOwner(HWND owner);
-
// A list of windows that currently own active shell dialogs for this
// instance. For example, if the DownloadManager owns an instance of this
// object and there are two browser windows open both with Save As dialog
diff --git a/chromium/ui/shell_dialogs/execute_select_file_win.cc b/chromium/ui/shell_dialogs/execute_select_file_win.cc
new file mode 100644
index 00000000000..504e6cb50d0
--- /dev/null
+++ b/chromium/ui/shell_dialogs/execute_select_file_win.cc
@@ -0,0 +1,407 @@
+// 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/shell_dialogs/execute_select_file_win.h"
+
+#include <shlobj.h>
+#include <wrl/client.h>
+
+#include "base/callback.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/win/com_init_util.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/shortcut.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/shell_dialogs/base_shell_dialog_win.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace ui {
+
+namespace {
+
+// Distinguish directories from regular files.
+bool IsDirectory(const base::FilePath& path) {
+ base::File::Info file_info;
+ return base::GetFileInfo(path, &file_info) ? file_info.is_directory
+ : path.EndsWithSeparator();
+}
+
+// Given |extension|, if it's not empty, then remove the leading dot.
+base::string16 GetExtensionWithoutLeadingDot(const base::string16& extension) {
+ DCHECK(extension.empty() || extension[0] == L'.');
+ return extension.empty() ? extension : extension.substr(1);
+}
+
+// Sets which path is going to be open when the dialog will be shown. If
+// |default_path| is not only a directory, also sets the contents of the text
+// box equals to the basename of the path.
+bool SetDefaultPath(IFileDialog* file_dialog,
+ const base::FilePath& default_path) {
+ if (default_path.empty())
+ return true;
+
+ base::FilePath default_folder;
+ base::FilePath default_file_name;
+ if (IsDirectory(default_path)) {
+ default_folder = default_path;
+ } else {
+ default_folder = default_path.DirName();
+ default_file_name = default_path.BaseName();
+ }
+
+ // Do not fail the file dialog operation if the specified folder is invalid.
+ Microsoft::WRL::ComPtr<IShellItem> default_folder_shell_item;
+ if (SUCCEEDED(SHCreateItemFromParsingName(
+ default_folder.value().c_str(), nullptr,
+ IID_PPV_ARGS(&default_folder_shell_item)))) {
+ if (FAILED(file_dialog->SetFolder(default_folder_shell_item.Get())))
+ return false;
+ }
+
+ return SUCCEEDED(file_dialog->SetFileName(default_file_name.value().c_str()));
+}
+
+// Sets the file extension filters on the dialog.
+bool SetFilters(IFileDialog* file_dialog,
+ const std::vector<FileFilterSpec>& filter,
+ int filter_index) {
+ if (filter.empty())
+ return true;
+
+ // A COMDLG_FILTERSPEC instance does not own any memory. |filter| must still
+ // be alive at the time the dialog is shown.
+ std::vector<COMDLG_FILTERSPEC> comdlg_filterspec(filter.size());
+
+ for (size_t i = 0; i < filter.size(); ++i) {
+ comdlg_filterspec[i].pszName = filter[i].description.c_str();
+ comdlg_filterspec[i].pszSpec = filter[i].extension_spec.c_str();
+ }
+
+ return SUCCEEDED(file_dialog->SetFileTypes(comdlg_filterspec.size(),
+ comdlg_filterspec.data())) &&
+ SUCCEEDED(file_dialog->SetFileTypeIndex(filter_index));
+}
+
+// Sets the requested |dialog_options|, making sure to keep the default values
+// when not overwritten.
+bool SetOptions(IFileDialog* file_dialog, DWORD dialog_options) {
+ // First retrieve the default options for a file dialog.
+ DWORD options;
+ if (FAILED(file_dialog->GetOptions(&options)))
+ return false;
+
+ options |= dialog_options;
+
+ return SUCCEEDED(file_dialog->SetOptions(options));
+}
+
+// Configures a |file_dialog| object given the specified parameters.
+bool ConfigureDialog(IFileDialog* file_dialog,
+ const base::string16& title,
+ const base::string16& ok_button_label,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ int filter_index,
+ DWORD dialog_options) {
+ // Set title.
+ if (!title.empty()) {
+ if (FAILED(file_dialog->SetTitle(title.c_str())))
+ return false;
+ }
+
+ if (!ok_button_label.empty()) {
+ if (FAILED(file_dialog->SetOkButtonLabel(ok_button_label.c_str())))
+ return false;
+ }
+
+ return SetDefaultPath(file_dialog, default_path) &&
+ SetOptions(file_dialog, dialog_options) &&
+ SetFilters(file_dialog, filter, filter_index);
+}
+
+// Prompt the user for location to save a file.
+// Callers should provide the filter string, and also a filter index.
+// The parameter |index| indicates the initial index of filter description and
+// filter pattern for the dialog box. If |index| is zero or greater than the
+// number of total filter types, the system uses the first filter in the
+// |filter| buffer. |index| is used to specify the initial selected extension,
+// and when done contains the extension the user chose. The parameter |path|
+// returns the file name which contains the drive designator, path, file name,
+// and extension of the user selected file name. |def_ext| is the default
+// extension to give to the file if the user did not enter an extension.
+bool RunSaveFileDialog(HWND owner,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ DWORD dialog_options,
+ const base::string16& def_ext,
+ int* filter_index,
+ base::FilePath* path) {
+ Microsoft::WRL::ComPtr<IFileSaveDialog> file_save_dialog;
+ if (FAILED(::CoCreateInstance(CLSID_FileSaveDialog, nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&file_save_dialog)))) {
+ return false;
+ }
+
+ if (!ConfigureDialog(file_save_dialog.Get(), title, base::string16(),
+ default_path, filter, *filter_index, dialog_options)) {
+ return false;
+ }
+
+ file_save_dialog->SetDefaultExtension(def_ext.c_str());
+
+ HRESULT hr = file_save_dialog->Show(owner);
+ BaseShellDialogImpl::DisableOwner(owner);
+ if (FAILED(hr))
+ return false;
+
+ UINT file_type_index;
+ if (FAILED(file_save_dialog->GetFileTypeIndex(&file_type_index)))
+ return false;
+
+ *filter_index = static_cast<int>(file_type_index);
+
+ Microsoft::WRL::ComPtr<IShellItem> result;
+ if (FAILED(file_save_dialog->GetResult(&result)))
+ return false;
+
+ base::win::ScopedCoMem<wchar_t> display_name;
+ if (FAILED(result->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,
+ &display_name))) {
+ return false;
+ }
+
+ *path = base::FilePath(display_name.get());
+ return true;
+}
+
+// Runs an Open file dialog box, with similar semantics for input parameters as
+// RunSaveFileDialog.
+bool RunOpenFileDialog(HWND owner,
+ const base::string16& title,
+ const base::string16& ok_button_label,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ DWORD dialog_options,
+ int* filter_index,
+ std::vector<base::FilePath>* paths) {
+ Microsoft::WRL::ComPtr<IFileOpenDialog> file_open_dialog;
+ if (FAILED(::CoCreateInstance(CLSID_FileOpenDialog, nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&file_open_dialog)))) {
+ return false;
+ }
+
+ if (!ConfigureDialog(file_open_dialog.Get(), title, ok_button_label,
+ default_path, filter, *filter_index, dialog_options)) {
+ return false;
+ }
+
+ HRESULT hr = file_open_dialog->Show(owner);
+ BaseShellDialogImpl::DisableOwner(owner);
+ if (FAILED(hr))
+ return false;
+
+ UINT file_type_index;
+ if (FAILED(file_open_dialog->GetFileTypeIndex(&file_type_index)))
+ return false;
+
+ *filter_index = static_cast<int>(file_type_index);
+
+ Microsoft::WRL::ComPtr<IShellItemArray> selected_items;
+ if (FAILED(file_open_dialog->GetResults(&selected_items)))
+ return false;
+
+ DWORD result_count;
+ if (FAILED(selected_items->GetCount(&result_count)))
+ return false;
+
+ DCHECK(result_count == 1 || (dialog_options & FOS_ALLOWMULTISELECT));
+
+ std::vector<base::FilePath> result(result_count);
+ for (DWORD i = 0; i < result_count; ++i) {
+ Microsoft::WRL::ComPtr<IShellItem> shell_item;
+ if (FAILED(selected_items->GetItemAt(i, &shell_item)))
+ return false;
+
+ base::win::ScopedCoMem<wchar_t> display_name;
+ if (FAILED(shell_item->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,
+ &display_name))) {
+ return false;
+ }
+
+ result[i] = base::FilePath(display_name.get());
+ }
+
+ // Only modify the out parameter if the enumeration didn't fail.
+ *paths = std::move(result);
+ return !paths->empty();
+}
+
+// Runs a Folder selection dialog box, passes back the selected folder in |path|
+// and returns true if the user clicks OK. If the user cancels the dialog box
+// the value in |path| is not modified and returns false. Run on the dialog
+// thread.
+bool ExecuteSelectFolder(HWND owner,
+ SelectFileDialog::Type type,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ std::vector<base::FilePath>* paths) {
+ DCHECK(paths);
+
+ base::string16 new_title = title;
+ if (new_title.empty() && type == SelectFileDialog::SELECT_UPLOAD_FOLDER) {
+ // If it's for uploading don't use default dialog title to
+ // make sure we clearly tell it's for uploading.
+ new_title =
+ l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE);
+ }
+
+ base::string16 ok_button_label;
+ if (type == SelectFileDialog::SELECT_UPLOAD_FOLDER) {
+ ok_button_label = l10n_util::GetStringUTF16(
+ IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON);
+ }
+
+ DWORD dialog_options = FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM;
+
+ std::vector<FileFilterSpec> no_filter;
+ int filter_index = 0;
+
+ return RunOpenFileDialog(owner, new_title, ok_button_label, default_path,
+ no_filter, dialog_options, &filter_index, paths);
+}
+
+bool ExecuteSelectSingleFile(HWND owner,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ int* filter_index,
+ std::vector<base::FilePath>* paths) {
+ // Note: The title is not passed down for historical reasons.
+ // TODO(pmonette): Figure out if it's a worthwhile improvement.
+ return RunOpenFileDialog(owner, base::string16(), base::string16(),
+ default_path, filter, 0, filter_index, paths);
+}
+
+bool ExecuteSelectMultipleFile(HWND owner,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ int* filter_index,
+ std::vector<base::FilePath>* paths) {
+ DWORD dialog_options = FOS_ALLOWMULTISELECT;
+
+ // Note: The title is not passed down for historical reasons.
+ // TODO(pmonette): Figure out if it's a worthwhile improvement.
+ return RunOpenFileDialog(owner, base::string16(), base::string16(),
+ default_path, filter, dialog_options, filter_index,
+ paths);
+}
+
+bool ExecuteSaveFile(HWND owner,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ const base::string16& def_ext,
+ int* filter_index,
+ base::FilePath* path) {
+ DCHECK(path);
+ // Having an empty filter for a bad user experience. We should always
+ // specify a filter when saving.
+ DCHECK(!filter.empty());
+
+ DWORD dialog_options = FOS_OVERWRITEPROMPT;
+
+ // Note: The title is not passed down for historical reasons.
+ // TODO(pmonette): Figure out if it's a worthwhile improvement.
+ return RunSaveFileDialog(owner, base::string16(), default_path, filter,
+ dialog_options, def_ext, filter_index, path);
+}
+
+} // namespace
+
+// This function takes the output of a SaveAs dialog: a filename, a filter and
+// the extension originally suggested to the user (shown in the dialog box) and
+// returns back the filename with the appropriate extension appended. If the
+// user requests an unknown extension and is not using the 'All files' filter,
+// the suggested extension will be appended, otherwise we will leave the
+// filename unmodified. |filename| should contain the filename selected in the
+// SaveAs dialog box and may include the path, |filter_selected| should be
+// '*.something', for example '*.*' or it can be blank (which is treated as
+// *.*). |suggested_ext| should contain the extension without the dot (.) in
+// front, for example 'jpg'.
+base::string16 AppendExtensionIfNeeded(const base::string16& filename,
+ const base::string16& filter_selected,
+ const base::string16& suggested_ext) {
+ DCHECK(!filename.empty());
+ base::string16 return_value = filename;
+
+ // If we wanted a specific extension, but the user's filename deleted it or
+ // changed it to something that the system doesn't understand, re-append.
+ // Careful: Checking net::GetMimeTypeFromExtension() will only find
+ // extensions with a known MIME type, which many "known" extensions on Windows
+ // don't have. So we check directly for the "known extension" registry key.
+ base::string16 file_extension(
+ GetExtensionWithoutLeadingDot(base::FilePath(filename).Extension()));
+ base::string16 key(L"." + file_extension);
+ if (!(filter_selected.empty() || filter_selected == L"*.*") &&
+ !base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
+ file_extension != suggested_ext) {
+ if (return_value.back() != L'.')
+ return_value.append(L".");
+ return_value.append(suggested_ext);
+ }
+
+ // Strip any trailing dots, which Windows doesn't allow.
+ size_t index = return_value.find_last_not_of(L'.');
+ if (index < return_value.size() - 1)
+ return_value.resize(index + 1);
+
+ return return_value;
+}
+
+void ExecuteSelectFile(
+ SelectFileDialog::Type type,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ int file_type_index,
+ const base::string16& default_extension,
+ HWND owner,
+ OnSelectFileExecutedCallback on_select_file_executed_callback) {
+ base::win::AssertComInitialized();
+ std::vector<base::FilePath> paths;
+ switch (type) {
+ case SelectFileDialog::SELECT_FOLDER:
+ case SelectFileDialog::SELECT_UPLOAD_FOLDER:
+ case SelectFileDialog::SELECT_EXISTING_FOLDER:
+ ExecuteSelectFolder(owner, type, title, default_path, &paths);
+ break;
+ case SelectFileDialog::SELECT_SAVEAS_FILE: {
+ base::FilePath path;
+ if (ExecuteSaveFile(owner, default_path, filter, default_extension,
+ &file_type_index, &path)) {
+ paths.push_back(std::move(path));
+ }
+ break;
+ }
+ case SelectFileDialog::SELECT_OPEN_FILE:
+ ExecuteSelectSingleFile(owner, title, default_path, filter,
+ &file_type_index, &paths);
+ break;
+ case SelectFileDialog::SELECT_OPEN_MULTI_FILE:
+ ExecuteSelectMultipleFile(owner, title, default_path, filter,
+ &file_type_index, &paths);
+ break;
+ case SelectFileDialog::SELECT_NONE:
+ NOTREACHED();
+ }
+
+ std::move(on_select_file_executed_callback).Run(paths, file_type_index);
+}
+
+} // namespace ui
diff --git a/chromium/ui/shell_dialogs/execute_select_file_win.h b/chromium/ui/shell_dialogs/execute_select_file_win.h
new file mode 100644
index 00000000000..4d2880be039
--- /dev/null
+++ b/chromium/ui/shell_dialogs/execute_select_file_win.h
@@ -0,0 +1,58 @@
+// 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_SHELL_DIALOGS_EXECUTE_SELECT_FILE_WIN_H_
+#define UI_SHELL_DIALOGS_EXECUTE_SELECT_FILE_WIN_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/strings/string16.h"
+#include "base/win/windows_types.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "ui/shell_dialogs/shell_dialogs_export.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace ui {
+
+// Implementation detail exported for unit tests.
+SHELL_DIALOGS_EXPORT base::string16 AppendExtensionIfNeeded(
+ const base::string16& filename,
+ const base::string16& filter_selected,
+ const base::string16& suggested_ext);
+
+// Describes a filter for a file dialog.
+struct FileFilterSpec {
+ // A human readable description of this filter. E.g. "HTML Files."
+ base::string16 description;
+ // The different extensions that map to this spec. This is a semicolon-
+ // separated list of extensions that contains a wildcard and the separator.
+ // E.g. "*.html;*.htm"
+ base::string16 extension_spec;
+};
+
+using OnSelectFileExecutedCallback =
+ base::OnceCallback<void(const std::vector<base::FilePath>&, int)>;
+
+// Shows the file selection dialog modal to |owner| returns the selected file(s)
+// and file type index using the |on_select_file_executed_callback|. The file
+// path vector will be empty on failure.
+SHELL_DIALOGS_EXPORT
+void ExecuteSelectFile(
+ SelectFileDialog::Type type,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ int file_type_index,
+ const base::string16& default_extension,
+ HWND owner,
+ OnSelectFileExecutedCallback on_select_file_executed_callback);
+
+} // namespace ui
+
+#endif // UI_SHELL_DIALOGS_EXECUTE_SELECT_FILE_WIN_H_
diff --git a/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc b/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc
new file mode 100644
index 00000000000..6f13dd770b6
--- /dev/null
+++ b/chromium/ui/shell_dialogs/execute_select_file_win_unittest.cc
@@ -0,0 +1,54 @@
+// 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/shell_dialogs/execute_select_file_win.h"
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+TEST(ShellDialogsWin, AppendExtensionIfNeeded) {
+ struct AppendExtensionTestCase {
+ const wchar_t* filename;
+ const wchar_t* filter_selected;
+ const wchar_t* suggested_ext;
+ const wchar_t* expected_filename;
+ } test_cases[] = {
+ // Known extensions, with or without associated MIME types, should not get
+ // an extension appended.
+ {L"sample.html", L"*.txt", L"txt", L"sample.html"},
+ {L"sample.reg", L"*.txt", L"txt", L"sample.reg"},
+
+ // An unknown extension, or no extension, should get the default extension
+ // appended.
+ {L"sample.unknown", L"*.txt", L"txt", L"sample.unknown.txt"},
+ {L"sample", L"*.txt", L"txt", L"sample.txt"},
+ // ...unless the unknown and default extensions match.
+ {L"sample.unknown", L"*.unknown", L"unknown", L"sample.unknown"},
+
+ // The extension alone should be treated like a filename with no
+ // extension.
+ {L"txt", L"*.txt", L"txt", L"txt.txt"},
+
+ // Trailing dots should cause us to append an extension.
+ {L"sample.txt.", L"*.txt", L"txt", L"sample.txt.txt"},
+ {L"...", L"*.txt", L"txt", L"...txt"},
+
+ // If the filter is changed to "All files", we allow any filename.
+ {L"sample.unknown", L"*.*", L"", L"sample.unknown"},
+ };
+
+ for (size_t i = 0; i < base::size(test_cases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("i=%zu", i));
+
+ EXPECT_EQ(base::string16(test_cases[i].expected_filename),
+ ui::AppendExtensionIfNeeded(test_cases[i].filename,
+ test_cases[i].filter_selected,
+ test_cases[i].suggested_ext));
+ }
+}
diff --git a/chromium/ui/shell_dialogs/run_all_unittests.cc b/chromium/ui/shell_dialogs/run_all_unittests.cc
index 2e6f7138d11..f5d80c1daf2 100644
--- a/chromium/ui/shell_dialogs/run_all_unittests.cc
+++ b/chromium/ui/shell_dialogs/run_all_unittests.cc
@@ -4,17 +4,18 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "base/path_service.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
#include "build/build_config.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
#if defined(OS_MACOSX)
#include "base/files/file_path.h"
#include "base/mac/bundle_locations.h"
-#include "base/path_service.h"
#include "base/test/mock_chrome_application_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/resource/resource_bundle.h"
#endif
namespace {
@@ -47,17 +48,21 @@ void ShellDialogsTestSuite::Initialize() {
path = path.Append(
FILE_PATH_LITERAL("shell_dialogs_unittests_bundle.framework"));
base::mac::SetOverrideFrameworkBundlePath(path);
+#endif
// Setup resource bundle.
ui::MaterialDesignController::Initialize();
- ui::ResourceBundle::InitSharedInstanceWithLocale(
- "en-US", nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
-#endif
+ ui::RegisterPathProvider();
+
+ base::FilePath ui_test_pak_path;
+ base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path);
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
}
void ShellDialogsTestSuite::Shutdown() {
-#if defined(OS_MACOSX)
ui::ResourceBundle::CleanupSharedInstance();
+
+#if defined(OS_MACOSX)
base::mac::SetOverrideFrameworkBundle(NULL);
#endif
base::TestSuite::Shutdown();
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_mac.mm b/chromium/ui/shell_dialogs/select_file_dialog_mac.mm
index 25742569c7f..29329c65f98 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_mac.mm
+++ b/chromium/ui/shell_dialogs/select_file_dialog_mac.mm
@@ -97,7 +97,7 @@ SelectFileDialogImpl::SelectFileDialogImpl(
[[SelectFileDialogBridge alloc] initWithSelectFileDialogImpl:this]) {}
bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const {
- return parents_.find(parent_window) != parents_.end();
+ return parents_.find(parent_window.GetNativeNSWindow()) != parents_.end();
}
void SelectFileDialogImpl::ListenerDestroyed() {
@@ -141,11 +141,12 @@ void SelectFileDialogImpl::SelectFileImpl(
const FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
+ gfx::NativeWindow owning_native_window,
void* params) {
DCHECK(type == SELECT_FOLDER || type == SELECT_UPLOAD_FOLDER ||
type == SELECT_EXISTING_FOLDER || type == SELECT_OPEN_FILE ||
type == SELECT_OPEN_MULTI_FILE || type == SELECT_SAVEAS_FILE);
+ NSWindow* owning_window = owning_native_window.GetNativeNSWindow();
parents_.insert(owning_window);
// Note: we need to retain the dialog as owning_window can be null.
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm b/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
index b569168cc59..7b15ec2c986 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
+++ b/chromium/ui/shell_dialogs/select_file_dialog_mac_unittest.mm
@@ -6,6 +6,7 @@
#include <vector>
+#include "base/files/file_util.h"
#import "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "base/macros.h"
@@ -442,9 +443,8 @@ TEST_F(SelectFileDialogMacTest, MultipleDialogs) {
// Verify that the default_path argument is respected.
TEST_F(SelectFileDialogMacTest, DefaultPath) {
- const std::string fake_path = "/fake_directory/filename.txt";
FileDialogArguments args(GetDefaultArguments());
- args.default_path = base::FilePath(FILE_PATH_LITERAL(fake_path));
+ args.default_path = base::GetHomeDir().AppendASCII("test.txt");
SelectFileWithParams(args);
NSSavePanel* panel = GetPanel();
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win.cc b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
index 5f30fefc62f..470a0fdb267 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win.cc
@@ -4,16 +4,8 @@
#include "ui/shell_dialogs/select_file_dialog_win.h"
-#include <shlobj.h>
-#include <stddef.h>
-#include <wrl/client.h>
-
#include <algorithm>
#include <memory>
-#include <set>
-#include <tuple>
-#include <utility>
-#include <vector>
#include "base/bind.h"
#include "base/files/file_path.h"
@@ -23,51 +15,32 @@
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/registry.h"
-#include "base/win/shortcut.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/win/open_file_name_win.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/shell_dialogs/base_shell_dialog_win.h"
+#include "ui/shell_dialogs/execute_select_file_win.h"
#include "ui/shell_dialogs/select_file_policy.h"
#include "ui/strings/grit/ui_strings.h"
-namespace {
-
-bool CallBuiltinGetOpenFileName(OPENFILENAME* ofn) {
- return ::GetOpenFileName(ofn) == TRUE;
-}
-
-bool CallBuiltinGetSaveFileName(OPENFILENAME* ofn) {
- return ::GetSaveFileName(ofn) == TRUE;
-}
-
-// Given |extension|, if it's not empty, then remove the leading dot.
-std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) {
- DCHECK(extension.empty() || extension[0] == L'.');
- return extension.empty() ? extension : extension.substr(1);
-}
+namespace ui {
-// Distinguish directories from regular files.
-bool IsDirectory(const base::FilePath& path) {
- base::File::Info file_info;
- return base::GetFileInfo(path, &file_info) ?
- file_info.is_directory : path.EndsWithSeparator();
-}
+namespace {
// Get the file type description from the registry. This will be "Text Document"
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
// have an entry for the file type, we return false, true if the description was
// found. 'file_ext' must be in form ".txt".
-static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
- std::wstring* reg_description) {
+bool GetRegistryDescriptionFromExtension(const base::string16& file_ext,
+ base::string16* reg_description) {
DCHECK(reg_description);
base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
- std::wstring reg_app;
+ base::string16 reg_app;
if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) {
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
@@ -76,28 +49,22 @@ static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
return false;
}
-// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
-// extensions (internally separated by semicolons), |ext_desc| as the text
-// descriptions of the |file_ext| types (optional), and (optionally) the default
-// 'All Files' view. The purpose of the filter is to show only files of a
-// particular type in a Windows Save/Open dialog box. The resulting filter is
-// returned. The filters created here are:
+// Set up a filter for a Save/Open dialog, |ext_desc| as the text descriptions
+// of the |file_ext| types (optional), and (optionally) the default 'All Files'
+// view. The purpose of the filter is to show only files of a particular type in
+// a Windows Save/Open dialog box. The resulting filter is returned. The filter
+// created here are:
// 1. only files that have 'file_ext' as their extension
// 2. all files (only added if 'include_all_files' is true)
-// Example:
-// file_ext: { "*.txt", "*.htm;*.html" }
-// ext_desc: { "Text Document" }
-// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
-// "All Files\0*.*\0\0" (in one big string)
// If a description is not provided for a file extension, it will be retrieved
// from the registry. If the file extension does not exist in the registry, it
// will be omitted from the filter, as it is likely a bogus extension.
-std::wstring FormatFilterForExtensions(
- const std::vector<std::wstring>& file_ext,
- const std::vector<std::wstring>& ext_desc,
+std::vector<FileFilterSpec> FormatFilterForExtensions(
+ const std::vector<base::string16>& file_ext,
+ const std::vector<base::string16>& ext_desc,
bool include_all_files) {
- const std::wstring all_ext = L"*.*";
- const std::wstring all_desc =
+ const base::string16 all_ext = L"*.*";
+ const base::string16 all_desc =
l10n_util::GetStringUTF16(IDS_APP_SAVEAS_ALL_FILES);
DCHECK(file_ext.size() >= ext_desc.size());
@@ -105,11 +72,15 @@ std::wstring FormatFilterForExtensions(
if (file_ext.empty())
include_all_files = true;
- std::wstring result;
+ std::vector<FileFilterSpec> result;
+
+ // Precompute the final size of the resulting vector.
+ size_t final_size = file_ext.size() + (include_all_files ? 1 : 0);
+ result.resize(final_size);
for (size_t i = 0; i < file_ext.size(); ++i) {
- std::wstring ext = file_ext[i];
- std::wstring desc;
+ base::string16 ext = file_ext[i];
+ base::string16 desc;
if (i < ext_desc.size())
desc = ext_desc[i];
@@ -121,16 +92,16 @@ std::wstring FormatFilterForExtensions(
}
if (desc.empty()) {
- DCHECK(ext.find(L'.') != std::wstring::npos);
- std::wstring first_extension = ext.substr(ext.find(L'.'));
+ DCHECK(ext.find(L'.') != base::string16::npos);
+ base::string16 first_extension = ext.substr(ext.find(L'.'));
size_t first_separator_index = first_extension.find(L';');
- if (first_separator_index != std::wstring::npos)
+ if (first_separator_index != base::string16::npos)
first_extension = first_extension.substr(0, first_separator_index);
// Find the extension name without the preceeding '.' character.
- std::wstring ext_name = first_extension;
+ base::string16 ext_name = first_extension;
size_t ext_index = ext_name.find_first_not_of(L'.');
- if (ext_index != std::wstring::npos)
+ if (ext_index != base::string16::npos)
ext_name = ext_name.substr(ext_index);
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
@@ -138,27 +109,35 @@ std::wstring FormatFilterForExtensions(
// based on the unknown extension type (i.e. if the extension is .qqq,
// the we create a description "QQQ File (.qqq)").
include_all_files = true;
- desc = l10n_util::GetStringFUTF16(IDS_APP_SAVEAS_EXTENSION_FORMAT,
- base::i18n::ToUpper(ext_name),
- ext_name);
+ desc =
+ l10n_util::GetStringFUTF16(IDS_APP_SAVEAS_EXTENSION_FORMAT,
+ base::i18n::ToUpper(ext_name), ext_name);
}
if (desc.empty())
desc = L"*." + ext_name;
}
- result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
- result.append(ext.c_str(), ext.size() + 1);
+ result[i] = {desc, ext};
}
- if (include_all_files) {
- result.append(all_desc.c_str(), all_desc.size() + 1);
- result.append(all_ext.c_str(), all_ext.size() + 1);
- }
+ if (include_all_files)
+ result.back() = {all_desc, all_ext};
- result.append(1, '\0'); // Double NULL required.
return result;
}
+// Forwards the result from a select file operation to the SelectFileDialog
+// object on the UI thread.
+void OnSelectFileExecutedOnDialogTaskRunner(
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+ OnSelectFileExecutedCallback on_select_file_executed_callback,
+ const std::vector<base::FilePath>& paths,
+ int index) {
+ ui_task_runner->PostTask(
+ FROM_HERE, base::BindOnce(std::move(on_select_file_executed_callback),
+ paths, index));
+}
+
// Implementation of SelectFileDialog that shows a Windows common dialog for
// choosing a file or folder.
class SelectFileDialogImpl : public ui::SelectFileDialog,
@@ -167,8 +146,7 @@ class SelectFileDialogImpl : public ui::SelectFileDialog,
SelectFileDialogImpl(
Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
- const base::Callback<bool(OPENFILENAME*)>& get_open_file_name_impl,
- const base::Callback<bool(OPENFILENAME*)>& get_save_file_name_impl);
+ const ExecuteSelectFileCallback& execute_select_file_callback);
// BaseShellDialog implementation:
bool IsRunning(gfx::NativeWindow owning_window) const override;
@@ -176,137 +154,40 @@ class SelectFileDialogImpl : public ui::SelectFileDialog,
protected:
// SelectFileDialog implementation:
- void SelectFileImpl(
- Type type,
- const base::string16& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const base::FilePath::StringType& default_extension,
- gfx::NativeWindow owning_window,
- void* params) override;
+ void SelectFileImpl(Type type,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const base::FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params) override;
private:
~SelectFileDialogImpl() override;
- // A struct for holding all the state necessary for displaying a Save dialog.
- struct ExecuteSelectParams {
- ExecuteSelectParams(Type type,
- const std::wstring& title,
- const base::FilePath& default_path,
- const FileTypeInfo* file_types,
- int file_type_index,
- const std::wstring& default_extension,
- RunState run_state,
- HWND owner,
- void* params)
- : type(type),
- title(title),
- default_path(default_path),
- file_type_index(file_type_index),
- default_extension(default_extension),
- run_state(run_state),
- ui_task_runner(base::ThreadTaskRunnerHandle::Get()),
- owner(owner),
- params(params) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
- if (file_types)
- this->file_types = *file_types;
- }
- SelectFileDialog::Type type;
- std::wstring title;
- base::FilePath default_path;
- FileTypeInfo file_types;
- int file_type_index;
- std::wstring default_extension;
- RunState run_state;
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner;
- HWND owner;
- void* params;
- };
-
struct SelectFolderDialogOptions {
const wchar_t* default_path;
bool is_upload;
};
- // Shows the file selection dialog modal to |owner| and calls the result
- // back on the ui thread. Run on the dialog thread.
- void ExecuteSelectFile(const ExecuteSelectParams& params);
-
- // Prompt the user for location to save a file.
- // Callers should provide the filter string, and also a filter index.
- // The parameter |index| indicates the initial index of filter description
- // and filter pattern for the dialog box. If |index| is zero or greater than
- // the number of total filter types, the system uses the first filter in the
- // |filter| buffer. |index| is used to specify the initial selected extension,
- // and when done contains the extension the user chose. The parameter
- // |final_name| returns the file name which contains the drive designator,
- // path, file name, and extension of the user selected file name. |def_ext| is
- // the default extension to give to the file if the user did not enter an
- // extension. If |ignore_suggested_ext| is true, any file extension contained
- // in |suggested_name| will not be used to generate the file name. This is
- // useful in the case of saving web pages, where we know the extension type
- // already and where |suggested_name| may contain a '.' character as a valid
- // part of the name, thus confusing our extension detection code.
- bool SaveFileAsWithFilter(HWND owner,
- const std::wstring& suggested_name,
- const std::wstring& filter,
- const std::wstring& def_ext,
- bool ignore_suggested_ext,
- unsigned* index,
- std::wstring* final_name);
-
- // Notifies the listener that a folder was chosen. Run on the ui thread.
- void FileSelected(const base::FilePath& path, int index,
- void* params, RunState run_state);
-
- // Notifies listener that multiple files were chosen. Run on the ui thread.
- void MultiFilesSelected(const std::vector<base::FilePath>& paths,
- void* params,
- RunState run_state);
-
- // Notifies the listener that no file was chosen (the action was canceled).
- // Run on the ui thread.
- void FileNotSelected(void* params, RunState run_state);
-
- // Runs a Folder selection dialog box, passes back the selected folder in
- // |path| and returns true if the user clicks OK. If the user cancels the
- // dialog box the value in |path| is not modified and returns false. Run
- // on the dedicated dialog sequence.
- bool RunSelectFolderDialog(const ExecuteSelectParams& params,
- base::FilePath* path);
-
- // Runs an Open file dialog box, with similar semantics for input paramaters
- // as RunSelectFolderDialog.
- bool RunOpenFileDialog(const std::wstring& title,
- const std::wstring& filters,
- HWND owner,
- base::FilePath* path);
-
- // Runs an Open file dialog box that supports multi-select, with similar
- // semantics for input paramaters as RunOpenFileDialog.
- bool RunOpenMultiFileDialog(const std::wstring& title,
- const std::wstring& filter,
- const base::FilePath& initial_path,
- HWND owner,
- std::vector<base::FilePath>* paths);
-
- // The callback function for when the select folder dialog is opened.
- static int CALLBACK BrowseCallbackProc(HWND window, UINT message,
- LPARAM parameter,
- LPARAM data);
+ // Returns the result of the select file operation to the listener.
+ void OnSelectFileExecuted(Type type,
+ std::unique_ptr<RunState> run_state,
+ void* params,
+ const std::vector<base::FilePath>& paths,
+ int index);
bool HasMultipleFileTypeChoicesImpl() override;
// Returns the filter to be used while displaying the open/save file dialog.
// This is computed from the extensions for the file types being opened.
// |file_types| can be NULL in which case the returned filter will be empty.
- base::string16 GetFilterForFileTypes(const FileTypeInfo* file_types);
+ static std::vector<FileFilterSpec> GetFilterForFileTypes(
+ const FileTypeInfo* file_types);
bool has_multiple_file_type_choices_;
- base::Callback<bool(OPENFILENAME*)> get_open_file_name_impl_;
- base::Callback<bool(OPENFILENAME*)> get_save_file_name_impl_;
+ ExecuteSelectFileCallback execute_select_file_callback_;
DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
};
@@ -314,15 +195,32 @@ class SelectFileDialogImpl : public ui::SelectFileDialog,
SelectFileDialogImpl::SelectFileDialogImpl(
Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
- const base::Callback<bool(OPENFILENAME*)>& get_open_file_name_impl,
- const base::Callback<bool(OPENFILENAME*)>& get_save_file_name_impl)
+ const ExecuteSelectFileCallback& execute_select_file_callback)
: SelectFileDialog(listener, std::move(policy)),
BaseShellDialogImpl(),
has_multiple_file_type_choices_(false),
- get_open_file_name_impl_(get_open_file_name_impl),
- get_save_file_name_impl_(get_save_file_name_impl) {}
+ execute_select_file_callback_(execute_select_file_callback) {}
+
+SelectFileDialogImpl::~SelectFileDialogImpl() = default;
-SelectFileDialogImpl::~SelectFileDialogImpl() {
+// Invokes the |execute_select_file_callback| and returns the result to
+void DoSelectFileOnDialogTaskRunner(
+ const ExecuteSelectFileCallback& execute_select_file_callback,
+ SelectFileDialog::Type type,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<ui::FileFilterSpec>& filter,
+ int file_type_index,
+ const base::string16& default_extension,
+ HWND owner,
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+ OnSelectFileExecutedCallback on_select_file_executed_callback) {
+ execute_select_file_callback.Run(
+ type, title, default_path, filter, file_type_index, default_extension,
+ owner,
+ base::BindOnce(&OnSelectFileExecutedOnDialogTaskRunner,
+ std::move(ui_task_runner),
+ std::move(on_select_file_executed_callback)));
}
void SelectFileDialogImpl::SelectFileImpl(
@@ -336,16 +234,24 @@ void SelectFileDialogImpl::SelectFileImpl(
void* params) {
has_multiple_file_type_choices_ =
file_types ? file_types->extensions.size() > 1 : true;
+
+ std::vector<FileFilterSpec> filter = GetFilterForFileTypes(file_types);
HWND owner = owning_window && owning_window->GetRootWindow()
- ? owning_window->GetHost()->GetAcceleratedWidget() : NULL;
-
- ExecuteSelectParams execute_params(type, title,
- default_path, file_types, file_type_index,
- default_extension, BeginRun(owner),
- owner, params);
- execute_params.run_state.dialog_task_runner->PostTask(
- FROM_HERE, base::BindOnce(&SelectFileDialogImpl::ExecuteSelectFile, this,
- execute_params));
+ ? owning_window->GetHost()->GetAcceleratedWidget()
+ : NULL;
+
+ std::unique_ptr<RunState> run_state = BeginRun(owner);
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ run_state->dialog_task_runner;
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&DoSelectFileOnDialogTaskRunner,
+ execute_select_file_callback_, type, title, default_path,
+ filter, file_type_index, default_extension, owner,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::BindOnce(&SelectFileDialogImpl::OnSelectFileExecuted,
+ this, type, std::move(run_state), params)));
}
bool SelectFileDialogImpl::HasMultipleFileTypeChoicesImpl() {
@@ -365,309 +271,43 @@ void SelectFileDialogImpl::ListenerDestroyed() {
listener_ = NULL;
}
-void SelectFileDialogImpl::ExecuteSelectFile(
- const ExecuteSelectParams& params) {
- base::string16 filter = GetFilterForFileTypes(&params.file_types);
-
- base::FilePath path = params.default_path;
- bool success = false;
- unsigned filter_index = params.file_type_index;
- if (params.type == SELECT_FOLDER || params.type == SELECT_UPLOAD_FOLDER ||
- params.type == SELECT_EXISTING_FOLDER) {
- success = RunSelectFolderDialog(params, &path);
- } else if (params.type == SELECT_SAVEAS_FILE) {
- std::wstring path_as_wstring = path.value();
- success = SaveFileAsWithFilter(params.run_state.owner,
- params.default_path.value(), filter,
- params.default_extension, false, &filter_index, &path_as_wstring);
- if (success)
- path = base::FilePath(path_as_wstring);
- DisableOwner(params.run_state.owner);
- } else if (params.type == SELECT_OPEN_FILE) {
- success = RunOpenFileDialog(params.title, filter,
- params.run_state.owner, &path);
- } else if (params.type == SELECT_OPEN_MULTI_FILE) {
- std::vector<base::FilePath> paths;
- if (RunOpenMultiFileDialog(params.title, filter, path,
- params.run_state.owner, &paths)) {
- params.ui_task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(&SelectFileDialogImpl::MultiFilesSelected, this, paths,
- params.params, params.run_state));
- return;
- }
- }
-
- if (success) {
- params.ui_task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(&SelectFileDialogImpl::FileSelected, this, path,
- filter_index, params.params, params.run_state));
- } else {
- params.ui_task_runner->PostTask(
- FROM_HERE, base::BindOnce(&SelectFileDialogImpl::FileNotSelected, this,
- params.params, params.run_state));
- }
-}
-
-bool SelectFileDialogImpl::SaveFileAsWithFilter(
- HWND owner,
- const std::wstring& suggested_name,
- const std::wstring& filter,
- const std::wstring& def_ext,
- bool ignore_suggested_ext,
- unsigned* index,
- std::wstring* final_name) {
- DCHECK(final_name);
- // Having an empty filter makes for a bad user experience. We should always
- // specify a filter when saving.
- DCHECK(!filter.empty());
-
- ui::win::OpenFileName save_as(owner,
- OFN_OVERWRITEPROMPT | OFN_EXPLORER |
- OFN_ENABLESIZING | OFN_NOCHANGEDIR |
- OFN_PATHMUSTEXIST);
-
- const base::FilePath suggested_path = base::FilePath(suggested_name);
- if (!suggested_name.empty()) {
- base::FilePath suggested_file_name;
- base::FilePath suggested_directory;
- if (IsDirectory(suggested_path)) {
- suggested_directory = suggested_path;
- } else {
- suggested_directory = suggested_path.DirName();
- suggested_file_name = suggested_path.BaseName();
- // If the suggested_name is a root directory, file_part will be '\', and
- // the call to GetSaveFileName below will fail.
- if (suggested_file_name.value() == L"\\")
- suggested_file_name.clear();
- }
- save_as.SetInitialSelection(suggested_directory, suggested_file_name);
- }
-
- save_as.GetOPENFILENAME()->lpstrFilter =
- filter.empty() ? NULL : filter.c_str();
- save_as.GetOPENFILENAME()->nFilterIndex = *index;
- save_as.GetOPENFILENAME()->lpstrDefExt = &def_ext[0];
-
- if (!get_save_file_name_impl_.Run(save_as.GetOPENFILENAME()))
- return false;
-
- // Return the user's choice.
- final_name->assign(save_as.GetOPENFILENAME()->lpstrFile);
- *index = save_as.GetOPENFILENAME()->nFilterIndex;
-
- // Figure out what filter got selected. The filter index is 1-based.
- std::wstring filter_selected;
- if (*index > 0) {
- std::vector<std::tuple<base::string16, base::string16>> filters =
- ui::win::OpenFileName::GetFilters(save_as.GetOPENFILENAME());
- if (*index > filters.size())
- NOTREACHED() << "Invalid filter index.";
- else
- filter_selected = std::get<1>(filters[*index - 1]);
- }
-
- // Get the extension that was suggested to the user (when the Save As dialog
- // was opened). For saving web pages, we skip this step since there may be
- // 'extension characters' in the title of the web page.
- std::wstring suggested_ext;
- if (!ignore_suggested_ext)
- suggested_ext = GetExtensionWithoutLeadingDot(suggested_path.Extension());
-
- // If we can't get the extension from the suggested_name, we use the default
- // extension passed in. This is to cover cases like when saving a web page,
- // where we get passed in a name without an extension and a default extension
- // along with it.
- if (suggested_ext.empty())
- suggested_ext = def_ext;
-
- *final_name =
- ui::AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext);
- return true;
-}
-
-void SelectFileDialogImpl::FileSelected(const base::FilePath& selected_folder,
- int index,
- void* params,
- RunState run_state) {
- if (listener_)
- listener_->FileSelected(selected_folder, index, params);
- EndRun(run_state);
-}
-
-void SelectFileDialogImpl::MultiFilesSelected(
- const std::vector<base::FilePath>& selected_files,
+void SelectFileDialogImpl::OnSelectFileExecuted(
+ Type type,
+ std::unique_ptr<RunState> run_state,
void* params,
- RunState run_state) {
- if (listener_)
- listener_->MultiFilesSelected(selected_files, params);
- EndRun(run_state);
-}
-
-void SelectFileDialogImpl::FileNotSelected(void* params, RunState run_state) {
- if (listener_)
- listener_->FileSelectionCanceled(params);
- EndRun(run_state);
-}
-
-int CALLBACK SelectFileDialogImpl::BrowseCallbackProc(HWND window,
- UINT message,
- LPARAM parameter,
- LPARAM data) {
- if (message == BFFM_INITIALIZED) {
- SelectFolderDialogOptions* options =
- reinterpret_cast<SelectFolderDialogOptions*>(data);
- if (options->is_upload) {
- SendMessage(window, BFFM_SETOKTEXT, 0,
- reinterpret_cast<LPARAM>(
- l10n_util::GetStringUTF16(
- IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)
- .c_str()));
- }
- if (options->default_path) {
- SendMessage(window, BFFM_SETSELECTION, TRUE,
- reinterpret_cast<LPARAM>(options->default_path));
- }
- }
- return 0;
-}
-
-bool SelectFileDialogImpl::RunSelectFolderDialog(
- const ExecuteSelectParams& params,
- base::FilePath* path) {
- DCHECK(path);
- std::wstring title = params.title;
- if (title.empty() && params.type == SELECT_UPLOAD_FOLDER) {
- // If it's for uploading don't use default dialog title to
- // make sure we clearly tell it's for uploading.
- title = l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE);
- }
-
- wchar_t dir_buffer[MAX_PATH + 1];
-
- bool result = false;
- BROWSEINFO browse_info = {0};
- browse_info.hwndOwner = params.run_state.owner;
- browse_info.lpszTitle = title.c_str();
- browse_info.pszDisplayName = dir_buffer;
- browse_info.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
-
- // If uploading or a default path was provided, update the BROWSEINFO
- // and set the callback function for the dialog so the strings can be set in
- // the callback.
- SelectFolderDialogOptions dialog_options = {0};
- if (path->value().length())
- dialog_options.default_path = path->value().c_str();
- if (params.type == SELECT_UPLOAD_FOLDER) {
- dialog_options.is_upload = true;
- }
- if (params.type == SELECT_UPLOAD_FOLDER ||
- params.type == SELECT_EXISTING_FOLDER)
- browse_info.ulFlags |= BIF_NONEWFOLDERBUTTON;
- if (dialog_options.is_upload || dialog_options.default_path) {
- browse_info.lParam = reinterpret_cast<LPARAM>(&dialog_options);
- browse_info.lpfn = &BrowseCallbackProc;
- }
-
- LPITEMIDLIST list = SHBrowseForFolder(&browse_info);
- DisableOwner(params.run_state.owner);
- if (list) {
- STRRET out_dir_buffer;
- ZeroMemory(&out_dir_buffer, sizeof(out_dir_buffer));
- out_dir_buffer.uType = STRRET_WSTR;
- Microsoft::WRL::ComPtr<IShellFolder> shell_folder;
- if (SHGetDesktopFolder(shell_folder.GetAddressOf()) == NOERROR) {
- HRESULT hr = shell_folder->GetDisplayNameOf(list, SHGDN_FORPARSING,
- &out_dir_buffer);
- if (SUCCEEDED(hr) && out_dir_buffer.uType == STRRET_WSTR) {
- *path = base::FilePath(out_dir_buffer.pOleStr);
- CoTaskMemFree(out_dir_buffer.pOleStr);
- result = true;
- } else {
- // Use old way if we don't get what we want.
- wchar_t old_out_dir_buffer[MAX_PATH + 1];
- if (SHGetPathFromIDList(list, old_out_dir_buffer)) {
- *path = base::FilePath(old_out_dir_buffer);
- result = true;
- }
+ const std::vector<base::FilePath>& paths,
+ int index) {
+ if (listener_) {
+ // The paths vector is empty when the user cancels the dialog.
+ if (paths.empty()) {
+ listener_->FileSelectionCanceled(params);
+ } else {
+ switch (type) {
+ case SELECT_FOLDER:
+ case SELECT_UPLOAD_FOLDER:
+ case SELECT_EXISTING_FOLDER:
+ case SELECT_SAVEAS_FILE:
+ case SELECT_OPEN_FILE:
+ DCHECK_EQ(paths.size(), 1u);
+ listener_->FileSelected(paths[0], index, params);
+ break;
+ case SELECT_OPEN_MULTI_FILE:
+ listener_->MultiFilesSelected(paths, params);
+ break;
+ case SELECT_NONE:
+ NOTREACHED();
}
-
- // According to MSDN, win2000 will not resolve shortcuts, so we do it
- // ourself.
- base::win::ResolveShortcut(*path, path, NULL);
}
- CoTaskMemFree(list);
}
- return result;
-}
-bool SelectFileDialogImpl::RunOpenFileDialog(const std::wstring& title,
- const std::wstring& filter,
- HWND owner,
- base::FilePath* path) {
- // We use OFN_NOCHANGEDIR so that the user can rename or delete the
- // directory without having to close Chrome first.
- ui::win::OpenFileName ofn(owner, OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR);
- if (!path->empty()) {
- if (IsDirectory(*path))
- ofn.SetInitialSelection(*path, base::FilePath());
- else
- ofn.SetInitialSelection(path->DirName(), path->BaseName());
- }
-
- if (!filter.empty())
- ofn.GetOPENFILENAME()->lpstrFilter = filter.c_str();
-
- bool success = get_open_file_name_impl_.Run(ofn.GetOPENFILENAME());
- DisableOwner(owner);
- if (success)
- *path = ofn.GetSingleResult();
- return success;
-}
-
-bool SelectFileDialogImpl::RunOpenMultiFileDialog(
- const std::wstring& title,
- const std::wstring& filter,
- const base::FilePath& initial_path,
- HWND owner,
- std::vector<base::FilePath>* paths) {
- // We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
- // without having to close Chrome first.
- ui::win::OpenFileName ofn(owner,
- OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
- OFN_EXPLORER | OFN_HIDEREADONLY |
- OFN_ALLOWMULTISELECT | OFN_NOCHANGEDIR);
- if (!initial_path.empty()) {
- if (IsDirectory(initial_path))
- ofn.SetInitialSelection(initial_path, base::FilePath());
- else
- ofn.SetInitialSelection(initial_path.DirName(), base::FilePath());
- }
- if (!filter.empty())
- ofn.GetOPENFILENAME()->lpstrFilter = filter.c_str();
-
- base::FilePath directory;
- std::vector<base::FilePath> filenames;
-
- if (get_open_file_name_impl_.Run(ofn.GetOPENFILENAME()))
- ofn.GetResult(&directory, &filenames);
-
- DisableOwner(owner);
-
- for (std::vector<base::FilePath>::iterator it = filenames.begin();
- it != filenames.end();
- ++it) {
- paths->push_back(directory.Append(*it));
- }
-
- return !paths->empty();
+ EndRun(std::move(run_state));
}
-base::string16 SelectFileDialogImpl::GetFilterForFileTypes(
+// static
+std::vector<FileFilterSpec> SelectFileDialogImpl::GetFilterForFileTypes(
const FileTypeInfo* file_types) {
if (!file_types)
- return base::string16();
+ return std::vector<FileFilterSpec>();
std::vector<base::string16> exts;
for (size_t i = 0; i < file_types->extensions.size(); ++i) {
@@ -681,73 +321,26 @@ base::string16 SelectFileDialogImpl::GetFilterForFileTypes(
}
exts.push_back(ext_string);
}
- return FormatFilterForExtensions(
- exts,
- file_types->extension_description_overrides,
- file_types->include_all_files);
+ return FormatFilterForExtensions(exts,
+ file_types->extension_description_overrides,
+ file_types->include_all_files);
}
} // namespace
-namespace ui {
-
-// This function takes the output of a SaveAs dialog: a filename, a filter and
-// the extension originally suggested to the user (shown in the dialog box) and
-// returns back the filename with the appropriate extension tacked on. If the
-// user requests an unknown extension and is not using the 'All files' filter,
-// the suggested extension will be appended, otherwise we will leave the
-// filename unmodified. |filename| should contain the filename selected in the
-// SaveAs dialog box and may include the path, |filter_selected| should be
-// '*.something', for example '*.*' or it can be blank (which is treated as
-// *.*). |suggested_ext| should contain the extension without the dot (.) in
-// front, for example 'jpg'.
-std::wstring AppendExtensionIfNeeded(
- const std::wstring& filename,
- const std::wstring& filter_selected,
- const std::wstring& suggested_ext) {
- DCHECK(!filename.empty());
- std::wstring return_value = filename;
-
- // If we wanted a specific extension, but the user's filename deleted it or
- // changed it to something that the system doesn't understand, re-append.
- // Careful: Checking net::GetMimeTypeFromExtension() will only find
- // extensions with a known MIME type, which many "known" extensions on Windows
- // don't have. So we check directly for the "known extension" registry key.
- std::wstring file_extension(
- GetExtensionWithoutLeadingDot(base::FilePath(filename).Extension()));
- std::wstring key(L"." + file_extension);
- if (!(filter_selected.empty() || filter_selected == L"*.*") &&
- !base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
- file_extension != suggested_ext) {
- if (return_value.back() != L'.')
- return_value.append(L".");
- return_value.append(suggested_ext);
- }
-
- // Strip any trailing dots, which Windows doesn't allow.
- size_t index = return_value.find_last_not_of(L'.');
- if (index < return_value.size() - 1)
- return_value.resize(index + 1);
-
- return return_value;
-}
-
SelectFileDialog* CreateWinSelectFileDialog(
SelectFileDialog::Listener* listener,
std::unique_ptr<SelectFilePolicy> policy,
- const base::Callback<bool(OPENFILENAME* ofn)>& get_open_file_name_impl,
- const base::Callback<bool(OPENFILENAME* ofn)>& get_save_file_name_impl) {
+ const ExecuteSelectFileCallback& execute_select_file_callback) {
return new SelectFileDialogImpl(listener, std::move(policy),
- get_open_file_name_impl,
- get_save_file_name_impl);
+ execute_select_file_callback);
}
SelectFileDialog* CreateSelectFileDialog(
SelectFileDialog::Listener* listener,
std::unique_ptr<SelectFilePolicy> policy) {
return CreateWinSelectFileDialog(listener, std::move(policy),
- base::Bind(&CallBuiltinGetOpenFileName),
- base::Bind(&CallBuiltinGetSaveFileName));
+ base::BindRepeating(&ui::ExecuteSelectFile));
}
} // namespace ui
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win.h b/chromium/ui/shell_dialogs/select_file_dialog_win.h
index 22ef919a919..6d09000b96e 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win.h
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win.h
@@ -5,29 +5,40 @@
#ifndef UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_WIN_H_
#define UI_SHELL_DIALOGS_SELECT_FILE_DIALOG_WIN_H_
-#include <Windows.h>
-#include <commdlg.h>
+#include <memory>
+#include <utility>
+#include <vector>
#include "base/callback_forward.h"
+#include "base/strings/string16.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/shell_dialogs/execute_select_file_win.h"
#include "ui/shell_dialogs/select_file_dialog.h"
#include "ui/shell_dialogs/shell_dialogs_export.h"
+namespace base {
+class FilePath;
+}
+
namespace ui {
class SelectFilePolicy;
-
-// Implementation detail exported for unit tests.
-SHELL_DIALOGS_EXPORT std::wstring AppendExtensionIfNeeded(
- const std::wstring& filename,
- const std::wstring& filter_selected,
- const std::wstring& suggested_ext);
+struct FileFilterSpec;
+
+using ExecuteSelectFileCallback = base::RepeatingCallback<void(
+ SelectFileDialog::Type type,
+ const base::string16& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ int file_type_index,
+ const base::string16& default_extension,
+ HWND owner,
+ OnSelectFileExecutedCallback on_select_file_executed_callback)>;
SHELL_DIALOGS_EXPORT SelectFileDialog* CreateWinSelectFileDialog(
SelectFileDialog::Listener* listener,
std::unique_ptr<SelectFilePolicy> policy,
- const base::Callback<bool(OPENFILENAME* ofn)>& get_open_file_name_impl,
- const base::Callback<bool(OPENFILENAME* ofn)>& get_save_file_name_impl);
+ const ExecuteSelectFileCallback& execute_select_file_callback);
} // namespace ui
diff --git a/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc b/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc
index a01ebe8675e..2f8d4f345c9 100644
--- a/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc
+++ b/chromium/ui/shell_dialogs/select_file_dialog_win_unittest.cc
@@ -4,46 +4,502 @@
#include <stddef.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/scoped_com_initializer.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
#include "ui/shell_dialogs/select_file_dialog.h"
#include "ui/shell_dialogs/select_file_dialog_win.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace {
+
+// The default title for the various dialogs.
+constexpr wchar_t kSelectFolderDefaultTitle[] = L"Select Folder";
+constexpr wchar_t kSelectFileDefaultTitle[] = L"Open";
+constexpr wchar_t kSaveFileDefaultTitle[] = L"Save As";
+
+// Returns the title of |window|.
+base::string16 GetWindowTitle(HWND window) {
+ wchar_t buffer[256];
+ UINT count = ::GetWindowText(window, buffer, base::size(buffer));
+ return base::string16(buffer, count);
+}
+
+// Waits for a dialog window whose title is |dialog_title| to show and returns
+// its handle.
+HWND WaitForDialogWindow(const base::string16& dialog_title) {
+ // File dialogs uses this class name.
+ static constexpr wchar_t kDialogClassName[] = L"#32770";
+
+ HWND result = nullptr;
+ while (!result) {
+ result = ::FindWindow(kDialogClassName, dialog_title.c_str());
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+ }
-TEST(ShellDialogsWin, AppendExtensionIfNeeded) {
- struct AppendExtensionTestCase {
- const wchar_t* filename;
- const wchar_t* filter_selected;
- const wchar_t* suggested_ext;
- const wchar_t* expected_filename;
- } test_cases[] = {
- // Known extensions, with or without associated MIME types, should not get
- // an extension appended.
- { L"sample.html", L"*.txt", L"txt", L"sample.html" },
- { L"sample.reg", L"*.txt", L"txt", L"sample.reg" },
+ // Check the name of the dialog specifically. That's because if multiple file
+ // dialogs are opened in quick successions (e.g. from one test to another),
+ // the ::FindWindow() call above will work for both the previous dialog title
+ // and the current.
+ return GetWindowTitle(result) == dialog_title ? result : nullptr;
+}
+
+struct EnumWindowsParam {
+ // The owner of the dialog. This is used to differentiate the dialog prompt
+ // from the file dialog since they could have the same title.
+ HWND owner;
+
+ // Holds the resulting window.
+ HWND result;
+};
+
+BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM param) {
+ EnumWindowsParam* enum_param = reinterpret_cast<EnumWindowsParam*>(param);
- // An unknown extension, or no extension, should get the default extension
- // appended.
- { L"sample.unknown", L"*.txt", L"txt", L"sample.unknown.txt" },
- { L"sample", L"*.txt", L"txt", L"sample.txt" },
- // ...unless the unknown and default extensions match.
- { L"sample.unknown", L"*.unknown", L"unknown", L"sample.unknown" },
+ // Early continue if the current hwnd is the file dialog.
+ if (hwnd == enum_param->owner)
+ return TRUE;
+
+ // Only consider visible windows.
+ if (!::IsWindowVisible(hwnd))
+ return TRUE;
+
+ // If the window doesn't have |enum_param->owner| as the owner, it can't be
+ // the prompt dialog.
+ if (::GetWindow(hwnd, GW_OWNER) != enum_param->owner)
+ return TRUE;
+
+ enum_param->result = hwnd;
+ return FALSE;
+}
- // The extension alone should be treated like a filename with no extension.
- { L"txt", L"*.txt", L"txt", L"txt.txt" },
+HWND WaitForDialogPrompt(HWND owner) {
+ // The dialog prompt could have the same title as the file dialog. This means
+ // that it would not be possible to make sure the right window is found using
+ // ::FindWindow(). Instead enumerate all top-level windows and return the one
+ // whose owner is the file dialog.
+ EnumWindowsParam param = {owner, nullptr};
- // Trailing dots should cause us to append an extension.
- { L"sample.txt.", L"*.txt", L"txt", L"sample.txt.txt" },
- { L"...", L"*.txt", L"txt", L"...txt" },
+ while (!param.result) {
+ ::EnumWindows(&EnumWindowsCallback, reinterpret_cast<LPARAM>(&param));
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+ }
+
+ return param.result;
+}
+
+// Returns the text of the dialog item in |window| whose id is |dialog_item_id|.
+base::string16 GetDialogItemText(HWND window, int dialog_item_id) {
+ if (!window)
+ return base::string16();
+
+ wchar_t buffer[256];
+ UINT count =
+ ::GetDlgItemText(window, dialog_item_id, buffer, base::size(buffer));
+ return base::string16(buffer, count);
+}
+
+// Sends a command to |window| using PostMessage().
+void SendCommand(HWND window, int id) {
+ ASSERT_TRUE(window);
+
+ // Make sure the window is visible first or the WM_COMMAND may not have any
+ // effect.
+ while (!::IsWindowVisible(window))
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+
+ ::PostMessage(window, WM_COMMAND, id, 0);
+}
+
+} // namespace
+
+class SelectFileDialogWinTest : public ::testing::Test,
+ public ui::SelectFileDialog::Listener {
+ public:
+ SelectFileDialogWinTest() = default;
+ ~SelectFileDialogWinTest() override = default;
+
+ // ui::SelectFileDialog::Listener:
+ void FileSelected(const base::FilePath& path,
+ int index,
+ void* params) override {
+ selected_paths_.push_back(path);
+ }
+ void MultiFilesSelected(const std::vector<base::FilePath>& files,
+ void* params) override {
+ selected_paths_ = files;
+ }
+ void FileSelectionCanceled(void* params) override { was_cancelled_ = true; }
- // If the filter is changed to "All files", we allow any filename.
- { L"sample.unknown", L"*.*", L"", L"sample.unknown" },
- };
+ // Runs the scheduler until no tasks are executing anymore.
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- EXPECT_EQ(std::wstring(test_cases[i].expected_filename),
- ui::AppendExtensionIfNeeded(test_cases[i].filename,
- test_cases[i].filter_selected,
- test_cases[i].suggested_ext));
+ const std::vector<base::FilePath>& selected_paths() {
+ return selected_paths_;
}
+
+ // Return a fake NativeWindow. This will result in the dialog having no
+ // parent window but the tests will still work.
+ static gfx::NativeWindow native_window() {
+ return reinterpret_cast<gfx::NativeWindow>(0);
+ }
+
+ bool was_cancelled() { return was_cancelled_; }
+
+ // Resets the results so that this instance can be reused as a
+ // SelectFileDialog listener.
+ void ResetResults() {
+ was_cancelled_ = false;
+ selected_paths_.clear();
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ std::vector<base::FilePath> selected_paths_;
+ bool was_cancelled_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(SelectFileDialogWinTest);
+};
+
+TEST_F(SelectFileDialogWinTest, CancelAllDialogs) {
+ // Intentionally not testing SELECT_UPLOAD_FOLDER because the dialog is
+ // customized for that case.
+ struct {
+ ui::SelectFileDialog::Type dialog_type;
+ const wchar_t* dialog_title;
+ } kTestCases[] = {
+ {
+ ui::SelectFileDialog::SELECT_FOLDER, kSelectFolderDefaultTitle,
+ },
+ {
+ ui::SelectFileDialog::SELECT_EXISTING_FOLDER,
+ kSelectFolderDefaultTitle,
+ },
+ {
+ ui::SelectFileDialog::SELECT_SAVEAS_FILE, kSaveFileDefaultTitle,
+ },
+ {
+ ui::SelectFileDialog::SELECT_OPEN_FILE, kSelectFileDefaultTitle,
+ },
+ {
+ ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE, kSelectFileDefaultTitle,
+ }};
+
+ for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ SCOPED_TRACE(base::StringPrintf("i=%zu", i));
+
+ const auto& test_case = kTestCases[i];
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+
+ std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> file_type_info;
+ int file_type_info_index = 0;
+
+ // The Save As dialog requires a filetype info.
+ if (test_case.dialog_type == ui::SelectFileDialog::SELECT_SAVEAS_FILE) {
+ file_type_info = std::make_unique<ui::SelectFileDialog::FileTypeInfo>();
+ file_type_info->extensions.push_back({L"html"});
+ file_type_info_index = 1;
+ }
+
+ dialog->SelectFile(test_case.dialog_type, base::string16(),
+ base::FilePath(), file_type_info.get(),
+ file_type_info_index, base::string16(), native_window(),
+ nullptr);
+
+ // Accept the default value.
+ HWND window = WaitForDialogWindow(test_case.dialog_title);
+ SendCommand(window, IDCANCEL);
+
+ RunUntilIdle();
+
+ EXPECT_TRUE(was_cancelled());
+ EXPECT_TRUE(selected_paths().empty());
+
+ ResetResults();
+ }
+}
+
+// When using SELECT_UPLOAD_FOLDER, the title and the ok button strings are
+// modified to put emphasis on the fact that the whole folder will be uploaded.
+TEST_F(SelectFileDialogWinTest, UploadFolderCheckStrings) {
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+ base::FilePath default_path = scoped_temp_dir.GetPath();
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_UPLOAD_FOLDER,
+ base::string16(), default_path, nullptr, 0, L"",
+ native_window(), nullptr);
+
+ // Wait for the window to open and make sure the window title was changed from
+ // the default title for a regular select folder operation.
+ HWND window = WaitForDialogWindow(
+ l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE));
+ EXPECT_NE(GetWindowTitle(window), kSelectFolderDefaultTitle);
+
+ // Check the OK button text.
+ EXPECT_EQ(
+ GetDialogItemText(window, 1),
+ l10n_util::GetStringUTF16(IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON));
+
+ // Close the dialog.
+ SendCommand(window, IDOK);
+
+ RunUntilIdle();
+
+ EXPECT_FALSE(was_cancelled());
+ ASSERT_EQ(1u, selected_paths().size());
+ EXPECT_EQ(selected_paths()[0], default_path);
+}
+
+// Specifying the title when opening a dialog to select a file, select multiple
+// files or save a file doesn't do anything.
+TEST_F(SelectFileDialogWinTest, SpecifyTitle) {
+ static constexpr wchar_t kTitle[] = L"FooBar Title";
+
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ // Create an existing file since it is required.
+ base::FilePath default_path = scoped_temp_dir.GetPath().Append(L"foo.txt");
+ std::string contents = "Hello test!";
+ ASSERT_EQ(base::WriteFile(default_path, contents.c_str(), contents.length()),
+ static_cast<int>(contents.length()));
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, kTitle,
+ default_path, nullptr, 0, L"", native_window(), nullptr);
+
+ // Wait for the window to open. The title is unchanged. Note that if this
+ // hangs, it possibly is because the title changed.
+ HWND window = WaitForDialogWindow(kSelectFileDefaultTitle);
+
+ // Close the dialog and the result doesn't matter.
+ SendCommand(window, IDCANCEL);
+}
+
+// Tests the selection of one file in both the single and multiple case. It's
+// too much trouble to select a different file in the dialog so the default_path
+// is used to pre-select a file and the OK button is clicked as soon as the
+// dialog opens. This tests the default_path parameter and the single file
+// selection.
+TEST_F(SelectFileDialogWinTest, TestSelectFile) {
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ // Create an existing file since it is required.
+ base::FilePath default_path = scoped_temp_dir.GetPath().Append(L"foo.txt");
+ std::string contents = "Hello test!";
+ ASSERT_EQ(base::WriteFile(default_path, contents.c_str(), contents.length()),
+ static_cast<int>(contents.length()));
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(),
+ default_path, nullptr, 0, L"", native_window(), nullptr);
+
+ // Wait for the window to open
+ HWND window = WaitForDialogWindow(kSelectFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ RunUntilIdle();
+
+ EXPECT_FALSE(was_cancelled());
+ ASSERT_EQ(1u, selected_paths().size());
+ EXPECT_EQ(selected_paths()[0], default_path);
}
+// Tests that the file extension is automatically added.
+TEST_F(SelectFileDialogWinTest, TestSaveFile) {
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ base::FilePath default_path = scoped_temp_dir.GetPath().Append(L"foo");
+
+ ui::SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.push_back({L"html"});
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
+ default_path, &file_type_info, 1, L"", native_window(),
+ nullptr);
+
+ // Wait for the window to open
+ HWND window = WaitForDialogWindow(kSaveFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ RunUntilIdle();
+
+ EXPECT_FALSE(was_cancelled());
+ ASSERT_EQ(1u, selected_paths().size());
+ EXPECT_EQ(selected_paths()[0], default_path.AddExtension(L"html"));
+}
+
+// Tests that only specifying a basename as the default path works.
+TEST_F(SelectFileDialogWinTest, OnlyBasename) {
+ base::FilePath default_path(L"foobar.html");
+
+ ui::SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.push_back({L"html"});
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
+ default_path, &file_type_info, 1, L"", native_window(),
+ nullptr);
+
+ // Wait for the window to open
+ HWND window = WaitForDialogWindow(kSaveFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ RunUntilIdle();
+
+ EXPECT_FALSE(was_cancelled());
+ ASSERT_EQ(1u, selected_paths().size());
+ EXPECT_EQ(selected_paths()[0].BaseName(), default_path);
+}
+
+TEST_F(SelectFileDialogWinTest, SaveAsDifferentExtension) {
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ base::FilePath default_path = scoped_temp_dir.GetPath().Append(L"foo.txt");
+
+ ui::SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.push_back({L"exe"});
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
+ default_path, &file_type_info, 1, L"html", native_window(),
+ nullptr);
+
+ HWND window = WaitForDialogWindow(kSaveFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ RunUntilIdle();
+
+ EXPECT_FALSE(was_cancelled());
+ EXPECT_EQ(selected_paths()[0], default_path);
+}
+
+TEST_F(SelectFileDialogWinTest, OpenFileDifferentExtension) {
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ base::FilePath default_path = scoped_temp_dir.GetPath().Append(L"foo.txt");
+ std::string contents = "Hello test!";
+ ASSERT_EQ(base::WriteFile(default_path, contents.c_str(), contents.length()),
+ static_cast<int>(contents.length()));
+
+ ui::SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.push_back({L"exe"});
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(),
+ default_path, &file_type_info, 1, L"html", native_window(),
+ nullptr);
+
+ HWND window = WaitForDialogWindow(kSelectFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ RunUntilIdle();
+
+ EXPECT_FALSE(was_cancelled());
+ EXPECT_EQ(selected_paths()[0], default_path);
+}
+
+TEST_F(SelectFileDialogWinTest, SelectNonExistingFile) {
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ base::FilePath default_path =
+ scoped_temp_dir.GetPath().Append(L"does-not-exist.html");
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(),
+ default_path, nullptr, 0, L"", native_window(), nullptr);
+
+ HWND window = WaitForDialogWindow(kSelectFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ // Since selecting a non-existing file is not supported, a error dialog box
+ // should have appeared.
+ HWND error_box = WaitForDialogPrompt(window);
+ SendCommand(error_box, IDOK);
+
+ // Now actually cancel the file dialog box.
+ SendCommand(window, IDCANCEL);
+
+ RunUntilIdle();
+
+ EXPECT_TRUE(was_cancelled());
+ EXPECT_TRUE(selected_paths().empty());
+}
+
+// Tests that selecting an existing file when saving should prompt the user with
+// a dialog to confirm the overwrite.
+TEST_F(SelectFileDialogWinTest, SaveFileOverwritePrompt) {
+ // Create some file in a test folder.
+ base::ScopedTempDir scoped_temp_dir;
+ ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+ base::FilePath default_path = scoped_temp_dir.GetPath().Append(L"foo.txt");
+ std::string contents = "Hello test!";
+ ASSERT_EQ(base::WriteFile(default_path, contents.c_str(), contents.length()),
+ static_cast<int>(contents.length()));
+
+ ui::SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.push_back({L"txt"});
+
+ scoped_refptr<ui::SelectFileDialog> dialog =
+ ui::SelectFileDialog::Create(this, nullptr);
+ dialog->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
+ default_path, &file_type_info, 1, L"", native_window(),
+ nullptr);
+
+ HWND window = WaitForDialogWindow(kSaveFileDefaultTitle);
+ SendCommand(window, IDOK);
+
+ // Check that the prompt appears and close it. By default, the "no" option is
+ // selected so sending IDOK cancels the operation.
+ HWND error_box = WaitForDialogPrompt(window);
+ SendCommand(error_box, IDOK);
+
+ // Cancel the dialog.
+ SendCommand(window, IDCANCEL);
+
+ RunUntilIdle();
+
+ EXPECT_TRUE(was_cancelled());
+ EXPECT_TRUE(selected_paths().empty());
+}
diff --git a/chromium/ui/snapshot/screenshot_grabber.cc b/chromium/ui/snapshot/screenshot_grabber.cc
index 73b56dd7498..285fd0c2361 100644
--- a/chromium/ui/snapshot/screenshot_grabber.cc
+++ b/chromium/ui/snapshot/screenshot_grabber.cc
@@ -73,7 +73,7 @@ ScreenshotGrabber::~ScreenshotGrabber() {
void ScreenshotGrabber::TakeScreenshot(gfx::NativeWindow window,
const gfx::Rect& rect,
ScreenshotCallback callback) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
last_screenshot_timestamp_ = base::TimeTicks::Now();
bool is_partial = true;
@@ -106,7 +106,7 @@ void ScreenshotGrabber::GrabWindowSnapshotAsyncCallback(
bool is_partial,
ScreenshotCallback callback,
scoped_refptr<base::RefCountedMemory> png_data) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
#if defined(USE_AURA)
cursor_hider_.reset();
diff --git a/chromium/ui/snapshot/snapshot_aura_unittest.cc b/chromium/ui/snapshot/snapshot_aura_unittest.cc
index 84854e5ec6f..20bcc42fe60 100644
--- a/chromium/ui/snapshot/snapshot_aura_unittest.cc
+++ b/chromium/ui/snapshot/snapshot_aura_unittest.cc
@@ -30,7 +30,6 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/gfx_paths.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/transform.h"
#include "ui/gl/gl_implementation.h"
diff --git a/chromium/ui/snapshot/snapshot_mac.mm b/chromium/ui/snapshot/snapshot_mac.mm
index fab9c68172e..5eb36bce2b1 100644
--- a/chromium/ui/snapshot/snapshot_mac.mm
+++ b/chromium/ui/snapshot/snapshot_mac.mm
@@ -15,9 +15,10 @@
namespace ui {
-bool GrabViewSnapshot(gfx::NativeView view,
+bool GrabViewSnapshot(gfx::NativeView native_view,
const gfx::Rect& snapshot_bounds,
gfx::Image* image) {
+ NSView* view = native_view.GetNativeNSView();
NSWindow* window = [view window];
NSScreen* screen = [[NSScreen screens] firstObject];
gfx::Rect screen_bounds = gfx::Rect(NSRectToCGRect([screen frame]));
@@ -49,17 +50,18 @@ bool GrabViewSnapshot(gfx::NativeView view,
if (CGImageGetWidth(windowSnapshot) <= 0)
return false;
- NSImage* nsImage =
- [[NSImage alloc] initWithCGImage:windowSnapshot size:NSZeroSize];
- *image = gfx::Image(nsImage);
+ *image =
+ gfx::Image([[[NSImage alloc] initWithCGImage:windowSnapshot
+ size:NSZeroSize] autorelease]);
return true;
}
-bool GrabWindowSnapshot(gfx::NativeWindow window,
+bool GrabWindowSnapshot(gfx::NativeWindow native_window,
const gfx::Rect& snapshot_bounds,
gfx::Image* image) {
// Make sure to grab the "window frame" view so we get current tab +
// tabstrip.
+ NSWindow* window = native_window.GetNativeNSWindow();
return GrabViewSnapshot([[window contentView] superview], snapshot_bounds,
image);
}
@@ -78,9 +80,10 @@ void GrabViewSnapshotAsync(gfx::NativeView view,
callback.Run(gfx::Image());
}
-void GrabWindowSnapshotAsync(gfx::NativeWindow window,
+void GrabWindowSnapshotAsync(gfx::NativeWindow native_window,
const gfx::Rect& source_rect,
const GrabWindowSnapshotAsyncCallback& callback) {
+ NSWindow* window = native_window.GetNativeNSWindow();
return GrabViewSnapshotAsync([[window contentView] superview], source_rect,
callback);
}
diff --git a/chromium/ui/strings/translations/ui_strings_am.xtb b/chromium/ui/strings/translations/ui_strings_am.xtb
index 83623cebe78..a40952008cb 100644
--- a/chromium/ui/strings/translations/ui_strings_am.xtb
+++ b/chromium/ui/strings/translations/ui_strings_am.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;ሁሉንም ምረጥ</translation>
+<translation id="1938451708255335766">የመስኮቱን የማሳያ ትፍገት ለማስተካከል መተግበሪያውን ዳግም ያስጀምሩት።</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1ቀ}one{#ቀ}other{#ቀ}}</translation>
<translation id="2148716181193084225">ዛሬ</translation>
<translation id="2168039046890040389">ወደላይ አንቀሳቅስ</translation>
<translation id="2190355936436201913">(ባዶ)</translation>
+<translation id="2192232475740621500">ዝቅተኛ ትፍገትን ተጠቀም</translation>
<translation id="219905428774326614">ማስጀመሪያ፣ ሁሉም መተግበሪያዎች</translation>
<translation id="2267918077332197517">ከዚህ ጣቢያ የሚመጡ ሁሉንም ማሳወቂያዎች አግድ</translation>
<translation id="2289052229480071835">በማያ ገጽዎ ላይ ያሉት የንክኪ ዒላማዎችን መታ ያድርጉ።</translation>
<translation id="2295140143284145483">የዳሰሳ ጥናት</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> ቴባ/ሰ</translation>
<translation id="24452542372838207">ማሳወቂያን ዘርጋ</translation>
+<translation id="2445449901874883781">ከፍተኛ ትፍገትን ተጠቀም</translation>
<translation id="2482878487686419369">ማስታወቂያዎች</translation>
<translation id="2497284189126895209">ሁሉም ፋይሎች</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">ዝቅዝቅ ቀስት</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ቀን}one{# ቀኖች}other{# ቀኖች}}</translation>
<translation id="335581015389089642">ንግግር</translation>
+<translation id="3479552764303398839">አሁን አይደለም</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ቀን ቀርቷል}one{# ቀኖች ቀርቷል}other{# ቀኖች ቀርተዋል}}</translation>
<translation id="3618849550573277856">«<ph name="LOOKUP_STRING" />»ን ፈልግ</translation>
<translation id="364720409959344976">የሚሰቀል ዓቃፊ ይምረጡ</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">ግራ ቀስት</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 ደቂቃ}one{# ደቂቃዎች}other{# ደቂቃዎች}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 ቀን እና }one{# ቀኖች እና }other{# ቀኖች እና }}</translation>
+<translation id="5895138241574237353">እንደገና ጀምር</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 ሰከንድ ቀርቷል}one{# ሰከንዶች ቀርቷል}other{# ሰከንዶች ቀርቷል}}</translation>
<translation id="5941711191222866238">አሳንስ</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 ሰዓት}one{# ሰዓቶች}other{# ሰዓቶች}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ar.xtb b/chromium/ui/strings/translations/ui_strings_ar.xtb
index 5e810ada0ea..80c5211bd48 100644
--- a/chromium/ui/strings/translations/ui_strings_ar.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ar.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">‏مفتاح Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">تح&amp;ديد الكلّ</translation>
+<translation id="1938451708255335766">لتعديل كثافة عرض النافذة، يمكنك إعادة تشغيل التطبيق.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{يوم واحد}zero{# يوم}two{يومان (#)}few{# أيام}many{# يومًا}other{# يوم}}</translation>
<translation id="2148716181193084225">اليوم</translation>
<translation id="2168039046890040389">صفحة إلى أعلى</translation>
<translation id="2190355936436201913">(فارغ)</translation>
+<translation id="2192232475740621500">استخدام كثافة منخفضة</translation>
<translation id="219905428774326614">‏Launcher، جميع التطبيقات</translation>
<translation id="2267918077332197517">حظر جميع الإشعارات الواردة من هذا الموقع</translation>
<translation id="2289052229480071835">انقر على أهداف اللمس على شاشتك.</translation>
<translation id="2295140143284145483">الاستطلاع</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> تيرابايت/ثانية</translation>
<translation id="24452542372838207">توسيع الإشعار</translation>
+<translation id="2445449901874883781">استخدام كثافة عالية</translation>
<translation id="2482878487686419369">الاشعارات</translation>
<translation id="2497284189126895209">الملفّات كلّها</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">مفتاح سهم إلى أسفل</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{يوم واحد}zero{# من الأيام}two{يومان (#)}few{# أيام}many{# يومًا}other{# من الأيام}}</translation>
<translation id="335581015389089642">الحديث</translation>
+<translation id="3479552764303398839">ليس الآن</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{يتبقى يوم واحد}zero{يتبقى عدد # من الأيام}two{يتبقى يومان (#)}few{يتبقى # أيام}many{يتبقى # يومًا}other{يتبقى # من الأيام}}</translation>
<translation id="3618849550573277856">البحث عن "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">حدد مجلدًا للتحميل</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">مفتاح سهم إلى اليسار</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{دقيقة واحدة}zero{# من الدقائق}two{دقيقتان (#)}few{# دقائق}many{# دقيقة}other{# من الدقائق}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{يوم واحد و }zero{# من الأيام و }two{يومان (#) و }few{# أيام و }many{# يومًا و }other{# من الأيام و }}</translation>
+<translation id="5895138241574237353">إعادة التشغيل</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{يتبقى ثانية واحدة}zero{يتبقى # من الثواني}two{يتبقى ثانيتان (#)}few{يتبقى # ثانية}many{يتبقى # ثانية}other{يتبقى # من الثواني}}</translation>
<translation id="5941711191222866238">تصغير</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{ساعة واحدة}zero{# من الساعات}two{ساعتان (#)}few{# ساعات}many{# ساعةً}other{# من الساعات}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bg.xtb b/chromium/ui/strings/translations/ui_strings_bg.xtb
index e1a2be58747..3e831578c26 100644
--- a/chromium/ui/strings/translations/ui_strings_bg.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bg.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">&amp;Избиране на всички</translation>
+<translation id="1938451708255335766">За да коригирате плътността за показване на прозорците, рестартирайте приложението.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 д.}other{# д.}}</translation>
<translation id="2148716181193084225">Днес</translation>
<translation id="2168039046890040389">Страница нагоре</translation>
<translation id="2190355936436201913">(празно)</translation>
+<translation id="2192232475740621500">Използване на ниска плътност</translation>
<translation id="219905428774326614">Стартов панел, всички приложения</translation>
<translation id="2267918077332197517">Блокиране на всички известия от този сайт</translation>
<translation id="2289052229480071835">Докоснете съответните цели на екрана.</translation>
<translation id="2295140143284145483">Анкета</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> ТБ/сек</translation>
<translation id="24452542372838207">Разгъване на известието</translation>
+<translation id="2445449901874883781">Използване на висока плътност</translation>
<translation id="2482878487686419369">Известия</translation>
<translation id="2497284189126895209">Всички файлове</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Стрелка надолу</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ден}other{# дни}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3479552764303398839">Не сега</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Остава 1 ден}other{Остават # дни}}</translation>
<translation id="3618849550573277856">Търсене на „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Избиране на папка за качване</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Стрелка наляво</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 мин}other{# мин}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 ден и }other{# дни и }}</translation>
+<translation id="5895138241574237353">Рестартиране</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Остава 1 секунда}other{Остават # секунди}}</translation>
<translation id="5941711191222866238">Намаляване</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 час}other{# часа}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_bn.xtb b/chromium/ui/strings/translations/ui_strings_bn.xtb
index 3ed795a58e5..295ac2ef66c 100644
--- a/chromium/ui/strings/translations/ui_strings_bn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_bn.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;সকল বেছে নিন</translation>
+<translation id="1938451708255335766">উইন্ডো স্ক্রিনের রেজোলিউশন অ্যাডজাস্ট করতে অ্যাপটি রিস্টার্ট করুন।</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{১ দিন}one{# দিন}other{# দিন}}</translation>
<translation id="2148716181193084225">আজ</translation>
<translation id="2168039046890040389">পৃষ্ঠা নিচে</translation>
<translation id="2190355936436201913">(খালি)</translation>
+<translation id="2192232475740621500">কম রেজোলিউশন ব্যবহার করুন</translation>
<translation id="219905428774326614">লঞ্চার, সমস্ত অ্যাপ</translation>
<translation id="2267918077332197517">এই সাইটের সমস্ত বিজ্ঞপ্তি ব্লক করুন</translation>
<translation id="2289052229480071835">আপনার স্ক্রীনে স্পর্শ লক্ষ্যগুলি আলতা চাপুন।</translation>
<translation id="2295140143284145483">সমীক্ষা</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">বিজ্ঞপ্তি প্রসারিত করুন</translation>
+<translation id="2445449901874883781">উচ্চ রেজোলিউশন ব্যবহার করুন</translation>
<translation id="2482878487686419369">বিজ্ঞপ্তিগুলি</translation>
<translation id="2497284189126895209">সকল ফাইল</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{১ দিন}one{# দিন}other{# দিন}}</translation>
<translation id="335581015389089642">স্পিচ</translation>
+<translation id="3479552764303398839">এখনই নয়</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{১ দিন বাকি}one{# দিন বাকি}other{# দিন বাকি}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” খুঁজে দেখুন</translation>
<translation id="364720409959344976">আপলোড করার জন্য ফোল্ডার বেছে নিন</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Left Arrow</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{১ মিনিট}one{# মিনিট}other{# মিনিট}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{১ দিন এবং }one{# দিন এবং }other{# দিন এবং }}</translation>
+<translation id="5895138241574237353">পুনর্সূচনা</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{১ সেকেন্ড বাকি}one{# সেকেন্ড বাকি}other{# সেকেন্ড বাকি}}</translation>
<translation id="5941711191222866238">ছোট করুন</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{১ ঘণ্টা}one{# ঘণ্টা}other{# ঘণ্টা}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ca.xtb b/chromium/ui/strings/translations/ui_strings_ca.xtb
index 9020f20262a..19f60bfd926 100644
--- a/chromium/ui/strings/translations/ui_strings_ca.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ca.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Selecciona-ho &amp;tot</translation>
+<translation id="1938451708255335766">Per ajustar la densitat de visualització de la finestra, reinicia l'aplicació.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}other{# d}}</translation>
<translation id="2148716181193084225">Avui</translation>
<translation id="2168039046890040389">Re Pàg</translation>
<translation id="2190355936436201913">(buit)</translation>
+<translation id="2192232475740621500">Utilitza una densitat baixa</translation>
<translation id="219905428774326614">Menú d'aplicacions, totes les aplicacions</translation>
<translation id="2267918077332197517">Bloqueja totes les notificacions d'aquest lloc web</translation>
<translation id="2289052229480071835">Toca els elements tàctils a la pantalla.</translation>
<translation id="2295140143284145483">Enquesta</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Desplega la notificació</translation>
+<translation id="2445449901874883781">Utilitza una densitat alta</translation>
<translation id="2482878487686419369">Notificacions</translation>
<translation id="2497284189126895209">Tots els fitxers</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Fletxa avall</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dia}other{# dies}}</translation>
<translation id="335581015389089642">Veu</translation>
+<translation id="3479552764303398839">Ara no</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dia restant}other{# dies restants}}</translation>
<translation id="3618849550573277856">Cerca "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Selecció d'una carpeta per penjar</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Fletxa esquerra</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dia i }other{# dies i }}</translation>
+<translation id="5895138241574237353">Reinicia</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 segon restant}other{# segons restants}}</translation>
<translation id="5941711191222866238">Minimitza</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hora}other{# hores}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_cs.xtb b/chromium/ui/strings/translations/ui_strings_cs.xtb
index fe6c504aa2d..883e5ab2a34 100644
--- a/chromium/ui/strings/translations/ui_strings_cs.xtb
+++ b/chromium/ui/strings/translations/ui_strings_cs.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Klávesa Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;Vybrat vše</translation>
+<translation id="1938451708255335766">Chcete-li upravit kompaktnost zobrazení okna, restartujte aplikaci.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}few{# d}many{# d}other{# d}}</translation>
<translation id="2148716181193084225">Dnes</translation>
<translation id="2168039046890040389">Klávesa PageUp</translation>
<translation id="2190355936436201913">(prázdné)</translation>
+<translation id="2192232475740621500">Použít nízkou hustotu</translation>
<translation id="219905428774326614">Spouštěč, všechny aplikace</translation>
<translation id="2267918077332197517">Blokovat všechna oznámení z tohoto webu</translation>
<translation id="2289052229480071835">Klepněte na cíle klepnutí na obrazovce.</translation>
<translation id="2295140143284145483">Průzkum</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Rozbalit oznámení</translation>
+<translation id="2445449901874883781">Použít vysokou hustotu</translation>
<translation id="2482878487686419369">Oznámení</translation>
<translation id="2497284189126895209">Všechny soubory</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Klávesa šipka dolů</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 den}few{# dny}many{# dne}other{# dnů}}</translation>
<translation id="335581015389089642">Řeč</translation>
+<translation id="3479552764303398839">Teď ne</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Zbývá 1 den}few{Zbývají # dny}many{Zbývá # dne}other{Zbývá # dnů}}</translation>
<translation id="3618849550573277856">Vyhledat „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Vyberte složku pro nahrávání</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Klávesa šipka vlevo</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}few{# min}many{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 den a }few{# dny a }many{# dne a }other{# dnů a }}</translation>
+<translation id="5895138241574237353">Restartovat</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Zbývá 1 sekunda}few{Zbývají # sekundy}many{Zbývá # sekundy}other{Zbývá # sekund}}</translation>
<translation id="5941711191222866238">Minimalizovat</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hodina}few{# hodiny}many{# hodiny}other{# hodin}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_da.xtb b/chromium/ui/strings/translations/ui_strings_da.xtb
index 847fd83e9f7..18f74d5fc1f 100644
--- a/chromium/ui/strings/translations/ui_strings_da.xtb
+++ b/chromium/ui/strings/translations/ui_strings_da.xtb
@@ -1,7 +1,7 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="da">
-<translation id="111910763555783249">Underretningsindstillinger</translation>
+<translation id="111910763555783249">Notifikationsindstillinger</translation>
<translation id="1127811143501539442">{DAYS,plural, =1{for 1 dag siden}one{for # dag siden}other{for # dage siden}}</translation>
<translation id="1156623771253174079">{SECONDS,plural, =1{For 1 minut siden}one{For # minut siden}other{For # minutter siden}}</translation>
<translation id="1169783199079129864">{MINUTES,plural, =1{1 min.}one{# min.}other{# min.}}</translation>
@@ -12,9 +12,9 @@
<translation id="1368832886055348810">Venstre til højre</translation>
<translation id="1383876407941801731">Søg</translation>
<translation id="1398853756734560583">Maksimér</translation>
-<translation id="1413622004203049571">Deaktiver underretninger fra <ph name="NOTIFIER_NAME" /></translation>
+<translation id="1413622004203049571">Deaktiver notifikationer fra <ph name="NOTIFIER_NAME" /></translation>
<translation id="1591184457164800433">{MINUTES,plural, =1{1 minut og }one{# minutter og }other{# minutter og }}</translation>
-<translation id="1643823602425662293">Underretning</translation>
+<translation id="1643823602425662293">Notifikation</translation>
<translation id="169515659049020177">Shift</translation>
<translation id="1710340000377843106">nu</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 minut}one{# minutter}other{# minutter}}</translation>
@@ -26,21 +26,24 @@
<translation id="1830179671306812954">{HOURS,plural, =1{1 time og }one{# timer og }other{# timer og }}</translation>
<translation id="1842960171412779397">vælg</translation>
<translation id="1859234291848436338">Skriveretning</translation>
-<translation id="1860796786778352021">Luk underretning</translation>
+<translation id="1860796786778352021">Luk notifikation</translation>
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Vælg &amp;alle</translation>
+<translation id="1938451708255335766">Genstart appen for at justere visningstætheden i vinduet.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}one{# d}other{# d}}</translation>
<translation id="2148716181193084225">I dag</translation>
<translation id="2168039046890040389">Side op</translation>
<translation id="2190355936436201913">(tom)</translation>
+<translation id="2192232475740621500">Brug lav tæthed</translation>
<translation id="219905428774326614">Starter. Alle apps</translation>
-<translation id="2267918077332197517">Bloker alle underretninger fra dette website</translation>
+<translation id="2267918077332197517">Bloker alle notifikationer fra dette website</translation>
<translation id="2289052229480071835">Tryk på de punkter på skærmen, der kan trykkes på.</translation>
<translation id="2295140143284145483">Undersøgelse</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/sek.</translation>
-<translation id="24452542372838207">Udvid underretning</translation>
-<translation id="2482878487686419369">Underretninger</translation>
+<translation id="24452542372838207">Udvid notifikation</translation>
+<translation id="2445449901874883781">Brug høj tæthed</translation>
+<translation id="2482878487686419369">Notifikationer</translation>
<translation id="2497284189126895209">Alle filer</translation>
<translation id="2515586267016047495">Alt</translation>
<translation id="2522350507219695259">Kalibreringen er fuldført</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Pil nedad</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}one{# dage}other{# dage}}</translation>
<translation id="335581015389089642">Tale</translation>
+<translation id="3479552764303398839">Ikke nu</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag tilbage}one{# dage tilbage}other{# dage tilbage}}</translation>
<translation id="3618849550573277856">Slå "<ph name="LOOKUP_STRING" />" op</translation>
<translation id="364720409959344976">Vælg den mappe, der skal uploades</translation>
@@ -79,7 +83,7 @@
<translation id="4289300219472526559">Start indtaling</translation>
<translation id="4316910396681052118">ALLE APPS</translation>
<translation id="4588090240171750605">Scroll til højre</translation>
-<translation id="4724120544754982507">Underretningscenter, <ph name="UNREAD_NOTIFICATION_COUNT" /> ulæste underretninger</translation>
+<translation id="4724120544754982507">Notifikationscenter, <ph name="UNREAD_NOTIFICATION_COUNT" /> ulæste notifikationer</translation>
<translation id="4730374152663651037">OFTE ANVENDT</translation>
<translation id="4788285488841504513">{MONTHS,plural, =1{Der er 1 måned tilbage}one{Der er # måned tilbage}other{Der er # måneder tilbage}}</translation>
<translation id="4841881773802181781">Indsættelse</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Venstrepil</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min.}one{# min.}other{# min.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dag og }one{# dage og }other{# dage og }}</translation>
+<translation id="5895138241574237353">Genstart</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 sekund tilbage}one{# sekunder tilbage}other{# sekunder tilbage}}</translation>
<translation id="5941711191222866238">Minimer</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 time}one{# timer}other{# timer}}</translation>
@@ -116,9 +121,9 @@
<translation id="6394627529324717982">Komma</translation>
<translation id="6397363302884558537">Stop indtaling</translation>
<translation id="6404817160109697034">{SECONDS,plural, =1{for 1 sek. siden}one{for # sek. siden}other{for # sek. siden}}</translation>
-<translation id="6430678249303439055">Bloker alle underretninger fra denne app</translation>
+<translation id="6430678249303439055">Bloker alle notifikationer fra denne app</translation>
<translation id="6483402905448010557">{SECONDS,plural, =1{For 1 sekund siden}one{For # sekund siden}other{For # sekunder siden}}</translation>
-<translation id="654149438358937226">Bloker alle underretninger</translation>
+<translation id="654149438358937226">Bloker alle notifikationer</translation>
<translation id="6567071839949112727">klik på overordnet element</translation>
<translation id="6612467943526193239">Tryk på Esc for at afslutte kalibreringen.</translation>
<translation id="6620110761915583480">Gem fil</translation>
@@ -179,7 +184,7 @@
<translation id="9002566407876343676">åbn</translation>
<translation id="9038489124413477075">Unavngiven mappe</translation>
<translation id="9044832324875206639">{SECONDS,plural, =1{1 sek.}one{# sek.}other{# sek.}}</translation>
-<translation id="9059834730836941392">Skjul underretning</translation>
+<translation id="9059834730836941392">Skjul notifikation</translation>
<translation id="9150735707954472829">Fane</translation>
<translation id="9161053988251441839">FORESLÅEDE APPS</translation>
<translation id="9170848237812810038">&amp;Fortryd</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_de.xtb b/chromium/ui/strings/translations/ui_strings_de.xtb
index 47df84f9805..1eee1ee7513 100644
--- a/chromium/ui/strings/translations/ui_strings_de.xtb
+++ b/chromium/ui/strings/translations/ui_strings_de.xtb
@@ -19,7 +19,7 @@
<translation id="1710340000377843106">jetzt</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 Minute}other{# Minuten}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> B</translation>
-<translation id="1801827354178857021">Zeitraum</translation>
+<translation id="1801827354178857021">Punkt</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{1 Monat}other{# Monate}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> MB/s</translation>
<translation id="1812519734428420144">Bewertung <ph name="RATING_SCORE" /></translation>
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Einfg</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;Alles auswählen</translation>
+<translation id="1938451708255335766">Wenn Sie die Anzeigedichte der App-Fenster anpassen möchten, starten Sie die App neu.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 Tag}other{# Tage}}</translation>
<translation id="2148716181193084225">Heute</translation>
<translation id="2168039046890040389">Nach oben</translation>
<translation id="2190355936436201913">(leer)</translation>
+<translation id="2192232475740621500">Niedrige Anzeigedichte verwenden</translation>
<translation id="219905428774326614">Launcher, alle Apps</translation>
<translation id="2267918077332197517">Alle Benachrichtigungen von dieser Website blockieren</translation>
<translation id="2289052229480071835">Tippen Sie auf die Zielelemente auf dem Bildschirm.</translation>
<translation id="2295140143284145483">Umfrage</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Benachrichtigung erweitern</translation>
+<translation id="2445449901874883781">Hohe Anzeigedichte verwenden</translation>
<translation id="2482878487686419369">Benachrichtigungen</translation>
<translation id="2497284189126895209">Alle Dateien</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Abwärtspfeil</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 Tag}other{# Tage}}</translation>
<translation id="335581015389089642">Sprachausgabe</translation>
+<translation id="3479552764303398839">Jetzt nicht</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 Tag übrig}other{# Tage übrig}}</translation>
<translation id="3618849550573277856">"<ph name="LOOKUP_STRING" />" nachschlagen</translation>
<translation id="364720409959344976">Ordner zum Hochladen auswählen</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Linkspfeil</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 Min.}other{# Min.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 Tag und }other{# Tage und }}</translation>
+<translation id="5895138241574237353">Neu starten</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 Sekunde übrig}other{# Sekunden übrig}}</translation>
<translation id="5941711191222866238">Verkleinern</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 Stunde}other{# Stunden}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_el.xtb b/chromium/ui/strings/translations/ui_strings_el.xtb
index f1cca4202c7..1084c065de7 100644
--- a/chromium/ui/strings/translations/ui_strings_el.xtb
+++ b/chromium/ui/strings/translations/ui_strings_el.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Επιλογή όλ&amp;ων</translation>
+<translation id="1938451708255335766">Για να προσαρμόσετε την πυκνότητα της προβολής του παραθύρου, επανεκκινήστε την εφαρμογή.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1ημ.}other{#ημ.}}</translation>
<translation id="2148716181193084225">Σήμερα</translation>
<translation id="2168039046890040389">Προηγούμενη σελίδα</translation>
<translation id="2190355936436201913">(κενό)</translation>
+<translation id="2192232475740621500">Χρήση χαμηλής πυκνότητας</translation>
<translation id="219905428774326614">Εφαρμογή εκκίνησης, όλες οι εφαρμογές</translation>
<translation id="2267918077332197517">Αποκλεισμός όλων των ειδοποιήσεων από αυτόν τον ιστότοπο</translation>
<translation id="2289052229480071835">Πατήστε τους στόχους αφής στην οθόνη σας.</translation>
<translation id="2295140143284145483">Έρευνα</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Ανάπτυξη ειδοποίησης</translation>
+<translation id="2445449901874883781">Χρήση υψηλής πυκνότητας</translation>
<translation id="2482878487686419369">Ειδοποιήσεις</translation>
<translation id="2497284189126895209">Όλα τα αρχεία</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Κάτω βέλος</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ημέρα}other{# ημέρες}}</translation>
<translation id="335581015389089642">Ομιλία</translation>
+<translation id="3479552764303398839">Όχι τώρα</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Απομένει 1 ημέρα}other{Απομένουν # ημέρες}}</translation>
<translation id="3618849550573277856">Αναζήτηση "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Επιλέξτε φάκελο για μεταφόρτωση</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Αριστερό βέλος</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 λεπτό}other{# λεπτά}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 ημέρα και }other{# ημέρες και }}</translation>
+<translation id="5895138241574237353">Επανεκκίνηση</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Απομένει 1 δευτερόλεπτο}other{Απομένουν # δευτερόλεπτα}}</translation>
<translation id="5941711191222866238">Ελαχιστοποίηση</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 ώρα}other{# ώρες}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_en-GB.xtb b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
index cda9340e79c..477460d7580 100644
--- a/chromium/ui/strings/translations/ui_strings_en-GB.xtb
+++ b/chromium/ui/strings/translations/ui_strings_en-GB.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Select &amp;all</translation>
+<translation id="1938451708255335766">To adjust the window display density, restart the app.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1d}other{#d}}</translation>
<translation id="2148716181193084225">Today</translation>
<translation id="2168039046890040389">Page Up</translation>
<translation id="2190355936436201913">(empty)</translation>
+<translation id="2192232475740621500">Use low density</translation>
<translation id="219905428774326614">Launcher, all apps</translation>
<translation id="2267918077332197517">Block all notifications from this site</translation>
<translation id="2289052229480071835">Tap the touch targets on your screen.</translation>
<translation id="2295140143284145483">Survey</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Expand notification</translation>
+<translation id="2445449901874883781">Use high density</translation>
<translation id="2482878487686419369">Notifications</translation>
<translation id="2497284189126895209">All Files</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 day}other{# days}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3479552764303398839">Not now</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 day left}other{# days left}}</translation>
<translation id="3618849550573277856">Look Up “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Select Folder to Upload</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Left Arrow</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# mins}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 day and }other{# days and }}</translation>
+<translation id="5895138241574237353">Restart</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 second left}other{# seconds left}}</translation>
<translation id="5941711191222866238">Minimise</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hour}other{# hours}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es-419.xtb b/chromium/ui/strings/translations/ui_strings_es-419.xtb
index 2ceb6b6d7b3..17fbbc33bb8 100644
--- a/chromium/ui/strings/translations/ui_strings_es-419.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es-419.xtb
@@ -19,7 +19,7 @@
<translation id="1710340000377843106">ahora</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 minuto}other{# minutos}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> B</translation>
-<translation id="1801827354178857021">Período</translation>
+<translation id="1801827354178857021">Punto</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{1 mes}other{# meses}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> de MB</translation>
<translation id="1812519734428420144">Calificación por estrellas <ph name="RATING_SCORE" /></translation>
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Insert</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Seleccionar &amp;todo</translation>
+<translation id="1938451708255335766">Para ajustar la densidad de la visualización de la ventana, reinicia la app.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}other{# d}}</translation>
<translation id="2148716181193084225">Hoy</translation>
<translation id="2168039046890040389">Retroceder página</translation>
<translation id="2190355936436201913">(vacío)</translation>
+<translation id="2192232475740621500">Usar la densidad baja</translation>
<translation id="219905428774326614">Launcher, todas las apps</translation>
<translation id="2267918077332197517">No permitir las notificaciones de este sitio</translation>
<translation id="2289052229480071835">Presiona los objetivos táctiles en tu pantalla.</translation>
<translation id="2295140143284145483">Encuesta</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Expandir notificación</translation>
+<translation id="2445449901874883781">Usar la densidad alta</translation>
<translation id="2482878487686419369">Notificaciones</translation>
<translation id="2497284189126895209">Todos los archivos</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Flecha abajo</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 día}other{# días}}</translation>
<translation id="335581015389089642">Voz</translation>
+<translation id="3479552764303398839">Ahora no</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 día.}other{Faltan # días.}}</translation>
<translation id="3618849550573277856">Buscar "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Seleccionar carpeta para cargar</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Flecha izquierda</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 día y }other{# días y }}</translation>
+<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Falta 1 segundo.}other{Faltan # segundos.}}</translation>
<translation id="5941711191222866238">Minimizar</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hora}other{# horas}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_es.xtb b/chromium/ui/strings/translations/ui_strings_es.xtb
index ad68eca086e..f814044cb0a 100644
--- a/chromium/ui/strings/translations/ui_strings_es.xtb
+++ b/chromium/ui/strings/translations/ui_strings_es.xtb
@@ -19,7 +19,7 @@
<translation id="1710340000377843106">ahora</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 minuto}other{# minutos}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> B</translation>
-<translation id="1801827354178857021">Periodo</translation>
+<translation id="1801827354178857021">Punto</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{1 mes}other{# meses}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> MB/s</translation>
<translation id="1812519734428420144">Valoración por estrellas <ph name="RATING_SCORE" /></translation>
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Insert</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Seleccionar &amp;todo</translation>
+<translation id="1938451708255335766">Para modificar la densidad de pantalla de la ventana, reinicia la aplicación.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 día}other{# días}}</translation>
<translation id="2148716181193084225">Hoy</translation>
<translation id="2168039046890040389">Retroceder página</translation>
<translation id="2190355936436201913">(vacío)</translation>
+<translation id="2192232475740621500">Usar baja densidad</translation>
<translation id="219905428774326614">Menú de aplicaciones, todas las aplicaciones</translation>
<translation id="2267918077332197517">Bloquear todas las notificaciones de este sitio web</translation>
<translation id="2289052229480071835">Toca los elementos táctiles en la pantalla.</translation>
<translation id="2295140143284145483">Encuesta</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Mostrar notificación</translation>
+<translation id="2445449901874883781">Usar alta densidad</translation>
<translation id="2482878487686419369">Notificaciones</translation>
<translation id="2497284189126895209">Todos los archivos</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Flecha abajo</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 día}other{# días}}</translation>
<translation id="335581015389089642">Voz</translation>
+<translation id="3479552764303398839">Ahora no</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Queda 1 día}other{Quedan # días}}</translation>
<translation id="3618849550573277856">Buscar <ph name="LOOKUP_STRING" /></translation>
<translation id="364720409959344976">Seleccionar una carpeta para subirla</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Flecha izquierda</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 día y }other{# días y }}</translation>
+<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Queda 1 segundo}other{Quedan # segundos}}</translation>
<translation id="5941711191222866238">Minimizar</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hora}other{# horas}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_et.xtb b/chromium/ui/strings/translations/ui_strings_et.xtb
index 154405d6628..3b99834f71b 100644
--- a/chromium/ui/strings/translations/ui_strings_et.xtb
+++ b/chromium/ui/strings/translations/ui_strings_et.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Vali &amp;kõik</translation>
+<translation id="1938451708255335766">Aknakuva tiheduse kohandamiseks taaskäivitage rakendus.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1p}other{#p}}</translation>
<translation id="2148716181193084225">Täna</translation>
<translation id="2168039046890040389">Lehekülje üles</translation>
<translation id="2190355936436201913">(tühi)</translation>
+<translation id="2192232475740621500">Kasuta madalat tihedust</translation>
<translation id="219905428774326614">Käivitaja, kõik rakendused</translation>
<translation id="2267918077332197517">Blokeeri kõik märguanded sellelt saidilt</translation>
<translation id="2289052229480071835">Puudutage ekraanil puutesihtmärke.</translation>
<translation id="2295140143284145483">Küsitlus</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Laienda märguannet</translation>
+<translation id="2445449901874883781">Kasuta kõrget tihedust</translation>
<translation id="2482878487686419369">Märguanded</translation>
<translation id="2497284189126895209">Kõik failid</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Allanool</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 päev}other{# päeva}}</translation>
<translation id="335581015389089642">Kõne</translation>
+<translation id="3479552764303398839">Mitte praegu</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 päev on jäänud}other{# päeva on jäänud}}</translation>
<translation id="3618849550573277856">Otsi terminit „<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Kausta valimine üleslaadimiseks</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Vasaknool</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 päev ja }other{# päeva ja }}</translation>
+<translation id="5895138241574237353">Taaskäivitamine</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 sekund on jäänud}other{# sekundit on jäänud}}</translation>
<translation id="5941711191222866238">Minimeeri</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 tund}other{# tundi}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fa.xtb b/chromium/ui/strings/translations/ui_strings_fa.xtb
index 38102551c88..e0cd88867c8 100644
--- a/chromium/ui/strings/translations/ui_strings_fa.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fa.xtb
@@ -19,7 +19,7 @@
<translation id="1710340000377843106">اکنون</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{۱ دقیقه}one{# دقیقه}other{# دقیقه}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> بایت</translation>
-<translation id="1801827354178857021">دوره زمانی</translation>
+<translation id="1801827354178857021">نقطه</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{۱ ماه}one{# ماه}other{# ماه}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> مگابایت/ثانیه</translation>
<translation id="1812519734428420144">رتبه‌بندی ستاره‌ای <ph name="RATING_SCORE" /></translation>
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />٪</translation>
<translation id="1901303067676059328">انتخاب &amp;همه</translation>
+<translation id="1938451708255335766">برای تنظیم تراکم نمایشگر پنجره، برنامه را بازراه‌اندازی کنید.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{۱ روز}one{# روز}other{# روز}}</translation>
<translation id="2148716181193084225">امروز</translation>
<translation id="2168039046890040389">صفحه بالا</translation>
<translation id="2190355936436201913">(خالی)</translation>
+<translation id="2192232475740621500">استفاده از تراکم پایین</translation>
<translation id="219905428774326614">راه‌انداز، همه برنامه‌ها</translation>
<translation id="2267918077332197517">مسدود کردن همه اعلان‌های این سایت</translation>
<translation id="2289052229480071835">روی اهداف لمسی در صفحه‌تان ضربه بزنید.</translation>
<translation id="2295140143284145483">نظرسنجی</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> ترابایت/ثانیه</translation>
<translation id="24452542372838207">بزرگ کردن اعلان</translation>
+<translation id="2445449901874883781">استفاده از تراکم بالا</translation>
<translation id="2482878487686419369">اعلان‌ها</translation>
<translation id="2497284189126895209">همه فایل‌ها</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">پیکان پایین</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{۱ روز}one{# روز}other{# روز}}</translation>
<translation id="335581015389089642">صدا</translation>
+<translation id="3479552764303398839">اکنون نه</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{۱ روز باقی مانده است}one{# روز باقی مانده است}other{# روز باقی مانده است}}</translation>
<translation id="3618849550573277856">جستجوی «<ph name="LOOKUP_STRING" />»</translation>
<translation id="364720409959344976">انتخاب پوشه برای بارگذاری</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">پیکان چپ</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{۱ دقیقه}one{# دقیقه}other{# دقیقه}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{۱ روز و }one{# روز و }other{# روز و }}</translation>
+<translation id="5895138241574237353">راه‌اندازی مجدد</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{۱ ثانیه باقی مانده است}one{# ثانیه باقی مانده است}other{# ثانیه باقی مانده است}}</translation>
<translation id="5941711191222866238">کوچک کردن</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{۱ ساعت}one{# ساعت}other{# ساعت}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fi.xtb b/chromium/ui/strings/translations/ui_strings_fi.xtb
index 3deafdc6e5b..c328e1808d5 100644
--- a/chromium/ui/strings/translations/ui_strings_fi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fi.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Valitse &amp;kaikki</translation>
+<translation id="1938451708255335766">Muuta ikkunoiden näyttötiheyttä käynnistämällä sovellus uudelleen.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 p}other{# p}}</translation>
<translation id="2148716181193084225">Tänään</translation>
<translation id="2168039046890040389">Sivu ylös</translation>
<translation id="2190355936436201913">(tyhjä)</translation>
+<translation id="2192232475740621500">Matala tiheys</translation>
<translation id="219905428774326614">Käynnistysohjelma, kaikki sovellukset</translation>
<translation id="2267918077332197517">Estä kaikki tämän sivuston ilmoitukset</translation>
<translation id="2289052229480071835">Napauta näytölläsi olevia kosketettavia kohteita.</translation>
<translation id="2295140143284145483">Kysely</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> Tt/s</translation>
<translation id="24452542372838207">Laajenna ilmoitus</translation>
+<translation id="2445449901874883781">Korkea tiheys</translation>
<translation id="2482878487686419369">Ilmoitukset</translation>
<translation id="2497284189126895209">Kaikki tiedostot</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Nuoli al.</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 päivä}other{# päivää}}</translation>
<translation id="335581015389089642">Puhe</translation>
+<translation id="3479552764303398839">Ei nyt</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 päivä jäljellä}other{# päivää jäljellä}}</translation>
<translation id="3618849550573277856">Hae ”<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Valitse lähetettävä kansio</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Nuoli vas.</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 päivä ja }other{# päivää ja }}</translation>
+<translation id="5895138241574237353">Käynnistä uudelleen</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 sekunti jäljellä}other{# sekuntia jäljellä}}</translation>
<translation id="5941711191222866238">Pienennä</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 tunti}other{# tuntia}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fil.xtb b/chromium/ui/strings/translations/ui_strings_fil.xtb
index 14edf08b529..21aa704068f 100644
--- a/chromium/ui/strings/translations/ui_strings_fil.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fil.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Piliin ang &amp;lahat</translation>
+<translation id="1938451708255335766">Para i-adjust ang density ng display ng window, i-restart ang app.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 araw}one{# araw}other{# na araw}}</translation>
<translation id="2148716181193084225">Ngayon</translation>
<translation id="2168039046890040389">Pataas</translation>
<translation id="2190355936436201913">(walang laman)</translation>
+<translation id="2192232475740621500">Gumamit ng mababang density</translation>
<translation id="219905428774326614">Launcher, lahat ng app</translation>
<translation id="2267918077332197517">I-block ang lahat ng notification mula sa site na ito</translation>
<translation id="2289052229480071835">I-tap ang mga target sa pagpindot sa iyong screen.</translation>
<translation id="2295140143284145483">Survey</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> (na) TB/s</translation>
<translation id="24452542372838207">Palawakin ang notification</translation>
+<translation id="2445449901874883781">Gumamit ng mataas na density</translation>
<translation id="2482878487686419369">Mga Abiso</translation>
<translation id="2497284189126895209">Lahat ng Mga File</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 araw}one{# araw}other{# na araw}}</translation>
<translation id="335581015389089642">Pananalita</translation>
+<translation id="3479552764303398839">Hindi ngayon</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 araw na lang ang natitira}one{# araw na lang ang natitira}other{# na araw na lang ang natitira}}</translation>
<translation id="3618849550573277856">Hanapin ang “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Pumili ng Folder na I-a-upload</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">KAliwang Arrow</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 minuto}one{# minuto}other{# na minuto}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 araw at }one{# araw at }other{# na araw at }}</translation>
+<translation id="5895138241574237353">I-restart</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 segundo na lang ang natitira}one{# segundo na lang ang natitira}other{# na segundo na lang ang natitira}}</translation>
<translation id="5941711191222866238">Minimize</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 oras}one{# oras}other{# na oras}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_fr.xtb b/chromium/ui/strings/translations/ui_strings_fr.xtb
index b5dfcea2e3e..07e461c0569 100644
--- a/chromium/ui/strings/translations/ui_strings_fr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_fr.xtb
@@ -19,7 +19,7 @@
<translation id="1710340000377843106">maintenant</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 minute}one{# minute}other{# minutes}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> o</translation>
-<translation id="1801827354178857021">Période</translation>
+<translation id="1801827354178857021">Point</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{1 mois}one{# mois}other{# mois}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> Mo/s</translation>
<translation id="1812519734428420144">Note : <ph name="RATING_SCORE" /></translation>
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Insér.</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;Tout sélectionner</translation>
+<translation id="1938451708255335766">Pour ajuster la densité d'affichage des fenêtres, redémarrez l'application.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 j}one{# j}other{# j}}</translation>
<translation id="2148716181193084225">Aujourd'hui</translation>
<translation id="2168039046890040389">Page précédente</translation>
<translation id="2190355936436201913">(vide)</translation>
+<translation id="2192232475740621500">Utiliser une densité faible</translation>
<translation id="219905428774326614">Lanceur d'applications, toutes les applications</translation>
<translation id="2267918077332197517">Bloquer toutes les notifications de ce site</translation>
<translation id="2289052229480071835">Appuyez sur les cibles tactiles affichées à l'écran.</translation>
<translation id="2295140143284145483">Enquête</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> To/s</translation>
<translation id="24452542372838207">Développer la notification</translation>
+<translation id="2445449901874883781">Utiliser une densité élevée</translation>
<translation id="2482878487686419369">Notifications</translation>
<translation id="2497284189126895209">Tous les fichiers</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Bas</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 jour}one{# jour}other{# jours}}</translation>
<translation id="335581015389089642">Voix</translation>
+<translation id="3479552764303398839">Pas maintenant</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 jour restant}one{# jour restant}other{# jours restants}}</translation>
<translation id="3618849550573277856">Rechercher "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Sélectionner le dossier d'importation</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Gauche</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}one{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 jour et }one{# jour et }other{# jours et }}</translation>
+<translation id="5895138241574237353">Redémarrer</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 seconde restante}one{# seconde restante}other{# secondes restantes}}</translation>
<translation id="5941711191222866238">Réduire</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 heure}one{# heure}other{# heures}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_gu.xtb b/chromium/ui/strings/translations/ui_strings_gu.xtb
index d1acf345a72..18b45cf4ebd 100644
--- a/chromium/ui/strings/translations/ui_strings_gu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_gu.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;બધા પસંદ કરો</translation>
+<translation id="1938451708255335766">વિંડો ડિસ્પ્લે ઘનતાને ગોઠવવા માટે, ઍપને ફરીથી શરૂ કરો.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 દિ}one{# દિ}other{# દિ}}</translation>
<translation id="2148716181193084225">આજે</translation>
<translation id="2168039046890040389">પૃષ્ઠ ઉપર</translation>
<translation id="2190355936436201913">(ખાલી)</translation>
+<translation id="2192232475740621500">ઓછી ઘનતાનો ઉપયોગ કરો</translation>
<translation id="219905428774326614">લૉન્ચર, બધી ઍપ</translation>
<translation id="2267918077332197517">આ સાઇટના બધા નોટિફિકેશનો અવરોધિત કરો</translation>
<translation id="2289052229480071835">તમારી સ્ક્રીન પર ટચ કરવાના લક્ષ્યોને ટૅપ કરો.</translation>
<translation id="2295140143284145483">સર્વેક્ષણ</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">નોટિફિકેશન વિસ્તૃત કરો</translation>
+<translation id="2445449901874883781">વધારે ઘનતાનો ઉપયોગ કરો</translation>
<translation id="2482878487686419369">સૂચનાઓ</translation>
<translation id="2497284189126895209">બધી ફાઇલો</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">નીચલો એરો</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 દિવસ}one{# દિવસ}other{# દિવસ}}</translation>
<translation id="335581015389089642">ભાષા</translation>
+<translation id="3479552764303398839">હમણાં નહીં</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 દિવસ બાકી}one{# દિવસ બાકી}other{# દિવસ બાકી}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” શોધો</translation>
<translation id="364720409959344976">અપલોડ કરવા માટે ફોલ્ડર પસંદ કરો</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">ડાબો એરો</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 મિનિટ}one{# મિનિટ}other{# મિનિટ}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 દિવસ અને }one{# દિવસ અને }other{# દિવસ અને }}</translation>
+<translation id="5895138241574237353">પુનઃપ્રારંભ કરો</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 સેકન્ડ બાકી}one{# સેકન્ડ બાકી}other{# સેકન્ડ બાકી}}</translation>
<translation id="5941711191222866238">નાનું કરો</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 કલાક}one{# કલાક}other{# કલાક}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hi.xtb b/chromium/ui/strings/translations/ui_strings_hi.xtb
index a8d86000ed5..b809c445c23 100644
--- a/chromium/ui/strings/translations/ui_strings_hi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hi.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;सभी को चुनें</translation>
+<translation id="1938451708255335766">विंडो डिसप्ले की सघनता में बदलाव करने के लिए, ऐप्लिकेशन को रीस्टार्ट करें.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1d}one{#d}other{#d}}</translation>
<translation id="2148716181193084225">आज</translation>
<translation id="2168039046890040389">पेज ऊपर</translation>
<translation id="2190355936436201913">(खाली)</translation>
+<translation id="2192232475740621500">कम सघनता का इस्तेमाल करें</translation>
<translation id="219905428774326614">लॉन्चर, सभी ऐप्लिकेशन</translation>
<translation id="2267918077332197517">इस साइट से सभी सूचनाएं रोकें</translation>
<translation id="2289052229480071835">अपनी स्क्रीन पर स्पर्श लक्ष्य पर टैप करें.</translation>
<translation id="2295140143284145483">सर्वे</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">सूचना को विस्तृत करें</translation>
+<translation id="2445449901874883781">ज़्यादा सघनता का इस्तेमाल करें</translation>
<translation id="2482878487686419369">अधिसूचनाएं</translation>
<translation id="2497284189126895209">सभी फ़ाइलें</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">नीचे तीर</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 दिन}one{# दिन}other{# दिन}}</translation>
<translation id="335581015389089642">बोली</translation>
+<translation id="3479552764303398839">अभी नहीं</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 दिन शेष}one{# दिन शेष}other{# दिन शेष}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” को खोजें</translation>
<translation id="364720409959344976">अपलोड करने के लिए फ़ोल्‍डर चुनें</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">बायां तीर</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 मिनट}one{# मिनट}other{# मिनट}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 दिन और }one{# दिन और }other{# दिन और }}</translation>
+<translation id="5895138241574237353">पुन: प्रारंभ करें</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 सेकंड शेष}one{# सेकंड शेष}other{# सेकंड शेष}}</translation>
<translation id="5941711191222866238">छोटा करें</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 घंटा}one{# घंटे}other{# घंटे}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hr.xtb b/chromium/ui/strings/translations/ui_strings_hr.xtb
index 5447710ad23..6811f587e9a 100644
--- a/chromium/ui/strings/translations/ui_strings_hr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hr.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Odaberi &amp;sve</translation>
+<translation id="1938451708255335766">Da biste prilagodili gustoću prikaza prozora, ponovo pokrenite aplikaciju.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}one{# d}few{# d}other{# d}}</translation>
<translation id="2148716181193084225">Danas</translation>
<translation id="2168039046890040389">Stranica prema gore</translation>
<translation id="2190355936436201913">(prazno)</translation>
+<translation id="2192232475740621500">Koristi nisku gustoću</translation>
<translation id="219905428774326614">Pokretač, sve aplikacije</translation>
<translation id="2267918077332197517">Blokiraj sve obavijesti te web-lokacije</translation>
<translation id="2289052229480071835">Dodirnite ciljeve dodira na zaslonu.</translation>
<translation id="2295140143284145483">Anketa</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Proširi obavijest</translation>
+<translation id="2445449901874883781">Koristi visoku gustoću</translation>
<translation id="2482878487686419369">Obavijesti</translation>
<translation id="2497284189126895209">Sve datoteke</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Strelica dolje</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dan}one{# dan}few{# dana}other{# dana}}</translation>
<translation id="335581015389089642">Govor</translation>
+<translation id="3479552764303398839">Ne sada</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Još 1 dan}one{Još # dan}few{Još # dana}other{Još # dana}}</translation>
<translation id="3618849550573277856">Potraži "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Odabir mape za prijenos</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Strelica lijevo</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}one{# min}few{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dan i }one{# dan i }few{# dana i }other{# dana i }}</translation>
+<translation id="5895138241574237353">Ponovno pokreni</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Još 1 sekunda}one{Još # sekunda}few{Još # sekunde}other{Još # sekundi}}</translation>
<translation id="5941711191222866238">Minimiziraj</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 sat}one{# sat}few{# sata}other{# sati}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_hu.xtb b/chromium/ui/strings/translations/ui_strings_hu.xtb
index 7e0643cf914..41c0a7b397f 100644
--- a/chromium/ui/strings/translations/ui_strings_hu.xtb
+++ b/chromium/ui/strings/translations/ui_strings_hu.xtb
@@ -19,7 +19,7 @@
<translation id="1710340000377843106">most</translation>
<translation id="1752946267035950200">{MINUTES,plural, =1{1 perc}other{# perc}}</translation>
<translation id="1761785978543082658"><ph name="QUANTITY" /> bájt</translation>
-<translation id="1801827354178857021">Időszak</translation>
+<translation id="1801827354178857021">Pont</translation>
<translation id="1803208670097017349">{MONTHS,plural, =1{1 hónap}other{# hónap}}</translation>
<translation id="1809410197924942083"><ph name="QUANTITY" /> MB/s</translation>
<translation id="1812519734428420144"><ph name="RATING_SCORE" /> csillagos értékelés</translation>
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Össz&amp;es kiválasztása</translation>
+<translation id="1938451708255335766">Az ablak megjelenítési sűrűségének módosításához indítsa újra az alkalmazást.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 n}other{# n}}</translation>
<translation id="2148716181193084225">Ma</translation>
<translation id="2168039046890040389">Oldal fel</translation>
<translation id="2190355936436201913">(üres)</translation>
+<translation id="2192232475740621500">Alacsony sűrűség használata</translation>
<translation id="219905428774326614">Indító, minden alkalmazás</translation>
<translation id="2267918077332197517">Minden értesítés letiltása erről a webhelyről</translation>
<translation id="2289052229480071835">Koppintson a képernyőn az érintési célpontokra.</translation>
<translation id="2295140143284145483">Felmérés</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Értesítés kibontása</translation>
+<translation id="2445449901874883781">Magas sűrűség használata</translation>
<translation id="2482878487686419369">Értesítések</translation>
<translation id="2497284189126895209">Minden fájl</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Lefelé nyíl</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 nap}other{# nap}}</translation>
<translation id="335581015389089642">Beszéd</translation>
+<translation id="3479552764303398839">Ne most</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 nap van hátra}other{# nap van hátra}}</translation>
<translation id="3618849550573277856">A(z) „<ph name="LOOKUP_STRING" />” keresése</translation>
<translation id="364720409959344976">Mappa kiválasztása a feltöltéshez</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Bal nyíl</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 perc}other{# perc}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 nap és }other{# nap és }}</translation>
+<translation id="5895138241574237353">Újraindítás</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 másodperc van hátra}other{# másodperc van hátra}}</translation>
<translation id="5941711191222866238">Kicsinyítés</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 óra}other{# óra}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_id.xtb b/chromium/ui/strings/translations/ui_strings_id.xtb
index c5349e33811..8a35010329b 100644
--- a/chromium/ui/strings/translations/ui_strings_id.xtb
+++ b/chromium/ui/strings/translations/ui_strings_id.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Pilih semu&amp;a</translation>
+<translation id="1938451708255335766">Untuk menyesuaikan kepadatan tampilan jendela, mulai ulang aplikasi.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1h}other{#h}}</translation>
<translation id="2148716181193084225">Hari ini</translation>
<translation id="2168039046890040389">Page Up</translation>
<translation id="2190355936436201913">(kosong)</translation>
+<translation id="2192232475740621500">Gunakan kepadatan rendah</translation>
<translation id="219905428774326614">Peluncur, semua aplikasi</translation>
<translation id="2267918077332197517">Blokir semua notifikasi dari situs ini</translation>
<translation id="2289052229480071835">Tap target sentuh di layar.</translation>
<translation id="2295140143284145483">Survei</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/dtk</translation>
<translation id="24452542372838207">Luaskan notifikasi</translation>
+<translation id="2445449901874883781">Gunakan kepadatan tinggi</translation>
<translation id="2482878487686419369">Notifikasi</translation>
<translation id="2497284189126895209">Semua Jenis File</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Panah Bawah</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 hari}other{# hari}}</translation>
<translation id="335581015389089642">Ucapan</translation>
+<translation id="3479552764303398839">Jangan sekarang</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation>
<translation id="3618849550573277856">Cari "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Pilih Folder untuk Diunggah</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Panah Kiri</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 mnt}other{# mnt}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 hari dan }other{# hari dan }}</translation>
+<translation id="5895138241574237353">Mulai Ulang</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 detik lagi}other{# detik lagi}}</translation>
<translation id="5941711191222866238">Perkecil</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 jam}other{# jam}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_it.xtb b/chromium/ui/strings/translations/ui_strings_it.xtb
index e6b55ba6964..89c47a9870f 100644
--- a/chromium/ui/strings/translations/ui_strings_it.xtb
+++ b/chromium/ui/strings/translations/ui_strings_it.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Seleziona &amp;tutto</translation>
+<translation id="1938451708255335766">Riavvia l'app per regolare la densità della visualizzazione della finestra.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 g}other{# gg}}</translation>
<translation id="2148716181193084225">Oggi</translation>
<translation id="2168039046890040389">Pagina su</translation>
<translation id="2190355936436201913">(vuoto)</translation>
+<translation id="2192232475740621500">Usa densità bassa</translation>
<translation id="219905428774326614">Avvio applicazioni, tutte le app</translation>
<translation id="2267918077332197517">Blocca tutte le notifiche da questo sito</translation>
<translation id="2289052229480071835">Tocca i touch target sul tuo schermo.</translation>
<translation id="2295140143284145483">Sondaggio</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Espandi la notifica</translation>
+<translation id="2445449901874883781">Usa densità alta</translation>
<translation id="2482878487686419369">Notifiche</translation>
<translation id="2497284189126895209">Tutti i file</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Freccia GIÙ</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 giorno}other{# giorni}}</translation>
<translation id="335581015389089642">Voce</translation>
+<translation id="3479552764303398839">Non adesso</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 giorno rimanente}other{# giorni rimanenti}}</translation>
<translation id="3618849550573277856">Cerca "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Seleziona la cartella da caricare</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Freccia sinistra</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 giorno e }other{# giorni e }}</translation>
+<translation id="5895138241574237353">Riavvia</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 secondo rimanente}other{# secondi rimanenti}}</translation>
<translation id="5941711191222866238">Riduci a icona</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 ora}other{# ore}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_iw.xtb b/chromium/ui/strings/translations/ui_strings_iw.xtb
index 8178dc769ea..dc717890dde 100644
--- a/chromium/ui/strings/translations/ui_strings_iw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_iw.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652">%<ph name="NUMBER" /></translation>
<translation id="1901303067676059328">בחר &amp;הכל</translation>
+<translation id="1938451708255335766">כדי להתאים את דחיסות התצוגה של החלון, צריך להפעיל מחדש את האפליקציה.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{יום}two{# ימ}many{# ימ}other{# ימ}}</translation>
<translation id="2148716181193084225">היום</translation>
<translation id="2168039046890040389">דף למעלה</translation>
<translation id="2190355936436201913">(ריק)</translation>
+<translation id="2192232475740621500">שימוש בדחיסות נמוכה</translation>
<translation id="219905428774326614">מפעיל האפליקציות, כל האפליקציות</translation>
<translation id="2267918077332197517">חסימת כל ההודעות מהאתר הזה</translation>
<translation id="2289052229480071835">הקש על יעדי המגע במסך.</translation>
<translation id="2295140143284145483">סקר</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">הרחבת ההודעה</translation>
+<translation id="2445449901874883781">שימוש בדחיסות גבוהה</translation>
<translation id="2482878487686419369">התראות</translation>
<translation id="2497284189126895209">כל הקבצים</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">חץ למטה</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{יום אחד}two{יומיים}many{# ימים}other{# ימים}}</translation>
<translation id="335581015389089642">דיבור</translation>
+<translation id="3479552764303398839">לא עכשיו</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{נותר יום אחד}two{נותרו יומיים}many{נותרו # ימים}other{נותרו # ימים}}</translation>
<translation id="3618849550573277856">חפש “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">בחירת תיקיה להעלאה</translation>
@@ -93,12 +97,13 @@
<translation id="528468243742722775">End</translation>
<translation id="5329858601952122676">&amp;מחק</translation>
<translation id="5463830097259460683">אמוג'י וסמלים</translation>
-<translation id="5476505524087279545">בטל סימון</translation>
+<translation id="5476505524087279545">ביטול הסימון</translation>
<translation id="5574202486608032840">מערכת <ph name="IDS_SHORT_PRODUCT_OS_NAME" /></translation>
<translation id="5583640892426849032">Backspace</translation>
<translation id="5613020302032141669">חץ לשמאל</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{דק‘ אחת}two{# דק‘}many{# דק‘}other{# דק‘}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{יום אחד ו }two{יומיים ו }many{# ימים ו }other{# ימים ו }}</translation>
+<translation id="5895138241574237353">הפעל מחדש</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{נותרה שנייה אחת}two{נותרו # שניות}many{נותרו # שניות}other{נותרו # שניות}}</translation>
<translation id="5941711191222866238">מזער</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{שעה אחת}two{שעתיים}many{# שעות}other{# שעות}}</translation>
@@ -139,7 +144,7 @@
<translation id="7130207228079676353">סבירות גבוהה</translation>
<translation id="7222373446505536781">F11</translation>
<translation id="7238427729722629793">{MINUTES,plural, =1{נותרה דק‘ אחת}two{נותרו # דק‘}many{נותרו # דק‘}other{נותרו # דק‘}}</translation>
-<translation id="7319740667687257810">מפעיל האפליקציות, תצוגה חלקית</translation>
+<translation id="7319740667687257810">מרכז האפליקציות, תצוגה חלקית</translation>
<translation id="7365057348334984696">{MINUTES,plural, =1{לפני דק‘ אחת}two{לפני # דק‘}many{לפני # דק‘}other{לפני # דק‘}}</translation>
<translation id="7389409599945284130">- <ph name="MESSAGE" /></translation>
<translation id="7410957453383678442">{MINUTES,plural, =1{נותרה דקה אחת}two{נותרו # דקות}many{נותרו # דקות}other{נותרו # דקות}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ja.xtb b/chromium/ui/strings/translations/ui_strings_ja.xtb
index 55d4dee55a6..51e5001a3a3 100644
--- a/chromium/ui/strings/translations/ui_strings_ja.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ja.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Insert</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">すべて選択(&amp;A)</translation>
+<translation id="1938451708255335766">ウィンドウの表示間隔を調整するには、アプリを再起動してください。</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1日}other{#日}}</translation>
<translation id="2148716181193084225">今日</translation>
<translation id="2168039046890040389">前のページへ</translation>
<translation id="2190355936436201913">(なし)</translation>
+<translation id="2192232475740621500">表示間隔を広くする</translation>
<translation id="219905428774326614">ランチャー、すべてのアプリ</translation>
<translation id="2267918077332197517">このサイトからのすべての通知をブロックする</translation>
<translation id="2289052229480071835">画面に表示されるタップ ターゲットをタップします。</translation>
<translation id="2295140143284145483">アンケート</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/秒</translation>
<translation id="24452542372838207">通知を展開</translation>
+<translation id="2445449901874883781">表示間隔を狭くする</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2497284189126895209">すべてのファイル</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">下矢印キー</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 日}other{# 日}}</translation>
<translation id="335581015389089642">スピーチ</translation>
+<translation id="3479552764303398839">後で</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{残り 1 日}other{残り # 日}}</translation>
<translation id="3618849550573277856">「<ph name="LOOKUP_STRING" />」を検索</translation>
<translation id="364720409959344976">アップロードするフォルダを選択</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">左矢印キー</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 分}other{# 分}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 日と }other{# 日と }}</translation>
+<translation id="5895138241574237353">再起動</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{残り 1 秒}other{残り # 秒}}</translation>
<translation id="5941711191222866238">最小化</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 時間}other{# 時間}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_kn.xtb b/chromium/ui/strings/translations/ui_strings_kn.xtb
index 3875572b073..da61a1730c8 100644
--- a/chromium/ui/strings/translations/ui_strings_kn.xtb
+++ b/chromium/ui/strings/translations/ui_strings_kn.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;ಎಲ್ಲ ಆಯ್ಕೆ ಮಾಡಿ</translation>
+<translation id="1938451708255335766">ವಿಂಡೋ ಡಿಸ್‌ಪ್ಲೇ ಸಾಂದ್ರತೆಯನ್ನು ಸರಿಹೊಂದಿಸಲು, ಆ್ಯಪ್ ಮರುಪ್ರಾರಂಭಿಸಿ.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1ದಿ}one{#ದಿ}other{#ದಿ}}</translation>
<translation id="2148716181193084225">ಇಂದು</translation>
<translation id="2168039046890040389">ಪುಟ ಮೇಲೆ</translation>
<translation id="2190355936436201913">(ಖಾಲಿ)</translation>
+<translation id="2192232475740621500">ಕಡಿಮೆ ಸಾಂದ್ರತೆಯನ್ನು ಬಳಸಿ</translation>
<translation id="219905428774326614">ಲಾಂಚರ್‌, ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು</translation>
<translation id="2267918077332197517">ಈ ಸೈಟ್‌ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ</translation>
<translation id="2289052229480071835">ನಿಮ್ಮ ಪರದೆಯಲ್ಲಿ ಸ್ಪರ್ಶ ಟಾರ್ಗೆಟ್‌ಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ.</translation>
<translation id="2295140143284145483">ಸಮೀಕ್ಷೆ</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">ವಿಸ್ತರಿಸುವ ಅಧಿಸೂಚನೆ</translation>
+<translation id="2445449901874883781">ಅಧಿಕ ಸಾಂದ್ರತೆಯನ್ನು ಬಳಸಿ</translation>
<translation id="2482878487686419369">ಸೂಚನೆಗಳು</translation>
<translation id="2497284189126895209">ಎಲ್ಲ ಫೈಲ್‌ಗಳು</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">ಕೆಳಗಿನ ಬಾಣದ ಗುರುತು</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ದಿನ}one{# ದಿನಗಳು}other{# ದಿನಗಳು}}</translation>
<translation id="335581015389089642">ಧ್ವನಿ</translation>
+<translation id="3479552764303398839">ಈಗ ಬೇಡ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 ದಿನ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ದಿನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” ನೋಡಿ</translation>
<translation id="364720409959344976">ಅಪ್‌ಲೋಡ್ ಮಾಡಲು ಫೋಲ್ಡರ್ ಆಯ್ಕೆಮಾಡಿ</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">ಎಡ ಬಾಣದ ಗುರುತು</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 ನಿಮಿ}one{# ನಿಮಿಷಗಳು}other{# ನಿಮಿಷಗಳು}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 ದಿನ ಮತ್ತು }one{# ದಿನಗಳು ಮತ್ತು }other{# ದಿನಗಳು ಮತ್ತು }}</translation>
+<translation id="5895138241574237353">ಮರುಪ್ರಾರಂಭಿಸಿ</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 ಸೆಕೆಂಡ್ ಬಾಕಿ ಉಳಿದಿದೆ}one{# ಸೆಕೆಂಡುಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}other{# ಸೆಕೆಂಡುಗಳು ಬಾಕಿ ಉಳಿದಿವೆ}}</translation>
<translation id="5941711191222866238">ಕುಗ್ಗಿಸು</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 ಗಂಟೆ}one{# ಗಂಟೆಗಳು}other{# ಗಂಟೆಗಳು}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ko.xtb b/chromium/ui/strings/translations/ui_strings_ko.xtb
index 7d7fa80827e..f2ac213bfb7 100644
--- a/chromium/ui/strings/translations/ui_strings_ko.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ko.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Insert</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">전체 선택(&amp;A)</translation>
+<translation id="1938451708255335766">창 표시 밀도를 조정하려면 앱을 다시 시작하세요.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1일}other{#일}}</translation>
<translation id="2148716181193084225">오늘</translation>
<translation id="2168039046890040389">페이지 위로</translation>
<translation id="2190355936436201913">(비어있음)</translation>
+<translation id="2192232475740621500">저밀도 사용</translation>
<translation id="219905428774326614">런처, 모든 앱</translation>
<translation id="2267918077332197517">이 사이트의 모든 알림 차단</translation>
<translation id="2289052229480071835">화면에서 터치 대상을 탭하세요.</translation>
<translation id="2295140143284145483">설문조사</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" />TB/s</translation>
<translation id="24452542372838207">알림 펼치기</translation>
+<translation id="2445449901874883781">고밀도 사용</translation>
<translation id="2482878487686419369">알림</translation>
<translation id="2497284189126895209">모든 파일</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">아래 화살표</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1일}other{#일}}</translation>
<translation id="335581015389089642">음성</translation>
+<translation id="3479552764303398839">나중에</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1일 남음}other{#일 남음}}</translation>
<translation id="3618849550573277856">'<ph name="LOOKUP_STRING" />' 찾기</translation>
<translation id="364720409959344976">업로드할 폴더 선택</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">왼쪽 화살표</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1분}other{#분}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1일 }other{#일 }}</translation>
+<translation id="5895138241574237353">다시 시작</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1초 남음}other{#초 남음}}</translation>
<translation id="5941711191222866238">최소화</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1시간}other{#시간}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lt.xtb b/chromium/ui/strings/translations/ui_strings_lt.xtb
index ec6bc01b05a..4d160fd66d6 100644
--- a/chromium/ui/strings/translations/ui_strings_lt.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lt.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Pasirinkti &amp;viską</translation>
+<translation id="1938451708255335766">Kad būtų pritaikytas lango rodymo tankio koregavimas, iš naujo paleiskite programą.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d.}one{# d.}few{# d.}many{# d.}other{# d.}}</translation>
<translation id="2148716181193084225">Šiandien</translation>
<translation id="2168039046890040389">Puslapį į viršų</translation>
<translation id="2190355936436201913">(tuščias)</translation>
+<translation id="2192232475740621500">Naudoti mažą tankį</translation>
<translation id="219905428774326614">Paleidimo priemonė, visos programos</translation>
<translation id="2267918077332197517">Blokuoti visus šios svetainės pranešimus</translation>
<translation id="2289052229480071835">Palieskite jutiklines sritis ekrane.</translation>
<translation id="2295140143284145483">Apklausa</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Išskleisti pranešimą</translation>
+<translation id="2445449901874883781">Naudoti didelį tankį</translation>
<translation id="2482878487686419369">Pranešimai</translation>
<translation id="2497284189126895209">Visi failai</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Rodyklė „Žemyn“</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 diena}one{# diena}few{# dienos}many{# dienos}other{# dienų}}</translation>
<translation id="335581015389089642">Kalba</translation>
+<translation id="3479552764303398839">Ne dabar</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Liko 1 diena}one{Liko # diena}few{Liko # dienos}many{Liko # dienos}other{Liko # dienų}}</translation>
<translation id="3618849550573277856">Ieškoti „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Pasirinkite norimą įkelti aplanką</translation>
@@ -67,7 +71,7 @@
<translation id="3740362395218339114"><ph name="QUANTITY" /> GB/s</translation>
<translation id="3757388668994797779"><ph name="QUANTITY" /> GB</translation>
<translation id="3842239759367498783">Toliau skaityti iš mobiliojo įrenginio „<ph name="TITLE" />“</translation>
-<translation id="385051799172605136">Grįžti</translation>
+<translation id="385051799172605136">Atgal</translation>
<translation id="3889424535448813030">Rodyklė į dešinę</translation>
<translation id="3892641579809465218">Vidinė pateiktis</translation>
<translation id="3897092660631435901">Meniu</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Rodyklė į kairę</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min.}one{# min.}few{# min.}many{# min.}other{# min.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 diena ir }one{# diena ir }few{# dienos ir }many{# dienos ir }other{# dienų ir }}</translation>
+<translation id="5895138241574237353">Paleisti iš naujo</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Liko 1 sekundė}one{Liko # sekundė}few{Liko # sekundės}many{Liko # sekundės}other{Liko # sekundžių}}</translation>
<translation id="5941711191222866238">Sumažinti</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 valanda}one{# valanda}few{# valandos}many{# valandos}other{# valandų}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_lv.xtb b/chromium/ui/strings/translations/ui_strings_lv.xtb
index 621829fab9a..00b029ccb5f 100644
--- a/chromium/ui/strings/translations/ui_strings_lv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_lv.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Iespraušana</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Izvēlēties visus</translation>
+<translation id="1938451708255335766">Lai pielāgotu loga attēlojuma blīvumu, restartējiet lietotni.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d.}zero{# d.}one{# d.}other{# d.}}</translation>
<translation id="2148716181193084225">Šodien</translation>
<translation id="2168039046890040389">Augšup</translation>
<translation id="2190355936436201913">(tukšs)</translation>
+<translation id="2192232475740621500">Izmantot mazu blīvumu</translation>
<translation id="219905428774326614">Palaišanas programma, visas lietotnes</translation>
<translation id="2267918077332197517">Bloķēt visus paziņojumus no šīs vietnes</translation>
<translation id="2289052229480071835">Pieskarieties ekrānā redzamajiem pieskāriena mērķiem.</translation>
<translation id="2295140143284145483">Aptauja</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Izvērst paziņojumu</translation>
+<translation id="2445449901874883781">Izmantot lielu blīvumu</translation>
<translation id="2482878487686419369">Paziņojumi</translation>
<translation id="2497284189126895209">Visi faili</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Bulta Lejup</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 diena}zero{# dienas}one{# diena}other{# dienas}}</translation>
<translation id="335581015389089642">Runa</translation>
+<translation id="3479552764303398839">Vēlāk</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Atlikusi 1 diena}zero{Atlikušas # dienas}one{Atlikusi # diena}other{Atlikušas # dienas}}</translation>
<translation id="3618849550573277856">Meklēt “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Augšupielādējamās mapes atlase</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Kreisā bulta</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}zero{# min}one{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 diena un }zero{# dienas un }one{# diena un }other{# dienas un }}</translation>
+<translation id="5895138241574237353">Restartēt</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Atlikusi 1 sekunde}zero{Atlikušas # sekundes}one{Atlikusi # sekunde}other{Atlikušas # sekundes}}</translation>
<translation id="5941711191222866238">Minimizēt</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 stunda}zero{# stundas}one{# stunda}other{# stundas}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ml.xtb b/chromium/ui/strings/translations/ui_strings_ml.xtb
index 30a79e79ec1..4ac3c5545e0 100644
--- a/chromium/ui/strings/translations/ui_strings_ml.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ml.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">എല്ലാം &amp;തിരഞ്ഞെടുക്കൂ</translation>
+<translation id="1938451708255335766">വിൻഡോ ഡിസ്പ്ലേ സാന്ദ്രത ക്രമീകരിക്കാൻ, ആപ്പ് റീസ്റ്റാര്‍ട്ട് ചെയ്യുക.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1ദിവസം}other{# ദിവസം}}</translation>
<translation id="2148716181193084225">ഇന്ന്</translation>
<translation id="2168039046890040389">പേജ് മുകളിലേയ്ക്ക്</translation>
<translation id="2190355936436201913">(ശൂന്യം)</translation>
+<translation id="2192232475740621500">കുറഞ്ഞ സാന്ദ്രത ഉപയോഗിക്കുക</translation>
<translation id="219905428774326614">ലോഞ്ചർ, എല്ലാ ആപ്പുകളും</translation>
<translation id="2267918077332197517">ഈ സൈറ്റിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്ക് ചെയ്യുക</translation>
<translation id="2289052229480071835">സ്‌ക്രീനിലുള്ള 'ടാർഗെറ്റുകൾ സ്‌പർശിക്കുക' ടാപ്പുചെയ്യുക.</translation>
<translation id="2295140143284145483">സർവ്വേ</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">അറിയിപ്പ് വികസിപ്പിക്കുക</translation>
+<translation id="2445449901874883781">കൂടിയ സാന്ദ്രത ഉപയോഗിക്കുക</translation>
<translation id="2482878487686419369">വിജ്ഞാപനങ്ങള്‍‌</translation>
<translation id="2497284189126895209">എല്ലാ ഫയലുകളും</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">താഴേക്കുള്ള ആരോ അടയാളം</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{ഒരു ദിവസം}other{# ദിവസം}}</translation>
<translation id="335581015389089642">സംഭാഷണം</translation>
+<translation id="3479552764303398839">ഇപ്പോഴല്ല</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{ഒരു ദിവസം ശേഷിക്കുന്നു}other{# ദിവസം ശേഷിക്കുന്നു}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” തിരയുക</translation>
<translation id="364720409959344976">അപ്‌ലോഡുചെയ്യുന്നതിന് ഫോൾഡർ തിരഞ്ഞെടുക്കുക</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">ഇടത് ആരോ അടയാളം</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{ഒരു മിനിറ്റ്}other{# മിനിറ്റ്}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{ഒരു ദിവസവും }other{# ദിവസവും }}</translation>
+<translation id="5895138241574237353">പുനരാരംഭിക്കുക</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{ഒരു സെക്കൻഡ് ശേഷിക്കുന്നു}other{# സെക്കൻഡ് ശേഷിക്കുന്നു}}</translation>
<translation id="5941711191222866238">ചെറുതാക്കുക‍</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{ഒരു മണിക്കൂർ}other{# മണിക്കൂർ}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_mr.xtb b/chromium/ui/strings/translations/ui_strings_mr.xtb
index 3c0483238e5..690566e8790 100644
--- a/chromium/ui/strings/translations/ui_strings_mr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_mr.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;सर्व निवडा</translation>
+<translation id="1938451708255335766">विंडो डिस्प्ले घनता अ‍ॅडजस्ट करण्यासाठी, अ‍ॅप रीस्टार्ट करा.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1दि}one{#दि}other{#दि}}</translation>
<translation id="2148716181193084225">आज</translation>
<translation id="2168039046890040389">पृष्ठ वर</translation>
<translation id="2190355936436201913">(रिक्त)</translation>
+<translation id="2192232475740621500">कमी घनता वापरा</translation>
<translation id="219905428774326614">लाँचर, सर्व अ‍ॅप्स</translation>
<translation id="2267918077332197517">या साइटच्या सर्व सूचना ब्‍लॉक करा</translation>
<translation id="2289052229480071835">आपल्या स्क्रीनवरील लक्ष्यांना स्पर्श करा टॅप करा.</translation>
<translation id="2295140143284145483">सर्वेक्षण</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">सूचना विस्तृत करा</translation>
+<translation id="2445449901874883781">उच्च घनता वापरा</translation>
<translation id="2482878487686419369">सूचना</translation>
<translation id="2497284189126895209">सर्व फाइल</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Down Arrow</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 दिवस}one{# दिवस}other{# दिवस}}</translation>
<translation id="335581015389089642">भाषण</translation>
+<translation id="3479552764303398839">सध्या नाही</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 दिवस शिल्लक}one{# दिवस शिल्लक}other{# दिवस शिल्लक}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” पहा</translation>
<translation id="364720409959344976">अपलोड करण्यासाठी फोल्डर निवडा</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Left Arrow</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 मिनिट}one{# मिनिट}other{# मिनिटे}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 दिवस आणि }one{# दिवस आणि }other{# दिवस आणि }}</translation>
+<translation id="5895138241574237353">रीस्टार्ट करा</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 सेकंद शिल्लक}one{# सेकंद शिल्लक}other{# सेकंद शिल्लक}}</translation>
<translation id="5941711191222866238">लहान करा</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 तास}one{# तास}other{# तास}}</translation>
@@ -111,7 +116,7 @@
<translation id="6142413573757616983"><ph name="QUANTITY" /> B/s</translation>
<translation id="6156262341071374681">सर्व अ‍ॅप्सवर विस्तृत करा</translation>
<translation id="6264365405983206840">&amp;सर्व निवडा</translation>
-<translation id="6351032674660237738">अॅप सूचना</translation>
+<translation id="6351032674660237738">ॲप सूचना</translation>
<translation id="6364916375976753737">डावीकडे स्क्रोल करा</translation>
<translation id="6394627529324717982">स्वल्पविराम</translation>
<translation id="6397363302884558537">बोलणे थांबवा</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ms.xtb b/chromium/ui/strings/translations/ui_strings_ms.xtb
index 51591dd3ffb..989667bf15b 100644
--- a/chromium/ui/strings/translations/ui_strings_ms.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ms.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Pilih &amp;semua</translation>
+<translation id="1938451708255335766">Untuk melaraskan ketumpatan paparan tetingkap, mulakan semula apl.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1h}other{#h}}</translation>
<translation id="2148716181193084225">Hari ini</translation>
<translation id="2168039046890040389">Halaman Ke Atas</translation>
<translation id="2190355936436201913">(kosong)</translation>
+<translation id="2192232475740621500">Gunakan ketumpatan rendah</translation>
<translation id="219905428774326614">Pelancar, semua apl</translation>
<translation id="2267918077332197517">Sekat semua pemberitahuan daripada tapak ini</translation>
<translation id="2289052229480071835">Ketik sasaran sentuhan pada skrin anda.</translation>
<translation id="2295140143284145483">Tinjauan</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Kembangkan pemberitahuan</translation>
+<translation id="2445449901874883781">Gunakan ketumpatan tinggi</translation>
<translation id="2482878487686419369">Pemberitahuan</translation>
<translation id="2497284189126895209">Semua Fail</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Anak Panah Bawah</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 hari}other{# hari}}</translation>
<translation id="335581015389089642">Pertuturan</translation>
+<translation id="3479552764303398839">Bukan sekarang</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 hari lagi}other{# hari lagi}}</translation>
<translation id="3618849550573277856">Cari “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Pilih Folder untuk Dimuat Naik</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Anak Panah Kiri</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 hari dan }other{# hari dan }}</translation>
+<translation id="5895138241574237353">Mulakan Semula</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 saat lagi}other{# saat lagi}}</translation>
<translation id="5941711191222866238">Minimumkan</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 jam}other{# jam}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_nl.xtb b/chromium/ui/strings/translations/ui_strings_nl.xtb
index c8c3bb38225..dc29cdcc961 100644
--- a/chromium/ui/strings/translations/ui_strings_nl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_nl.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">&amp;Alles selecteren</translation>
+<translation id="1938451708255335766">Als je de weergavedichtheid van het venster wilt aanpassen, start je de app opnieuw.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}other{# d}}</translation>
<translation id="2148716181193084225">Vandaag</translation>
<translation id="2168039046890040389">Pagina omhoog</translation>
<translation id="2190355936436201913">(leeg)</translation>
+<translation id="2192232475740621500">Lage dichtheid gebruiken</translation>
<translation id="219905428774326614">Launcher, alle apps</translation>
<translation id="2267918077332197517">Alle meldingen van deze site blokkeren</translation>
<translation id="2289052229480071835">Tik op de tikdoelen op je scherm.</translation>
<translation id="2295140143284145483">Enquête</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Melding uitvouwen</translation>
+<translation id="2445449901874883781">Hoge dichtheid gebruiken</translation>
<translation id="2482878487686419369">Meldingen</translation>
<translation id="2497284189126895209">Alle bestanden</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Pijl-omlaag</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dagen}}</translation>
<translation id="335581015389089642">Spraak</translation>
+<translation id="3479552764303398839">Niet nu</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag resterend}other{# dagen resterend}}</translation>
<translation id="3618849550573277856">'<ph name="LOOKUP_STRING" />' opzoeken</translation>
<translation id="364720409959344976">Map voor uploaden selecteren</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Pijl-links</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min.}other{# min.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dag en }other{# dagen en }}</translation>
+<translation id="5895138241574237353">Opnieuw starten</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 seconde resterend}other{# seconden reseterend}}</translation>
<translation id="5941711191222866238">Minimaliseren</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 uur}other{# uur}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_no.xtb b/chromium/ui/strings/translations/ui_strings_no.xtb
index 551c58bafa1..7e7f3827a42 100644
--- a/chromium/ui/strings/translations/ui_strings_no.xtb
+++ b/chromium/ui/strings/translations/ui_strings_no.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Marker &amp;alt</translation>
+<translation id="1938451708255335766">For å justere visningstettheten for vinduer, start appen på nytt.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}other{# d}}</translation>
<translation id="2148716181193084225">I dag</translation>
<translation id="2168039046890040389">Opp 1 s.</translation>
<translation id="2190355936436201913">(tom)</translation>
+<translation id="2192232475740621500">Bruk lav tetthet</translation>
<translation id="219905428774326614">Appoversikt, alle apper</translation>
<translation id="2267918077332197517">Blokkér alle varsler fra dette nettstedet</translation>
<translation id="2289052229480071835">Trykk på berøringsmålene på skjermen.</translation>
<translation id="2295140143284145483">Undersøkelse</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB per sek</translation>
<translation id="24452542372838207">Vis varselet</translation>
+<translation id="2445449901874883781">Bruk høy tetthet</translation>
<translation id="2482878487686419369">Varsler</translation>
<translation id="2497284189126895209">Alle filer</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Pil ned</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dager}}</translation>
<translation id="335581015389089642">Tale</translation>
+<translation id="3479552764303398839">Ikke nå</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag igjen}other{# dager igjen}}</translation>
<translation id="3618849550573277856">Slå opp «<ph name="LOOKUP_STRING" />»</translation>
<translation id="364720409959344976">Velg mappen du vil laste opp</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Pil venstre</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dag og }other{# dager og }}</translation>
+<translation id="5895138241574237353">Start på nytt</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 sekund igjen}other{# sekunder igjen}}</translation>
<translation id="5941711191222866238">Minimer</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 time}other{# timer}}</translation>
@@ -134,7 +139,7 @@
<translation id="6917971086528278418">{YEARS,plural, =1{1 år igjen}other{# år igjen}}</translation>
<translation id="6945221475159498467">Velg</translation>
<translation id="6965382102122355670">OK</translation>
-<translation id="6974053822202609517">Høyre til venstre</translation>
+<translation id="6974053822202609517">Høyre mot venstre</translation>
<translation id="7052633198403197513">F1</translation>
<translation id="7130207228079676353">MEST SANNSYNLIG</translation>
<translation id="7222373446505536781">F11</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pl.xtb b/chromium/ui/strings/translations/ui_strings_pl.xtb
index 39c52df45dc..636702c11a5 100644
--- a/chromium/ui/strings/translations/ui_strings_pl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pl.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Zaznacz &amp;wszystko</translation>
+<translation id="1938451708255335766">Aby dostosować gęstość wyświetlania okien, ponownie uruchom aplikację.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 dzień}few{# dni}many{# dni}other{# dnia}}</translation>
<translation id="2148716181193084225">Dzisiaj</translation>
<translation id="2168039046890040389">Strona do góry</translation>
<translation id="2190355936436201913">(puste)</translation>
+<translation id="2192232475740621500">Użyj małej gęstości</translation>
<translation id="219905428774326614">Menu ze wszystkimi aplikacjami</translation>
<translation id="2267918077332197517">Blokuj wszystkie powiadomienia z tej strony internetowej</translation>
<translation id="2289052229480071835">Kliknij docelowe obszary kliknięcia na ekranie.</translation>
<translation id="2295140143284145483">Ankieta</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Rozwiń powiadomienie</translation>
+<translation id="2445449901874883781">Użyj dużej gęstości</translation>
<translation id="2482878487686419369">Powiadomienia</translation>
<translation id="2497284189126895209">Wszystkie pliki</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Strzałka w dół</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dzień}few{# dni}many{# dni}other{# dnia}}</translation>
<translation id="335581015389089642">Mowa</translation>
+<translation id="3479552764303398839">Nie teraz</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Pozostał 1 dzień}few{Pozostały # dni}many{Pozostało # dni}other{Pozostało # dnia}}</translation>
<translation id="3618849550573277856">Sprawdź słowo „<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Wybierz folder do przesłania</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Strzałka w lewo</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}few{# min}many{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dzień i }few{# dni i }many{# dni i }other{# dnia i }}</translation>
+<translation id="5895138241574237353">Uruchom ponownie</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Pozostała 1 sekunda}few{Pozostały # sekundy}many{Pozostało # sekund}other{Pozostało # sekundy}}</translation>
<translation id="5941711191222866238">Minimalizuj</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 godzina}few{# godziny}many{# godzin}other{# godziny}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
index 84cc1d9f60a..62e68789939 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-BR.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Selecionar &amp;tudo</translation>
+<translation id="1938451708255335766">Para ajustar a densidade de exibição da janela, reinicie o app.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}one{# d}other{# d}}</translation>
<translation id="2148716181193084225">Hoje</translation>
<translation id="2168039046890040389">Página para cima</translation>
<translation id="2190355936436201913">(vazio)</translation>
+<translation id="2192232475740621500">Usar baixa densidade</translation>
<translation id="219905428774326614">Tela de início, todos os apps</translation>
<translation id="2267918077332197517">Bloquear todas as notificações emitidas por este site</translation>
<translation id="2289052229480071835">Toque nas áreas de toque da tela.</translation>
<translation id="2295140143284145483">Pesquisa</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Expandir notificação</translation>
+<translation id="2445449901874883781">Usar alta densidade</translation>
<translation id="2482878487686419369">Notificações</translation>
<translation id="2497284189126895209">Todos os arquivos</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Seta para baixo</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{Um dia}one{# dias}other{# dias}}</translation>
<translation id="335581015389089642">Voz</translation>
+<translation id="3479552764303398839">Não agora</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Um dia restante}one{# dias restantes}other{# dias restantes}}</translation>
<translation id="3618849550573277856">Pesquisar “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Selecionar pasta para upload</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Seta para a esquerda</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 minuto}one{# minutos}other{# minutos}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{Um dia e }one{# dias e }other{# dias e }}</translation>
+<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Um segundo restante}one{# segundos restantes}other{# segundos restantes}}</translation>
<translation id="5941711191222866238">Minimizar</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{Uma hora}one{# horas}other{# horas}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
index f6590736244..30810079c13 100644
--- a/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
+++ b/chromium/ui/strings/translations/ui_strings_pt-PT.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Seleccion&amp;ar tudo</translation>
+<translation id="1938451708255335766">Para ajustar a densidade de apresentação da janela, reinicie a aplicação.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}other{# d}}</translation>
<translation id="2148716181193084225">Hoje</translation>
<translation id="2168039046890040389">Página para cima</translation>
<translation id="2190355936436201913">(vazio)</translation>
+<translation id="2192232475740621500">Utilizar densidade baixa</translation>
<translation id="219905428774326614">Iniciador, todas as aplicações</translation>
<translation id="2267918077332197517">Bloquear todas as notificações deste site</translation>
<translation id="2289052229480071835">Toque nos alvos de toque no ecrã.</translation>
<translation id="2295140143284145483">Inquérito</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Expandir notificação</translation>
+<translation id="2445449901874883781">Utilizar densidade elevada</translation>
<translation id="2482878487686419369">Notificações</translation>
<translation id="2497284189126895209">Todos os ficheiros</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Seta para baixo</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dia}other{# dias}}</translation>
<translation id="335581015389089642">Voz</translation>
+<translation id="3479552764303398839">Agora não</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Falta 1 dia}other{Faltam # dias}}</translation>
<translation id="3618849550573277856">Procurar "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Selecionar Pasta a Carregar</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Seta para a esquerda</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dia e }other{# dias e }}</translation>
+<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Falta 1 segundo}other{Faltam # segundos}}</translation>
<translation id="5941711191222866238">Minimizar</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hora}other{# horas}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ro.xtb b/chromium/ui/strings/translations/ui_strings_ro.xtb
index b3a5f77cbcc..a800ec1fb0c 100644
--- a/chromium/ui/strings/translations/ui_strings_ro.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ro.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Select&amp;ează tot</translation>
+<translation id="1938451708255335766">Pentru a regla densitatea afișajului ferestrei, repornește aplicația.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 zi}few{# zile}other{# zile}}</translation>
<translation id="2148716181193084225">Astăzi</translation>
<translation id="2168039046890040389">O pagină mai sus</translation>
<translation id="2190355936436201913">(gol)</translation>
+<translation id="2192232475740621500">Folosește densitatea joasă</translation>
<translation id="219905428774326614">Lansator, toate aplicațiile</translation>
<translation id="2267918077332197517">Blochează toate notificările de la acest site</translation>
<translation id="2289052229480071835">Atinge țintele de atingere de pe ecran.</translation>
<translation id="2295140143284145483">Sondaj</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Extinde notificarea</translation>
+<translation id="2445449901874883781">Folosește densitatea ridicată</translation>
<translation id="2482878487686419369">Notificări</translation>
<translation id="2497284189126895209">Toate fișierele</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Săgeată în jos</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{O zi}few{# zile}other{# de zile}}</translation>
<translation id="335581015389089642">Voce</translation>
+<translation id="3479552764303398839">Nu acum</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{O zi rămasă}few{# zile rămase}other{# de zile rămase}}</translation>
<translation id="3618849550573277856">Caută „<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Selectați un dosar de încărcat</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Săgeată stânga</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{Un min.}few{# min.}other{# min.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{O zi și }few{# zile și }other{# de zile și }}</translation>
+<translation id="5895138241574237353">Reîncepe</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{O secundă rămasă}few{# secunde rămase}other{# de secunde rămase}}</translation>
<translation id="5941711191222866238">Minimizează</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{o oră}few{# ore}other{# de ore}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ru.xtb b/chromium/ui/strings/translations/ui_strings_ru.xtb
index b4752a9a49c..718d1bb9567 100644
--- a/chromium/ui/strings/translations/ui_strings_ru.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ru.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Выделить &amp;все</translation>
+<translation id="1938451708255335766">Чтобы применить новые настройки интерфейса, перезапустите приложение.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 д.}one{# д.}few{# д.}many{# д.}other{# д.}}</translation>
<translation id="2148716181193084225">Сегодня</translation>
<translation id="2168039046890040389">Вверх</translation>
<translation id="2190355936436201913">(пусто)</translation>
+<translation id="2192232475740621500">Показывать меньше окон</translation>
<translation id="219905428774326614">Панель запуска, все приложения</translation>
<translation id="2267918077332197517">Блокировать все уведомления этого сайта</translation>
<translation id="2289052229480071835">Коснитесь интерактивных элементов на экране.</translation>
<translation id="2295140143284145483">Опрос</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> ТБ/с</translation>
<translation id="24452542372838207">Развернуть уведомление</translation>
+<translation id="2445449901874883781">Показывать больше окон</translation>
<translation id="2482878487686419369">Уведомления</translation>
<translation id="2497284189126895209">Все файлы</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Стрелка вниз</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дня}many{# дней}other{# дня}}</translation>
<translation id="335581015389089642">Озвучить</translation>
+<translation id="3479552764303398839">Не сейчас</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Остался 1 день}one{Остался # день}few{Осталось # дня}many{Осталось # дней}other{Осталось # дня}}</translation>
<translation id="3618849550573277856">Найти "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Выберите папку для загрузки</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Стрелка влево</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 мин.}one{# мин.}few{# мин.}many{# мин.}other{# мин.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 день }one{# день }few{# дня }many{# дней }other{# дня }}</translation>
+<translation id="5895138241574237353">Перезапустить</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Осталась 1 секунда}one{Осталась # секунда}few{Осталось # секунды}many{Осталось # секунд}other{Осталось # секунды}}</translation>
<translation id="5941711191222866238">Свернуть</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 час}one{# час}few{# часа}many{# часов}other{# часа}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sk.xtb b/chromium/ui/strings/translations/ui_strings_sk.xtb
index 6b8c84d28c2..55aae547510 100644
--- a/chromium/ui/strings/translations/ui_strings_sk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sk.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Vybrať &amp;všetko</translation>
+<translation id="1938451708255335766">Ak chcete upraviť hustotu zobrazenia okien, reštartujte aplikáciu.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d.}few{# d.}many{# d.}other{# d.}}</translation>
<translation id="2148716181193084225">Dnes</translation>
<translation id="2168039046890040389">Page Up</translation>
<translation id="2190355936436201913">(prázdne)</translation>
+<translation id="2192232475740621500">Použiť nízku hustotu</translation>
<translation id="219905428774326614">Spúšťač, všetky aplikácie</translation>
<translation id="2267918077332197517">Blokovať všetky upozornenia z tohto webu</translation>
<translation id="2289052229480071835">Klepnite na dotykové ciele na obrazovke.</translation>
<translation id="2295140143284145483">Prieskum</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Rozbaliť upozornenie</translation>
+<translation id="2445449901874883781">Použiť vysokú hustotu</translation>
<translation id="2482878487686419369">Upozornenia</translation>
<translation id="2497284189126895209">Všetky súbory</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Šípka nadol</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 deň}few{# dni}many{# dňa}other{# dní}}</translation>
<translation id="335581015389089642">Reč</translation>
+<translation id="3479552764303398839">Teraz nie</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Zostáva 1 deň}few{Zostávajú # dni}many{Zostáva # dňa}other{Zostáva # dní}}</translation>
<translation id="3618849550573277856">Vyhľadať „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Výber priečinka na nahranie</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Šípka doľava</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}few{# min}many{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 deň a }few{# dni a }many{# dňa a }other{# dní a }}</translation>
+<translation id="5895138241574237353">Reštartovať</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Zostáva 1 sekunda}few{Zostávajú # sekundy}many{Zostáva # sekundy}other{Zostáva # sekúnd}}</translation>
<translation id="5941711191222866238">Minimalizovať</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 hodina}few{# hodiny}many{# hodiny}other{# hodín}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sl.xtb b/chromium/ui/strings/translations/ui_strings_sl.xtb
index d43f759535c..97b10ce46e3 100644
--- a/chromium/ui/strings/translations/ui_strings_sl.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sl.xtb
@@ -27,15 +27,18 @@
<translation id="1860796786778352021">Zapri obvestilo</translation>
<translation id="1871244248791675517">Ins</translation>
<translation id="1901303067676059328">Izberi &amp;vse</translation>
+<translation id="1938451708255335766">Če želite prilagoditi gostoto prikaza okna, znova zaženite aplikacijo.</translation>
<translation id="2148716181193084225">Danes</translation>
<translation id="2168039046890040389">Stran gor</translation>
<translation id="2190355936436201913">(prazno)</translation>
+<translation id="2192232475740621500">Uporabi majhno gostoto</translation>
<translation id="219905428774326614">Zaganjalnik, vse aplikacije</translation>
<translation id="2267918077332197517">Blokiraj vsa obvestila s tega spletnega mesta</translation>
<translation id="2289052229480071835">Dotaknite se ciljev za dotik na zaslonu.</translation>
<translation id="2295140143284145483">Anketa</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Razširi obvestilo</translation>
+<translation id="2445449901874883781">Uporabi veliko gostoto</translation>
<translation id="2482878487686419369">Obvestila</translation>
<translation id="2497284189126895209">Vse datoteke</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -56,6 +59,7 @@
<translation id="3234408098842461169">Puščica dol</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dan}one{# dan}two{# dneva}few{# dni}other{# dni}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3479552764303398839">Ne zdaj</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Še 1 dan}one{Še # dan}two{Še # dneva}few{Še # dni}other{Še # dni}}</translation>
<translation id="3618849550573277856">Poišči »<ph name="LOOKUP_STRING" />«</translation>
<translation id="364720409959344976">Izberite mapo, ki jo želite prenesti</translation>
@@ -93,6 +97,7 @@
<translation id="5613020302032141669">Puščica levo</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}one{# min}two{# min}few{# min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dan in }one{# dan in }two{# dneva in }few{# dni in }other{# dni in }}</translation>
+<translation id="5895138241574237353">Znova zaženi</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Še 1 s}one{Še # s}two{Še # s}few{Še # s}other{Še # s}}</translation>
<translation id="5941711191222866238">Pomanjšaj</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 h}one{# h}two{# h}few{# h}other{# h}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sr.xtb b/chromium/ui/strings/translations/ui_strings_sr.xtb
index 72192440d37..642dbfd3d12 100644
--- a/chromium/ui/strings/translations/ui_strings_sr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sr.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Изабери &amp;све</translation>
+<translation id="1938451708255335766">Да бисте подесили густину приказа прозора, поново покрените апликацију.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 д}one{# д}few{# д}other{# д}}</translation>
<translation id="2148716181193084225">Данас</translation>
<translation id="2168039046890040389">Страница нагоре</translation>
<translation id="2190355936436201913">(празно)</translation>
+<translation id="2192232475740621500">Користи ниску густину</translation>
<translation id="219905428774326614">Покретач, све апликације</translation>
<translation id="2267918077332197517">Блокирај сва обавештења са овог сајта</translation>
<translation id="2289052229480071835">Додирните циљна поља за додир на екрану.</translation>
<translation id="2295140143284145483">Анкета</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Прошири обавештење</translation>
+<translation id="2445449901874883781">Користи високу густину</translation>
<translation id="2482878487686419369">Обавештења</translation>
<translation id="2497284189126895209">Све датотеке</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Стрелица надоле</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 дан}one{# дан}few{# дана}other{# дана}}</translation>
<translation id="335581015389089642">Говор</translation>
+<translation id="3479552764303398839">Не сада</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Још 1 дан}one{Још # дан}few{Још # дана}other{Још # дана}}</translation>
<translation id="3618849550573277856">Потражи „<ph name="LOOKUP_STRING" />“</translation>
<translation id="364720409959344976">Избор директоријума за отпремање</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Стрелица налево</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 мин}one{# мин}few{# мин}other{# мин}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 дан и }one{# дан и }few{# дана и }other{# дана и }}</translation>
+<translation id="5895138241574237353">Покрени поново</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Још 1 секунда}one{Још # секунда}few{Још # секунде}other{Још # секунди}}</translation>
<translation id="5941711191222866238">Смањи</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 сат}one{# сат}few{# сата}other{# сати}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sv.xtb b/chromium/ui/strings/translations/ui_strings_sv.xtb
index 54a2a2e2dd2..b49a1c8f3e1 100644
--- a/chromium/ui/strings/translations/ui_strings_sv.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sv.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Välj &amp;alla</translation>
+<translation id="1938451708255335766">Starta om appen om du vill anpassa visningstätheten för fönstret.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 d}other{# d}}</translation>
<translation id="2148716181193084225">Idag</translation>
<translation id="2168039046890040389">Page Up</translation>
<translation id="2190355936436201913">(tom)</translation>
+<translation id="2192232475740621500">Använd låg densitet</translation>
<translation id="219905428774326614">Startprogram, alla appar</translation>
<translation id="2267918077332197517">Blockera alla aviseringar från den här webbplatsen</translation>
<translation id="2289052229480071835">Tryck på tryckområdena på skärmen.</translation>
<translation id="2295140143284145483">Enkät</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/sek</translation>
<translation id="24452542372838207">Utöka avisering</translation>
+<translation id="2445449901874883781">Använd hög densitet</translation>
<translation id="2482878487686419369">Aviseringar</translation>
<translation id="2497284189126895209">Alla filer</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Nedpil</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 dag}other{# dagar}}</translation>
<translation id="335581015389089642">Tal</translation>
+<translation id="3479552764303398839">Inte nu</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 dag kvar}other{# dagar kvar}}</translation>
<translation id="3618849550573277856">Sök efter ”<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Välj en mapp för uppladdning</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Vänsterpil</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 min}other{# min}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 dag och }other{# dagar och }}</translation>
+<translation id="5895138241574237353">Starta om</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 sekund kvar}other{# sekunder kvar}}</translation>
<translation id="5941711191222866238">Minimera</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 timme}other{# timmar}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_sw.xtb b/chromium/ui/strings/translations/ui_strings_sw.xtb
index 7826e6cc78b..9e57408f9f4 100644
--- a/chromium/ui/strings/translations/ui_strings_sw.xtb
+++ b/chromium/ui/strings/translations/ui_strings_sw.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Chagua &amp;yote</translation>
+<translation id="1938451708255335766">Ili ubadilishe uzito wa onyesho la dirisha, zima kisha uwashe programu hii.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{Siku 1}other{Siku #}}</translation>
<translation id="2148716181193084225">Leo</translation>
<translation id="2168039046890040389">Ukurasa mmoja juu</translation>
<translation id="2190355936436201913">(tupu)</translation>
+<translation id="2192232475740621500">Tumia uzito wa chini</translation>
<translation id="219905428774326614">Kifungua Programu, programu zote</translation>
<translation id="2267918077332197517">Zuia arifa zote kutoka tovuti hii</translation>
<translation id="2289052229480071835">Gusa viashirio vya kugusa kwenye skrini yako.</translation>
<translation id="2295140143284145483">Utafiti</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">Panua arifa</translation>
+<translation id="2445449901874883781">Tumia uzito wa juu</translation>
<translation id="2482878487686419369">Arifa</translation>
<translation id="2497284189126895209">Faili zote</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Mshale Chini</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{Siku 1}other{Siku #}}</translation>
<translation id="335581015389089642">Usemi</translation>
+<translation id="3479552764303398839">Sio sasa</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Imesalia siku 1}other{Zimesalia siku #}}</translation>
<translation id="3618849550573277856">Angalia “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Chagua Folda ya Kupakia</translation>
@@ -67,7 +71,7 @@
<translation id="3740362395218339114">GB/s <ph name="QUANTITY" /></translation>
<translation id="3757388668994797779">GB <ph name="QUANTITY" /></translation>
<translation id="3842239759367498783">Endelea kusoma kwenye kifaa chako cha mkononi <ph name="TITLE" /></translation>
-<translation id="385051799172605136">Nyuma</translation>
+<translation id="385051799172605136">Rudi nyuma</translation>
<translation id="3889424535448813030">Mshale Kulia</translation>
<translation id="3892641579809465218">Onyesho la Ndani</translation>
<translation id="3897092660631435901">Menyu</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Mshale Kushoto</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{Dakika 1}other{Dakika #}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{Siku 1 na }other{Siku # na }}</translation>
+<translation id="5895138241574237353">Zzima na uwashe</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Imesalia sekunde 1}other{Zimesalia sekunde #}}</translation>
<translation id="5941711191222866238">Punguza</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{Saa 1}other{Saa #}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_ta.xtb b/chromium/ui/strings/translations/ui_strings_ta.xtb
index 012be74b666..8b052d21557 100644
--- a/chromium/ui/strings/translations/ui_strings_ta.xtb
+++ b/chromium/ui/strings/translations/ui_strings_ta.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">அ&amp;னைத்தையும் தேர்ந்தெடு</translation>
+<translation id="1938451708255335766">சாளரக் காட்சியின் அடர்த்தியைச் சரிசெய்ய, ஆப்ஸை மீண்டும் தொடங்கவும்.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1நா}other{#நா}}</translation>
<translation id="2148716181193084225">இன்று</translation>
<translation id="2168039046890040389">பக்கத்தின் மேலே</translation>
<translation id="2190355936436201913">(காலி)</translation>
+<translation id="2192232475740621500">குறைந்த அடர்த்தியைப் பயன்படுத்து</translation>
<translation id="219905428774326614">துவக்கி, எல்லாப் பயன்பாடுகளும்</translation>
<translation id="2267918077332197517">இந்தத் தளத்திலிருந்து எல்லா அறிவிப்புகளையும் தடு</translation>
<translation id="2289052229480071835">உங்கள் திரையில் இருக்கும் தொடுவதற்கான இலக்கிடங்களைத் தட்டவும்.</translation>
<translation id="2295140143284145483">கருத்துக்கணிப்பு</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> டெ.பை/வி</translation>
<translation id="24452542372838207">அறிவிப்பை விரிவாக்கு</translation>
+<translation id="2445449901874883781">அதிக அடர்த்தியைப் பயன்படுத்து</translation>
<translation id="2482878487686419369">அறிவிப்புகள்</translation>
<translation id="2497284189126895209">அனைத்து கோப்புகளும்</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">கீழ்நோக்கிய அம்பு</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 நாள்}other{# நாட்கள்}}</translation>
<translation id="335581015389089642">பேச்சு</translation>
+<translation id="3479552764303398839">இப்பொழுது இல்லை</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 நாள் உள்ளது}other{# நாட்கள் உள்ளன}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” எனத் தேடு</translation>
<translation id="364720409959344976">பதிவேற்றுவதற்குக் கோப்புறையைத் தேர்ந்தெடு</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">இடது அம்பு</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 நிமிடம்}other{# நிமிடங்கள்}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 நாள், }other{# நாட்கள், }}</translation>
+<translation id="5895138241574237353">மறுதொடக்கம்</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 நிமிடம் உள்ளது}other{# நிமிடங்கள் உள்ளன}}</translation>
<translation id="5941711191222866238">சிறிதாக்கு</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 மணிநேரம்}other{# மணிநேரம்}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_te.xtb b/chromium/ui/strings/translations/ui_strings_te.xtb
index b94fc4fc376..c8e93a4a5f8 100644
--- a/chromium/ui/strings/translations/ui_strings_te.xtb
+++ b/chromium/ui/strings/translations/ui_strings_te.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">&amp;అన్నీ ఎంచుకోండి</translation>
+<translation id="1938451708255335766">విండో డిస్‌ప్లే సాంద్రతను సర్దుబాటు చేయడం కోసం, యాప్‌ని పునఃప్రారంభించండి.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1రో}other{#రో}}</translation>
<translation id="2148716181193084225">ఈ రోజు</translation>
<translation id="2168039046890040389">పేజీ పైకి</translation>
<translation id="2190355936436201913">(ఖాళీ)</translation>
+<translation id="2192232475740621500">తక్కువ సాంద్రతను ఉపయోగించు</translation>
<translation id="219905428774326614">లాంచర్, అన్ని యాప్‌లు</translation>
<translation id="2267918077332197517">ఈ సైట్ నుండి నోటిఫికేషన్‌లు అన్ని బ్లాక్ చేయండి</translation>
<translation id="2289052229480071835">మీ స్క్రీన్‌పై ఉన్న స్పర్శ లక్ష్యాలను నొక్కండి.</translation>
<translation id="2295140143284145483">సర్వే</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">నోటిఫికేషన్‌ను విస్తరించు</translation>
+<translation id="2445449901874883781">ఎక్కువ సాంద్రతను ఉపయోగించు</translation>
<translation id="2482878487686419369">ప్రకటనలు</translation>
<translation id="2497284189126895209">మొత్తం ఫైళ్లు</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">క్రింది బాణం</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 రోజు}other{# రోజులు}}</translation>
<translation id="335581015389089642">ప్రసంగం</translation>
+<translation id="3479552764303398839">ఇప్పుడు కాదు</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 రోజు మిగిలి ఉంది}other{# రోజులు మిగిలి ఉన్నాయి}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />”ని వెతకండి</translation>
<translation id="364720409959344976">అప్‌లోడ్ చేయడానికి ఫోల్డర్‌ని ఎంచుకోండి</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">ఎడమ బాణం</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 నిమి.}other{# నిమి.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 రోజు మరియు }other{# రోజులు మరియు }}</translation>
+<translation id="5895138241574237353">మళ్ళీ ప్రారంభించు</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 సెకను మిగిలి ఉంది}other{# సెకన్లు మిగిలి ఉన్నాయి}}</translation>
<translation id="5941711191222866238">కనిష్టీకరించు</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 గంట}other{# గంటలు}}</translation>
@@ -122,7 +127,7 @@
<translation id="6567071839949112727">క్లిక్ మూలకం</translation>
<translation id="6612467943526193239">క్రమాంకనం నుండి నిష్క్రమించేందుకు, Esc నొక్కండి.</translation>
<translation id="6620110761915583480">ఫైల్‌ను సేవ్ చేయి</translation>
-<translation id="6699343763173986273">మీడియా తదుపరి ట్రాక్</translation>
+<translation id="6699343763173986273">మీడియా తరువాత ట్రాక్</translation>
<translation id="673773751041746814">తొలగింపు</translation>
<translation id="6786750046913594791">ఫోల్డర్‌ను మూసివేయండి</translation>
<translation id="6808150112686056157">మీడియా ఆపివేయి</translation>
@@ -145,7 +150,7 @@
<translation id="7410957453383678442">{MINUTES,plural, =1{1 నిమిషం మిగిలి ఉంది}other{# నిమిషాలు మిగిలి ఉన్నాయి}}</translation>
<translation id="7460907917090416791"><ph name="QUANTITY" /> TB</translation>
<translation id="7507604095951736240">ఎమోజి</translation>
-<translation id="7658239707568436148">రద్దు చెయ్యి</translation>
+<translation id="7658239707568436148">రద్దు చేయి</translation>
<translation id="7781829728241885113">నిన్న</translation>
<translation id="7814458197256864873">&amp;కాపీ</translation>
<translation id="7879499977785298635">బ్లాక్ చేయవద్దు</translation>
@@ -162,7 +167,7 @@
<translation id="8328145009876646418">ఎడమ హద్దు</translation>
<translation id="8331626408530291785">పైకి స్క్రోల్ చెయ్యి</translation>
<translation id="8352146631962686268">{YEARS,plural, =1{1 సంవత్సరం}other{# సంవత్సరాలు}}</translation>
-<translation id="838869780401515933">తనిఖీ చెయ్యి</translation>
+<translation id="838869780401515933">తనిఖీ చేయి</translation>
<translation id="8393700583063109961">సందేశాన్ని పంపండి</translation>
<translation id="8394908167088220973">మీడియా ప్లే/పాజ్</translation>
<translation id="8458811141851741261">{YEARS,plural, =1{1సం}other{#సం}}</translation>
@@ -173,7 +178,7 @@
<translation id="8772073294905169192">{HOURS,plural, =1{1గం}other{#గం}}</translation>
<translation id="8798099450830957504">డిఫాల్ట్</translation>
<translation id="8806053966018712535">ఫోల్డర్ <ph name="FOLDER_NAME" /></translation>
-<translation id="883911313571074303">చిత్రాన్ని అనులేఖించు</translation>
+<translation id="883911313571074303">చిత్రంపై అదనపు గమనికలు పంపండి</translation>
<translation id="8841375032071747811">వెనుకకు బటన్</translation>
<translation id="8901569739625249689"><ph name="QUANTITY" /> KB</translation>
<translation id="9002566407876343676">తెరువు</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_th.xtb b/chromium/ui/strings/translations/ui_strings_th.xtb
index 632f518ccd6..e9e24a31832 100644
--- a/chromium/ui/strings/translations/ui_strings_th.xtb
+++ b/chromium/ui/strings/translations/ui_strings_th.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">เลือก&amp;ทั้งหมด</translation>
+<translation id="1938451708255335766">หากต้องการปรับความหนาแน่นของการแสดงผลในหน้าต่าง ให้ปิดแอปแล้วเปิดใหม่</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 วัน}other{# วัน}}</translation>
<translation id="2148716181193084225">วันนี้</translation>
<translation id="2168039046890040389">เลื่อนหน้าขึ้น</translation>
<translation id="2190355936436201913">(ว่างเปล่า)</translation>
+<translation id="2192232475740621500">ใช้ความหนาแน่นต่ำ</translation>
<translation id="219905428774326614">Launcher, แอปทั้งหมด</translation>
<translation id="2267918077332197517">บล็อกการแจ้งเตือนทั้งหมดจากเว็บไซต์นี้</translation>
<translation id="2289052229480071835">แตะเป้าหมายการสัมผัสในหน้าจอ</translation>
<translation id="2295140143284145483">แบบสำรวจ</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/วินาที</translation>
<translation id="24452542372838207">ขยายการแจ้งเตือน</translation>
+<translation id="2445449901874883781">ใช้ความหนาแน่นสูง</translation>
<translation id="2482878487686419369">การแจ้งเตือน</translation>
<translation id="2497284189126895209">ไฟล์ทั้งหมด</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">ลูกศรลง</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 วัน}other{# วัน}}</translation>
<translation id="335581015389089642">คำพูด</translation>
+<translation id="3479552764303398839">ไม่ใช่ตอนนี้</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{เหลือ 1 วัน}other{เหลือ # วัน}}</translation>
<translation id="3618849550573277856">ค้นหา “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">เลือกโฟลเดอร์เพื่ออัปโหลด</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">ลูกศรซ้าย</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 นาที}other{# นาที}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 วันกับอีก }other{# วันกับอีก }}</translation>
+<translation id="5895138241574237353">ปิดแล้วเปิดอีกครั้ง</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{เหลือ 1 วินาที}other{เหลือ # วินาที}}</translation>
<translation id="5941711191222866238">ย่อ</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 ชั่วโมง}other{# ชั่วโมง}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_tr.xtb b/chromium/ui/strings/translations/ui_strings_tr.xtb
index 0d1d871005b..4fbb78c1c22 100644
--- a/chromium/ui/strings/translations/ui_strings_tr.xtb
+++ b/chromium/ui/strings/translations/ui_strings_tr.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652">%<ph name="NUMBER" /></translation>
<translation id="1901303067676059328">Tümünü &amp;seç</translation>
+<translation id="1938451708255335766">Pencerenin görüntü yoğunluğunu ayarlamak için uygulamayı yeniden başlatın.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 gün}other{# gün}}</translation>
<translation id="2148716181193084225">Bugün</translation>
<translation id="2168039046890040389">Page Up</translation>
<translation id="2190355936436201913">(boş)</translation>
+<translation id="2192232475740621500">Düşük yoğunluk kullan</translation>
<translation id="219905428774326614">Launcher, tüm uygulamalar</translation>
<translation id="2267918077332197517">Bu siteden gelen tüm bildirimleri engelle</translation>
<translation id="2289052229480071835">Ekranınızda dokunma hedeflerine dokunun.</translation>
<translation id="2295140143284145483">Anket</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/sn</translation>
<translation id="24452542372838207">Bildirimi genişlet</translation>
+<translation id="2445449901874883781">Yüksek yoğunluk kullan</translation>
<translation id="2482878487686419369">Bildirimler</translation>
<translation id="2497284189126895209">Tüm Dosyalar</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Aşağı Ok</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 gün}other{# gün}}</translation>
<translation id="335581015389089642">Konuşma</translation>
+<translation id="3479552764303398839">Şimdi değil</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{1 gün kaldı}other{# gün kaldı}}</translation>
<translation id="3618849550573277856">“<ph name="LOOKUP_STRING" />” Araması Yap</translation>
<translation id="364720409959344976">Yüklenecek Klasörü Seçin</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Sol Ok</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 dk.}other{# dk.}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 gün ve }other{# gün ve }}</translation>
+<translation id="5895138241574237353">Yeniden başlat</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{1 saniye kaldı}other{# saniye kaldı}}</translation>
<translation id="5941711191222866238">Simge durumuna küçült</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 saat}other{# saat}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_uk.xtb b/chromium/ui/strings/translations/ui_strings_uk.xtb
index bc3ffde91dc..c316037fcfd 100644
--- a/chromium/ui/strings/translations/ui_strings_uk.xtb
+++ b/chromium/ui/strings/translations/ui_strings_uk.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" />%</translation>
<translation id="1901303067676059328">Вибрати &amp;всі</translation>
+<translation id="1938451708255335766">Щоб налаштувати щільність показу вікон, перезапустіть додаток.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 д.}one{# д.}few{# дн.}many{# дн.}other{# дн.}}</translation>
<translation id="2148716181193084225">Сьогодні</translation>
<translation id="2168039046890040389">Сторінка вгору</translation>
<translation id="2190355936436201913">(пусто)</translation>
+<translation id="2192232475740621500">Використовувати низьку щільність</translation>
<translation id="219905428774326614">Панель запуску, усі додатки</translation>
<translation id="2267918077332197517">Блокувати всі сповіщення від цього сайту</translation>
<translation id="2289052229480071835">Торкніться елементів для дотику на екрані.</translation>
<translation id="2295140143284145483">Опитування</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> ТБ/сек.</translation>
<translation id="24452542372838207">Розгорнути сповіщення</translation>
+<translation id="2445449901874883781">Використовувати високу щільність</translation>
<translation id="2482878487686419369">Сповіщення</translation>
<translation id="2497284189126895209">Усі файли</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Курсор униз</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 день}one{# день}few{# дні}many{# днів}other{# дня}}</translation>
<translation id="335581015389089642">Speech</translation>
+<translation id="3479552764303398839">Не зараз</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Залишився 1 день}one{Залишився # день}few{Залишилося # дні}many{Залишилося # днів}other{Залишилося # дня}}</translation>
<translation id="3618849550573277856">Шукати "<ph name="LOOKUP_STRING" />"</translation>
<translation id="364720409959344976">Виберіть папку для завантаження</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Курсор ліворуч</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 хв}one{# хв}few{# хв}many{# хв}other{# хв}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 день і }one{# день і }few{# дні та }many{# днів і }other{# дня та }}</translation>
+<translation id="5895138241574237353">Перезапустити</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Залишилась 1 секунда}one{Залишилася # секунда}few{Залишилося # секунди}many{Залишилося # секунд}other{Залишилося # секунди}}</translation>
<translation id="5941711191222866238">Зменшити</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 година}one{# година}few{# години}many{# годин}other{# години}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_vi.xtb b/chromium/ui/strings/translations/ui_strings_vi.xtb
index ea8e3c7e21b..9ce6b423e11 100644
--- a/chromium/ui/strings/translations/ui_strings_vi.xtb
+++ b/chromium/ui/strings/translations/ui_strings_vi.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">Chọn &amp;tất cả</translation>
+<translation id="1938451708255335766">Để điều chỉnh mật độ hiển thị cửa sổ, hãy khởi động lại ứng dụng.</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 ngày}other{# ngày}}</translation>
<translation id="2148716181193084225">Hôm nay</translation>
<translation id="2168039046890040389">Page Up</translation>
<translation id="2190355936436201913">(trống)</translation>
+<translation id="2192232475740621500">Sử dụng mật độ thấp</translation>
<translation id="219905428774326614">Trình khởi chạy, tất cả ứng dụng</translation>
<translation id="2267918077332197517">Chặn tất cả thông báo từ trang web này</translation>
<translation id="2289052229480071835">Nhấn vào các mục tiêu cảm ứng trên màn hình của bạn.</translation>
<translation id="2295140143284145483">Khảo sát</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/giây</translation>
<translation id="24452542372838207">Mở rộng thông báo</translation>
+<translation id="2445449901874883781">Sử dụng mật độ cao</translation>
<translation id="2482878487686419369">Thông báo</translation>
<translation id="2497284189126895209">Tất cả Tệp tin</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">Phím mũi tên Xuống</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 ngày}other{# ngày}}</translation>
<translation id="335581015389089642">Giọng nói</translation>
+<translation id="3479552764303398839">Không phải bây giờ</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{Còn 1 ngày}other{Còn # ngày}}</translation>
<translation id="3618849550573277856">Tra cứu “<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">Chọn thư mục để tải lên</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">Mũi tên trái</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 phút}other{# phút}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 ngày và }other{# ngày và }}</translation>
+<translation id="5895138241574237353">Khởi động lại</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{Còn 1 giây}other{Còn # giây}}</translation>
<translation id="5941711191222866238">Thu nhỏ</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 giờ}other{# giờ}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
index 2d61a32c8e8..c1d9d8271a7 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-CN.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">全选(&amp;A)</translation>
+<translation id="1938451708255335766">要调整窗口显示密度,请重启该应用。</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 天}other{# 天}}</translation>
<translation id="2148716181193084225">今天</translation>
<translation id="2168039046890040389">向上翻页</translation>
<translation id="2190355936436201913">(空)</translation>
+<translation id="2192232475740621500">使用低密度</translation>
<translation id="219905428774326614">启动器,所有应用</translation>
<translation id="2267918077332197517">屏蔽来自此网站的所有通知</translation>
<translation id="2289052229480071835">点按您屏幕上的触摸目标。</translation>
<translation id="2295140143284145483">调查问卷</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/s</translation>
<translation id="24452542372838207">展开通知</translation>
+<translation id="2445449901874883781">使用高密度</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2497284189126895209">所有文件</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">向下箭头</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 天}other{# 天}}</translation>
<translation id="335581015389089642">语音</translation>
+<translation id="3479552764303398839">以后再说</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{还剩 1 天}other{还剩 # 天}}</translation>
<translation id="3618849550573277856">查询“<ph name="LOOKUP_STRING" />”</translation>
<translation id="364720409959344976">选择要上传的文件夹</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">向左箭头</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 分钟}other{# 分钟}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 天 }other{# 天 }}</translation>
+<translation id="5895138241574237353">重新启动</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{还剩 1 秒}other{还剩 # 秒}}</translation>
<translation id="5941711191222866238">最小化</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 小时}other{# 小时}}</translation>
diff --git a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
index 4ef0487a835..0f39485f684 100644
--- a/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
+++ b/chromium/ui/strings/translations/ui_strings_zh-TW.xtb
@@ -30,16 +30,19 @@
<translation id="1871244248791675517">Ins</translation>
<translation id="1884435127456172652"><ph name="NUMBER" /> %</translation>
<translation id="1901303067676059328">選取全部(&amp;A)</translation>
+<translation id="1938451708255335766">如要調整視窗顯示密度,請重新啟動應用程式。</translation>
<translation id="2141853158323869627">{DAYS,plural, =1{1 天}other{# 天}}</translation>
<translation id="2148716181193084225">今天</translation>
<translation id="2168039046890040389">向上翻頁</translation>
<translation id="2190355936436201913">(空白)</translation>
+<translation id="2192232475740621500">使用低密度模式</translation>
<translation id="219905428774326614">啟動器,所有應用程式</translation>
<translation id="2267918077332197517">一律封鎖來自這個網站的通知</translation>
<translation id="2289052229480071835">輕觸畫面上的觸控目標。</translation>
<translation id="2295140143284145483">問卷調查</translation>
<translation id="2297836609126180313"><ph name="QUANTITY" /> TB/秒</translation>
<translation id="24452542372838207">展開通知</translation>
+<translation id="2445449901874883781">使用高密度模式</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2497284189126895209">所有檔案</translation>
<translation id="2515586267016047495">Alt</translation>
@@ -60,6 +63,7 @@
<translation id="3234408098842461169">向下鍵</translation>
<translation id="3291688615589870984">{DAYS,plural, =1{1 天}other{# 天}}</translation>
<translation id="335581015389089642">語音</translation>
+<translation id="3479552764303398839">現在不要</translation>
<translation id="3600566671520689681">{DAYS,plural, =1{還剩 1 天}other{還剩 # 天}}</translation>
<translation id="3618849550573277856">查詢「<ph name="LOOKUP_STRING" />」</translation>
<translation id="364720409959344976">選取要上傳的資料夾</translation>
@@ -99,6 +103,7 @@
<translation id="5613020302032141669">向左鍵</translation>
<translation id="5754277640426581776">{MINUTES,plural, =1{1 分鐘}other{# 分鐘}}</translation>
<translation id="5768079895599174203">{DAYS,plural, =1{1 天 }other{# 天 }}</translation>
+<translation id="5895138241574237353">重新啟動</translation>
<translation id="5906667377645263094">{SECONDS,plural, =1{還剩 1 秒}other{還剩 # 秒}}</translation>
<translation id="5941711191222866238">縮到最小</translation>
<translation id="5943826764092288734">{HOURS,plural, =1{1 小時}other{# 小時}}</translation>
@@ -158,7 +163,7 @@
<translation id="8179976553408161302">Enter</translation>
<translation id="8210608804940886430">向下翻頁</translation>
<translation id="8245914219290430011">Tab 鍵</translation>
-<translation id="8259556432390118667">16 進位色彩值</translation>
+<translation id="8259556432390118667">十六進位顏色值</translation>
<translation id="8328145009876646418">左邊緣</translation>
<translation id="8331626408530291785">向上捲動</translation>
<translation id="8352146631962686268">{YEARS,plural, =1{1 年}other{# 年}}</translation>
diff --git a/chromium/ui/strings/ui_strings.grd b/chromium/ui/strings/ui_strings.grd
index d82bf2ff6ce..146d3fe1988 100644
--- a/chromium/ui/strings/ui_strings.grd
+++ b/chromium/ui/strings/ui_strings.grd
@@ -840,6 +840,23 @@ need to be translated for each locale.-->
<message name="IDS_DISPLAY_NAME_INTERNAL" desc="The name used for internal displays, which is shown in the display settings.">
Internal Display
</message>
+
+ <!-- Crostini app context menu item names, dialog message and button strings -->
+ <message name="IDS_CROSTINI_USE_LOW_DENSITY" desc="The Crostini app Shelf item context menu item to use low display density for app windows.">
+ Use low density
+ </message>
+ <message name="IDS_CROSTINI_USE_HIGH_DENSITY" desc="The Crostini app Shelf item context menu item to use high display density for app windows.">
+ Use high density
+ </message>
+ <message name="IDS_CROSTINI_APP_RESTART_BODY" desc="Description for the Crostini app restart dialog.">
+ To adjust the window display density, restart the app.
+ </message>
+ <message name="IDS_CROSTINI_APP_RESTART_BUTTON" desc="Label for the button in the Crostini app restart dialog to restart an app.">
+ Restart
+ </message>
+ <message name="IDS_CROSTINI_NOT_NOW_BUTTON" desc="Label for the button in the Crostini app restart dialog to dismiss the dialog.">
+ Not now
+ </message>
</messages>
</release>
</grit>
diff --git a/chromium/ui/surface/transport_dib_win.cc b/chromium/ui/surface/transport_dib_win.cc
index b1069ae1bde..a1382d31262 100644
--- a/chromium/ui/surface/transport_dib_win.cc
+++ b/chromium/ui/surface/transport_dib_win.cc
@@ -12,7 +12,7 @@
#include <memory>
#include "base/logging.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "skia/ext/platform_canvas.h"
TransportDIB::TransportDIB()
diff --git a/chromium/ui/touch_selection/touch_selection_menu_runner.h b/chromium/ui/touch_selection/touch_selection_menu_runner.h
index f4e05da49bd..c82e05ebd51 100644
--- a/chromium/ui/touch_selection/touch_selection_menu_runner.h
+++ b/chromium/ui/touch_selection/touch_selection_menu_runner.h
@@ -6,6 +6,7 @@
#define UI_TOUCH_SELECTION_TOUCH_SELECTION_MENU_RUNNER_H_
#include "base/macros.h"
+#include "base/strings/string_util.h"
#include "ui/touch_selection/ui_touch_selection_export.h"
namespace aura {
@@ -32,6 +33,12 @@ class UI_TOUCH_SELECTION_EXPORT TouchSelectionMenuClient {
// menu to show up in which case the menu will run asynchronously at a later
// time.
virtual void RunContextMenu() = 0;
+
+ // Whether the Quick Menu should be opened.
+ virtual bool ShouldShowQuickMenu() = 0;
+
+ // Returns the current text selection.
+ virtual base::string16 GetSelectedText() = 0;
};
// An interface for the singleton object responsible for running touch selection
diff --git a/chromium/ui/views/BUILD.gn b/chromium/ui/views/BUILD.gn
index b7fa6d3073c..a1868f58cfc 100644
--- a/chromium/ui/views/BUILD.gn
+++ b/chromium/ui/views/BUILD.gn
@@ -59,6 +59,9 @@ jumbo_component("views") {
"../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/ax_event_manager.h",
+ "accessibility/ax_event_observer.h",
+ "accessibility/ax_virtual_view.h",
"accessibility/view_accessibility.h",
"accessibility/view_accessibility_utils.h",
"accessible_pane_view.h",
@@ -69,7 +72,6 @@ jumbo_component("views") {
"animation/ink_drop_animation_ended_reason.h",
"animation/ink_drop_highlight.h",
"animation/ink_drop_highlight_observer.h",
- "animation/ink_drop_host.h",
"animation/ink_drop_host_view.h",
"animation/ink_drop_impl.h",
"animation/ink_drop_mask.h",
@@ -91,12 +93,11 @@ jumbo_component("views") {
"bubble/tooltip_icon.h",
"button_drag_utils.h",
"cocoa/bridge_factory_host.h",
+ "cocoa/bridged_native_widget_host_impl.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",
"controls/button/image_button.h",
@@ -105,6 +106,7 @@ jumbo_component("views") {
"controls/button/label_button_border.h",
"controls/button/md_text_button.h",
"controls/button/menu_button.h",
+ "controls/button/menu_button_event_handler.h",
"controls/button/menu_button_listener.h",
"controls/button/radio_button.h",
"controls/button/toggle_button.h",
@@ -207,7 +209,6 @@ jumbo_component("views") {
"native_theme_delegate.h",
"paint_info.h",
"painter.h",
- "pointer_watcher.h",
"rect_based_targeting_utils.h",
"repeat_controller.h",
"round_rect_painter.h",
@@ -244,6 +245,7 @@ jumbo_component("views") {
"widget/widget_deletion_observer.h",
"widget/widget_observer.h",
"widget/widget_removals_observer.h",
+ "widget/widget_utils.h",
"widget/widget_utils_mac.h",
"window/client_view.h",
"window/custom_frame_view.h",
@@ -266,6 +268,9 @@ jumbo_component("views") {
# 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/ax_event_manager.cc",
+ "accessibility/ax_event_observer.cc",
+ "accessibility/ax_virtual_view.cc",
"accessibility/view_accessibility.cc",
"accessibility/view_accessibility_utils.cc",
"accessible_pane_view.cc",
@@ -289,13 +294,12 @@ jumbo_component("views") {
"bubble/bubble_border.cc",
"bubble/bubble_dialog_delegate_view.cc",
"bubble/bubble_frame_view.cc",
+ "bubble/footnote_container_view.cc",
"bubble/info_bubble.cc",
"bubble/tooltip_icon.cc",
"button_drag_utils.cc",
"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",
"controls/button/image_button.cc",
@@ -304,6 +308,7 @@ jumbo_component("views") {
"controls/button/label_button_border.cc",
"controls/button/md_text_button.cc",
"controls/button/menu_button.cc",
+ "controls/button/menu_button_event_handler.cc",
"controls/button/radio_button.cc",
"controls/button/toggle_button.cc",
"controls/combobox/combobox.cc",
@@ -413,7 +418,6 @@ jumbo_component("views") {
"view_targeter_delegate.cc",
"view_tracker.cc",
"views_delegate.cc",
- "views_exports.cc",
"views_switches.cc",
"views_touch_selection_controller_factory_mac.cc",
"widget/drop_helper.cc",
@@ -426,6 +430,7 @@ jumbo_component("views") {
"widget/widget_aura_utils.cc",
"widget/widget_delegate.cc",
"widget/widget_deletion_observer.cc",
+ "widget/widget_utils.cc",
"widget/widget_utils_mac.mm",
"window/client_view.cc",
"window/custom_frame_view.cc",
@@ -451,14 +456,17 @@ jumbo_component("views") {
"../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/browser_native_widget_window_mac.h",
+ "../views_bridge_mac/browser_native_widget_window_mac.mm",
"../views_bridge_mac/cocoa_window_move_loop.h",
"../views_bridge_mac/cocoa_window_move_loop.mm",
+ "../views_bridge_mac/native_widget_mac_frameless_nswindow.h",
+ "../views_bridge_mac/native_widget_mac_frameless_nswindow.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/drag_drop_client_mac.h",
"cocoa/drag_drop_client_mac.mm",
@@ -520,6 +528,7 @@ jumbo_component("views") {
if (use_x11) {
deps += [ "//ui/display/util" ]
}
+
if (is_linux && !is_chromeos) {
sources -= [ "window/window_button_order_provider.cc" ]
deps += [ "//ui/shell_dialogs" ]
@@ -579,6 +588,7 @@ jumbo_component("views") {
if (use_ozone) {
deps += [ "//ui/ozone" ]
}
+
if (use_x11) {
configs += [
"//build/config/linux:x11",
@@ -610,6 +620,7 @@ jumbo_component("views") {
"event_monitor_aura.h",
"touchui/touch_selection_controller_impl.h",
"touchui/touch_selection_menu_runner_views.h",
+ "touchui/touch_selection_menu_views.h",
"view_constants_aura.h",
"widget/desktop_aura/desktop_capture_client.h",
"widget/desktop_aura/desktop_drop_target_win.h",
@@ -625,6 +636,7 @@ jumbo_component("views") {
"widget/tooltip_manager_aura.h",
"widget/window_reorderer.h",
]
+
sources += [
"accessibility/ax_aura_obj_cache.cc",
"accessibility/ax_aura_obj_wrapper.cc",
@@ -647,6 +659,7 @@ jumbo_component("views") {
"native_cursor_aura.cc",
"touchui/touch_selection_controller_impl.cc",
"touchui/touch_selection_menu_runner_views.cc",
+ "touchui/touch_selection_menu_views.cc",
"view_constants_aura.cc",
"views_touch_selection_controller_factory_aura.cc",
"widget/desktop_aura/desktop_capture_client.cc",
@@ -665,6 +678,7 @@ jumbo_component("views") {
deps += [
"//services/ws/public/mojom",
"//ui/aura",
+ "//ui/events",
"//ui/platform_window",
"//ui/platform_window/platform_window_handler",
"//ui/touch_selection",
@@ -715,8 +729,12 @@ jumbo_component("views") {
]
deps += [ "//ui/events:dom_keyboard_layout" ]
} else if (use_ozone) {
- public += [ "widget/desktop_aura/desktop_screen_ozone.h" ]
- sources += [ "widget/desktop_aura/desktop_screen_ozone.cc" ]
+ sources += [
+ "widget/desktop_aura/desktop_drag_drop_client_ozone.cc",
+ "widget/desktop_aura/desktop_drag_drop_client_ozone.h",
+ "widget/desktop_aura/desktop_screen_ozone.cc",
+ "widget/desktop_aura/desktop_screen_ozone.h",
+ ]
}
if (is_linux) {
sources += [
@@ -958,7 +976,6 @@ source_set("views_unittests_sources") {
"cocoa/bridged_native_widget_unittest.mm",
"cocoa/cocoa_mouse_capture_unittest.mm",
"cocoa/drag_drop_client_mac_unittest.mm",
- "controls/button/blue_button_unittest.cc",
"controls/button/button_unittest.cc",
"controls/button/checkbox_unittest.cc",
"controls/button/image_button_factory_unittest.cc",
@@ -976,6 +993,7 @@ source_set("views_unittests_sources") {
"controls/menu/menu_model_adapter_unittest.cc",
"controls/menu/menu_runner_cocoa_unittest.mm",
"controls/menu/menu_runner_unittest.cc",
+ "controls/menu/submenu_view_unittest.cc",
"controls/native/native_view_host_mac_unittest.mm",
"controls/native/native_view_host_test_base.cc",
"controls/native/native_view_host_test_base.h",
@@ -1085,7 +1103,10 @@ source_set("views_unittests_sources") {
}
if (has_native_accessibility) {
- sources += [ "accessibility/view_ax_platform_node_delegate_unittest.cc" ]
+ sources += [
+ "accessibility/ax_virtual_view_unittest.cc",
+ "accessibility/view_ax_platform_node_delegate_unittest.cc",
+ ]
}
if (use_x11) {
@@ -1168,8 +1189,10 @@ test("views_unittests") {
}
if (is_linux && !is_chromeos && !use_x11) {
- sources +=
- [ "widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc" ]
+ sources += [
+ "widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc",
+ "widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc",
+ ]
}
if (!is_chromeos) {
@@ -1180,6 +1203,7 @@ test("views_unittests") {
":test_support",
":views_unittests_sources",
"//mojo/core/embedder",
+ "//ui/platform_window/platform_window_handler",
]
}
@@ -1233,7 +1257,7 @@ source_set("views_interactive_ui_tests") {
"//ui/wm/public",
]
- if (!is_chromeos && ((is_linux && !use_x11) || is_fuchsia)) {
+ if (!is_chromeos && (is_linux && !use_x11)) {
sources += [ "widget/desktop_aura/desktop_window_tree_host_platform_interactive_uitest.cc" ]
}
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
index 5811bf26790..7c840f00b9a 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/chromium/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -208,7 +208,7 @@ AXAuraObjWrapper* AXAuraObjCache::CreateInternal(
return Get(it->second);
auto wrapper = std::make_unique<AuraViewWrapper>(aura_view);
- int32_t id = wrapper->GetUniqueId().Get();
+ int32_t id = wrapper->GetUniqueId();
aura_view_to_id_map[aura_view] = id;
cache_[id] = std::move(wrapper);
return cache_[id].get();
diff --git a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
index fa0f7954116..5ce9d6c31f5 100644
--- a/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_aura_obj_wrapper.h
@@ -17,7 +17,6 @@
namespace ui {
struct AXActionData;
struct AXNodeData;
-class AXUniqueId;
} // namespace ui
namespace views {
@@ -36,7 +35,7 @@ class VIEWS_EXPORT AXAuraObjWrapper {
virtual void GetChildren(
std::vector<AXAuraObjWrapper*>* out_children) = 0;
virtual void Serialize(ui::AXNodeData* out_node_data) = 0;
- virtual const ui::AXUniqueId& GetUniqueId() const = 0;
+ virtual int32_t GetUniqueId() const = 0;
// Actions.
virtual bool HandleAccessibleAction(const ui::AXActionData& action);
diff --git a/chromium/ui/views/accessibility/ax_event_manager.cc b/chromium/ui/views/accessibility/ax_event_manager.cc
new file mode 100644
index 00000000000..7e1fd0f3f97
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_event_manager.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/accessibility/ax_event_manager.h"
+
+#include "base/no_destructor.h"
+#include "ui/views/accessibility/ax_event_observer.h"
+
+namespace views {
+
+AXEventManager::AXEventManager() = default;
+
+AXEventManager::~AXEventManager() = default;
+
+// static
+AXEventManager* AXEventManager::Get() {
+ static base::NoDestructor<AXEventManager> instance;
+ return instance.get();
+}
+
+void AXEventManager::AddObserver(AXEventObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void AXEventManager::RemoveObserver(AXEventObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void AXEventManager::NotifyViewEvent(views::View* view,
+ ax::mojom::Event event_type) {
+ for (AXEventObserver& observer : observers_)
+ observer.OnViewEvent(view, event_type);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_event_manager.h b/chromium/ui/views/accessibility/ax_event_manager.h
new file mode 100644
index 00000000000..6eef3ef2820
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_event_manager.h
@@ -0,0 +1,41 @@
+// 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_EVENT_MANAGER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_EVENT_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class AXEventObserver;
+class View;
+
+// AXEventManager allows observation of accessibility events for all views.
+class VIEWS_EXPORT AXEventManager {
+ public:
+ AXEventManager();
+ ~AXEventManager();
+
+ // Returns the singleton instance.
+ static AXEventManager* Get();
+
+ void AddObserver(AXEventObserver* observer);
+ void RemoveObserver(AXEventObserver* observer);
+
+ // Notifies observers of an accessibility event. |view| must not be null.
+ void NotifyViewEvent(views::View* view, ax::mojom::Event event_type);
+
+ private:
+ base::ObserverList<AXEventObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXEventManager);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_EVENT_MANAGER_H_
diff --git a/chromium/ui/views/accessibility/ax_event_observer.cc b/chromium/ui/views/accessibility/ax_event_observer.cc
new file mode 100644
index 00000000000..cc1db79d83e
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_event_observer.cc
@@ -0,0 +1,13 @@
+// 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_event_observer.h"
+
+namespace views {
+
+AXEventObserver::AXEventObserver() = default;
+
+AXEventObserver::~AXEventObserver() = default;
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_event_observer.h b/chromium/ui/views/accessibility/ax_event_observer.h
new file mode 100644
index 00000000000..5fc3c812888
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_event_observer.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_AX_EVENT_OBSERVER_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_EVENT_OBSERVER_H_
+
+#include "base/observer_list_types.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+class View;
+
+// AXEventObserver is notified for accessibility events on all views.
+class VIEWS_EXPORT AXEventObserver : public base::CheckedObserver {
+ public:
+ virtual void OnViewEvent(views::View* view, ax::mojom::Event event_type) = 0;
+
+ protected:
+ AXEventObserver();
+ ~AXEventObserver() override;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_EVENT_OBSERVER_H_
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
index 8f16302c7cb..c9327cbb09a 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.cc
@@ -10,6 +10,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/platform/ax_unique_id.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/display/display.h"
@@ -98,8 +99,8 @@ void AXRootObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
#endif
}
-const ui::AXUniqueId& AXRootObjWrapper::GetUniqueId() const {
- return unique_id_;
+int32_t AXRootObjWrapper::GetUniqueId() const {
+ return unique_id_.Get();
}
void AXRootObjWrapper::OnDisplayMetricsChanged(const display::Display& display,
diff --git a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
index f90f9853dab..7f0ca125bf6 100644
--- a/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_root_obj_wrapper.h
@@ -37,7 +37,7 @@ class VIEWS_EXPORT AXRootObjWrapper : public views::AXAuraObjWrapper,
void GetChildren(
std::vector<views::AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- const ui::AXUniqueId& GetUniqueId() const override;
+ int32_t GetUniqueId() const override;
private:
// display::DisplayObserver:
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.cc b/chromium/ui/views/accessibility/ax_tree_source_views.cc
index cffc41f79b3..7f9231b8c53 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.cc
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.cc
@@ -7,6 +7,8 @@
#include <vector>
#include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/transform.h"
@@ -34,24 +36,29 @@ void AXTreeSourceViews::HandleAccessibleAction(const ui::AXActionData& action) {
}
bool AXTreeSourceViews::GetTreeData(ui::AXTreeData* tree_data) const {
+ tree_data->tree_id = tree_id_;
tree_data->loaded = true;
tree_data->loading_progress = 1.0;
AXAuraObjWrapper* focus = AXAuraObjCache::GetInstance()->GetFocus();
if (focus)
- tree_data->focus_id = focus->GetUniqueId().Get();
+ tree_data->focus_id = focus->GetUniqueId();
return true;
}
+AXAuraObjWrapper* AXTreeSourceViews::GetRoot() const {
+ return root_;
+}
+
AXAuraObjWrapper* AXTreeSourceViews::GetFromId(int32_t id) const {
AXAuraObjWrapper* root = GetRoot();
// Root might not be in the cache.
- if (id == root->GetUniqueId().Get())
+ if (id == root->GetUniqueId())
return root;
return AXAuraObjCache::GetInstance()->Get(id);
}
int32_t AXTreeSourceViews::GetId(AXAuraObjWrapper* node) const {
- return node->GetUniqueId().Get();
+ return node->GetUniqueId();
}
void AXTreeSourceViews::GetChildren(
@@ -99,8 +106,9 @@ void AXTreeSourceViews::SerializeNode(AXAuraObjWrapper* node,
return;
ui::AXNodeData parent_data;
parent->Serialize(&parent_data);
- out_data->location.Offset(-parent_data.location.OffsetFromOrigin());
- out_data->offset_container_id = parent->GetUniqueId().Get();
+ out_data->relative_bounds.bounds.Offset(
+ -parent_data.relative_bounds.bounds.OffsetFromOrigin());
+ out_data->relative_bounds.offset_container_id = parent->GetUniqueId();
}
std::string AXTreeSourceViews::ToString(AXAuraObjWrapper* root,
@@ -123,4 +131,12 @@ AXTreeSourceViews::AXTreeSourceViews() = default;
AXTreeSourceViews::~AXTreeSourceViews() = default;
+void AXTreeSourceViews::Init(AXAuraObjWrapper* root,
+ const ui::AXTreeID& tree_id) {
+ DCHECK(root);
+ DCHECK_NE(tree_id, ui::AXTreeIDUnknown());
+ root_ = root;
+ tree_id_ = tree_id;
+}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views.h b/chromium/ui/views/accessibility/ax_tree_source_views.h
index 1f50c3adddb..d7554c0abdf 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views.h
+++ b/chromium/ui/views/accessibility/ax_tree_source_views.h
@@ -6,13 +6,14 @@
#define UI_VIEWS_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_
#include "base/macros.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_source.h"
#include "ui/views/views_export.h"
namespace ui {
struct AXActionData;
+struct AXNodeData;
+struct AXTreeData;
}
namespace views {
@@ -33,7 +34,7 @@ class VIEWS_EXPORT AXTreeSourceViews
// AXTreeSource:
bool GetTreeData(ui::AXTreeData* data) const override;
- // GetRoot() must be implemented by subclasses.
+ AXAuraObjWrapper* GetRoot() const override;
AXAuraObjWrapper* GetFromId(int32_t id) const override;
int32_t GetId(AXAuraObjWrapper* node) const override;
void GetChildren(AXAuraObjWrapper* node,
@@ -52,7 +53,15 @@ class VIEWS_EXPORT AXTreeSourceViews
AXTreeSourceViews();
~AXTreeSourceViews() override;
+ void Init(AXAuraObjWrapper* root, const ui::AXTreeID& tree_id);
+
private:
+ // The top-level object to use for the AX tree. See class comment.
+ AXAuraObjWrapper* root_ = nullptr;
+
+ // ID to use for the AX tree.
+ ui::AXTreeID tree_id_;
+
DISALLOW_COPY_AND_ASSIGN(AXTreeSourceViews);
};
diff --git a/chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc b/chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc
index 82f6f53a8e5..05a8dcb682e 100644
--- a/chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc
+++ b/chromium/ui/views/accessibility/ax_tree_source_views_unittest.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
@@ -22,17 +23,16 @@
namespace views {
namespace {
-// TestAXTreeSourceViews provides a root object for testing.
+// TestAXTreeSourceViews provides a root with a default tree ID.
class TestAXTreeSourceViews : public AXTreeSourceViews {
public:
- TestAXTreeSourceViews(AXAuraObjWrapper* root) : root_(root) {}
- ~TestAXTreeSourceViews() override = default;
+ TestAXTreeSourceViews(AXAuraObjWrapper* root) {
+ Init(root, ui::AXTreeID::FromString("123"));
+ }
- // AXTreeSource:
- AXAuraObjWrapper* GetRoot() const override { return root_; }
+ ~TestAXTreeSourceViews() override = default;
private:
- AXAuraObjWrapper* root_;
DISALLOW_COPY_AND_ASSIGN(TestAXTreeSourceViews);
};
@@ -71,8 +71,8 @@ class AXTreeSourceViewsTest : public ViewsTestBase {
}
std::unique_ptr<Widget> widget_;
- Label* label1_ = nullptr; // Owned by views hierarchy.
- Label* label2_ = nullptr; // Owned by views hierarchy.
+ Label* label1_ = nullptr; // Owned by views hierarchy.
+ Label* label2_ = nullptr; // Owned by views hierarchy.
Textfield* textfield_ = nullptr; // Owned by views hierarchy.
private:
@@ -109,16 +109,16 @@ TEST_F(AXTreeSourceViewsTest, Basics) {
EXPECT_EQ(root, tree.GetParent(textfield));
// IDs match the ones in the cache.
- EXPECT_EQ(root->GetUniqueId().Get(), tree.GetId(root));
- EXPECT_EQ(label1->GetUniqueId().Get(), tree.GetId(label1));
- EXPECT_EQ(label2->GetUniqueId().Get(), tree.GetId(label2));
- EXPECT_EQ(textfield->GetUniqueId().Get(), tree.GetId(textfield));
+ EXPECT_EQ(root->GetUniqueId(), tree.GetId(root));
+ EXPECT_EQ(label1->GetUniqueId(), tree.GetId(label1));
+ EXPECT_EQ(label2->GetUniqueId(), tree.GetId(label2));
+ EXPECT_EQ(textfield->GetUniqueId(), tree.GetId(textfield));
// Reverse ID lookups work.
- EXPECT_EQ(root, tree.GetFromId(root->GetUniqueId().Get()));
- EXPECT_EQ(label1, tree.GetFromId(label1->GetUniqueId().Get()));
- EXPECT_EQ(label2, tree.GetFromId(label2->GetUniqueId().Get()));
- EXPECT_EQ(textfield, tree.GetFromId(textfield->GetUniqueId().Get()));
+ EXPECT_EQ(root, tree.GetFromId(root->GetUniqueId()));
+ EXPECT_EQ(label1, tree.GetFromId(label1->GetUniqueId()));
+ EXPECT_EQ(label2, tree.GetFromId(label2->GetUniqueId()));
+ EXPECT_EQ(textfield, tree.GetFromId(textfield->GetUniqueId()));
// Validity.
EXPECT_TRUE(tree.IsValid(root));
@@ -147,7 +147,7 @@ TEST_F(AXTreeSourceViewsTest, GetTreeDataWithFocus) {
TEST_F(AXTreeSourceViewsTest, IgnoredView) {
View* ignored_view = new View();
- ignored_view->GetViewAccessibility().set_is_ignored(true);
+ ignored_view->GetViewAccessibility().OverrideIsIgnored(true);
widget_->GetContentsView()->AddChildView(ignored_view);
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
index 4d1a9867730..d8c900efa8c 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -6,6 +6,7 @@
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/view.h"
@@ -16,15 +17,24 @@ namespace views {
AXViewObjWrapper::AXViewObjWrapper(View* view) : view_(view) {
if (view->GetWidget())
AXAuraObjCache::GetInstance()->GetOrCreate(view->GetWidget());
+ view->AddObserver(this);
}
-AXViewObjWrapper::~AXViewObjWrapper() {}
+AXViewObjWrapper::~AXViewObjWrapper() {
+ if (view_) {
+ view_->RemoveObserver(this);
+ view_ = nullptr;
+ }
+}
bool AXViewObjWrapper::IsIgnored() {
- return view_->GetViewAccessibility().is_ignored();
+ return view_ ? view_->GetViewAccessibility().IsIgnored() : true;
}
AXAuraObjWrapper* AXViewObjWrapper::GetParent() {
+ if (!view_)
+ return nullptr;
+
AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
if (view_->parent())
return cache->GetOrCreate(view_->parent());
@@ -37,6 +47,9 @@ AXAuraObjWrapper* AXViewObjWrapper::GetParent() {
void AXViewObjWrapper::GetChildren(
std::vector<AXAuraObjWrapper*>* out_children) {
+ if (!view_)
+ return;
+
if (view_->GetViewAccessibility().IsLeaf())
return;
@@ -52,16 +65,23 @@ void AXViewObjWrapper::GetChildren(
}
void AXViewObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
+ if (!view_)
+ return;
+
view_->GetViewAccessibility().GetAccessibleNodeData(out_node_data);
- out_node_data->id = GetUniqueId().Get();
+ out_node_data->id = GetUniqueId();
}
-const ui::AXUniqueId& AXViewObjWrapper::GetUniqueId() const {
- return view_->GetViewAccessibility().GetUniqueId();
+int32_t AXViewObjWrapper::GetUniqueId() const {
+ return view_ ? view_->GetViewAccessibility().GetUniqueId() : -1;
}
bool AXViewObjWrapper::HandleAccessibleAction(const ui::AXActionData& action) {
- return view_->HandleAccessibleAction(action);
+ return view_ ? view_->HandleAccessibleAction(action) : false;
+}
+
+void AXViewObjWrapper::OnViewIsDeleting(View* observed_view) {
+ view_ = nullptr;
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
index eff142fc74b..5a160307c47 100644
--- a/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -9,12 +9,13 @@
#include "base/macros.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/view_observer.h"
namespace views {
class View;
// Describes a |View| for use with other AX classes.
-class AXViewObjWrapper : public AXAuraObjWrapper {
+class AXViewObjWrapper : public AXAuraObjWrapper, public ViewObserver {
public:
explicit AXViewObjWrapper(View* view);
~AXViewObjWrapper() override;
@@ -26,11 +27,14 @@ class AXViewObjWrapper : public AXAuraObjWrapper {
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- const ui::AXUniqueId& GetUniqueId() const final;
+ int32_t GetUniqueId() const final;
bool HandleAccessibleAction(const ui::AXActionData& action) override;
+ // ViewObserver overrides.
+ void OnViewIsDeleting(View* observed_view) override;
+
private:
- View* const view_;
+ View* view_;
DISALLOW_COPY_AND_ASSIGN(AXViewObjWrapper);
};
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.cc b/chromium/ui/views/accessibility/ax_virtual_view.cc
new file mode 100644
index 00000000000..f6519a599e2
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_virtual_view.cc
@@ -0,0 +1,281 @@
+// 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_virtual_view.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+// static
+const char AXVirtualView::kViewClassName[] = "AXVirtualView";
+
+AXVirtualView::AXVirtualView()
+ : parent_view_(nullptr), virtual_parent_view_(nullptr) {
+ ax_platform_node_ = ui::AXPlatformNode::Create(this);
+ DCHECK(ax_platform_node_);
+ custom_data_.AddStringAttribute(ax::mojom::StringAttribute::kClassName,
+ GetViewClassName());
+}
+
+AXVirtualView::~AXVirtualView() {
+ DCHECK(!parent_view_ || !virtual_parent_view_)
+ << "Either |parent_view_| or |virtual_parent_view_| could be set but "
+ "not both.";
+
+ if (ax_platform_node_) {
+ ax_platform_node_->Destroy();
+ ax_platform_node_ = nullptr;
+ }
+}
+
+void AXVirtualView::AddChildView(std::unique_ptr<AXVirtualView> view) {
+ DCHECK(view);
+ if (view->virtual_parent_view_ == this)
+ return;
+ AddChildViewAt(std::move(view), GetChildCount());
+}
+
+void AXVirtualView::AddChildViewAt(std::unique_ptr<AXVirtualView> view,
+ int index) {
+ DCHECK(view);
+ CHECK_NE(view.get(), this)
+ << "You cannot add an AXVirtualView as its own child.";
+ DCHECK(!view->parent_view_) << "This |view| already has a View "
+ "parent. Call RemoveVirtualChildView first.";
+ DCHECK(!view->virtual_parent_view_) << "This |view| already has an "
+ "AXVirtualView parent. Call "
+ "RemoveChildView first.";
+ DCHECK_GE(index, 0);
+ DCHECK_LE(index, GetChildCount());
+
+ view->virtual_parent_view_ = this;
+ children_.insert(children_.begin() + index, std::move(view));
+}
+
+void AXVirtualView::ReorderChildView(AXVirtualView* view, int index) {
+ DCHECK(view);
+ if (index >= GetChildCount())
+ return;
+ if (index < 0)
+ index = GetChildCount() - 1;
+
+ DCHECK_EQ(view->virtual_parent_view_, this);
+ if (children_[index].get() == view)
+ return;
+
+ int cur_index = GetIndexOf(view);
+ if (cur_index < 0)
+ return;
+
+ std::unique_ptr<AXVirtualView> child = std::move(children_[cur_index]);
+ children_.erase(children_.begin() + cur_index);
+ children_.insert(children_.begin() + index, std::move(child));
+}
+
+std::unique_ptr<AXVirtualView> AXVirtualView::RemoveChildView(
+ AXVirtualView* view) {
+ DCHECK(view);
+ int cur_index = GetIndexOf(view);
+ if (cur_index < 0)
+ return {};
+
+ if (GetOwnerView()) {
+ ViewAccessibility& view_accessibility =
+ GetOwnerView()->GetViewAccessibility();
+ if (view_accessibility.FocusedVirtualChild() &&
+ Contains(view_accessibility.FocusedVirtualChild())) {
+ view_accessibility.OverrideFocus(nullptr);
+ }
+ }
+
+ std::unique_ptr<AXVirtualView> child = std::move(children_[cur_index]);
+ children_.erase(children_.begin() + cur_index);
+ child->virtual_parent_view_ = nullptr;
+ return child;
+}
+
+void AXVirtualView::RemoveAllChildViews() {
+ while (!children_.empty())
+ RemoveChildView(children_.back().get());
+}
+
+const AXVirtualView* AXVirtualView::child_at(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK_LT(index, static_cast<int>(children_.size()));
+ return children_[index].get();
+}
+
+AXVirtualView* AXVirtualView::child_at(int index) {
+ return const_cast<AXVirtualView*>(
+ const_cast<const AXVirtualView*>(this)->child_at(index));
+}
+
+bool AXVirtualView::Contains(const AXVirtualView* view) const {
+ DCHECK(view);
+ for (const AXVirtualView* v = view; v; v = v->virtual_parent_view_) {
+ if (v == this)
+ return true;
+ }
+ return false;
+}
+
+int AXVirtualView::GetIndexOf(const AXVirtualView* view) const {
+ DCHECK(view);
+ const auto iter =
+ std::find_if(children_.begin(), children_.end(),
+ [view](const auto& child) { return child.get() == view; });
+ return iter != children_.end() ? static_cast<int>(iter - children_.begin())
+ : -1;
+}
+
+const char* AXVirtualView::GetViewClassName() const {
+ return kViewClassName;
+}
+
+gfx::NativeViewAccessible AXVirtualView::GetNativeObject() const {
+ DCHECK(ax_platform_node_);
+ return ax_platform_node_->GetNativeViewAccessible();
+}
+
+void AXVirtualView::NotifyAccessibilityEvent(ax::mojom::Event event_type) {
+ DCHECK(ax_platform_node_);
+ ax_platform_node_->NotifyAccessibilityEvent(event_type);
+}
+
+ui::AXNodeData& AXVirtualView::GetCustomData() {
+ return custom_data_;
+}
+
+// ui::AXPlatformNodeDelegate
+
+const ui::AXNodeData& AXVirtualView::GetData() const {
+ // Make a copy of our |custom_data_| so that any modifications will not be
+ // made to the data that users of this class will be manipulating.
+ static ui::AXNodeData node_data;
+ node_data = custom_data_;
+ if (!GetOwnerView() || !GetOwnerView()->enabled())
+ node_data.SetRestriction(ax::mojom::Restriction::kDisabled);
+
+ if (!GetOwnerView() || !GetOwnerView()->IsDrawn())
+ node_data.AddState(ax::mojom::State::kInvisible);
+
+ if (GetOwnerView() && GetOwnerView()->context_menu_controller())
+ node_data.AddAction(ax::mojom::Action::kShowContextMenu);
+
+ return node_data;
+}
+
+int AXVirtualView::GetChildCount() {
+ return static_cast<int>(children_.size());
+}
+
+gfx::NativeViewAccessible AXVirtualView::ChildAtIndex(int index) {
+ DCHECK_GE(index, 0) << "Child indices should be greater or equal to 0.";
+ DCHECK_LT(index, GetChildCount())
+ << "Child indices should be less than the child count.";
+ if (index >= 0 && index < GetChildCount())
+ return children_[index]->GetNativeObject();
+ return nullptr;
+}
+
+gfx::NativeViewAccessible AXVirtualView::GetNSWindow() {
+ NOTREACHED();
+ return nullptr;
+}
+
+gfx::NativeViewAccessible AXVirtualView::GetParent() {
+ if (parent_view_)
+ return parent_view_->GetNativeObject();
+
+ if (virtual_parent_view_)
+ return virtual_parent_view_->GetNativeObject();
+
+ // This virtual view hasn't been added to a parent view yet.
+ return nullptr;
+}
+
+gfx::Rect AXVirtualView::GetClippedScreenBoundsRect() const {
+ // We could optionally add clipping here if ever needed.
+ // TODO(nektar): Implement bounds that are relative to the parent.
+ return gfx::ToEnclosingRect(custom_data_.relative_bounds.bounds);
+}
+
+gfx::Rect AXVirtualView::GetUnclippedScreenBoundsRect() const {
+ // TODO(nektar): Implement bounds that are relative to the parent.
+ return gfx::ToEnclosingRect(custom_data_.relative_bounds.bounds);
+}
+
+gfx::NativeViewAccessible AXVirtualView::HitTestSync(int x, int y) {
+ // TODO(nektar): Implement.
+ return GetNativeObject();
+}
+
+gfx::NativeViewAccessible AXVirtualView::GetFocus() {
+ if (parent_view_)
+ return parent_view_->GetFocusedDescendant();
+
+ if (virtual_parent_view_)
+ return virtual_parent_view_->GetFocus();
+
+ // This virtual view hasn't been added to a parent view yet.
+ return nullptr;
+}
+
+ui::AXPlatformNode* AXVirtualView::GetFromNodeID(int32_t id) {
+ // TODO(nektar): Implement.
+ return nullptr;
+}
+
+bool AXVirtualView::AccessibilityPerformAction(const ui::AXActionData& data) {
+ bool result = false;
+ if (custom_data_.HasAction(data.action))
+ result = HandleAccessibleAction(data);
+ if (!result && GetOwnerView())
+ return GetOwnerView()->HandleAccessibleAction(data);
+ return result;
+}
+
+bool AXVirtualView::ShouldIgnoreHoveredStateForTesting() {
+ // TODO(nektar): Implement.
+ return false;
+}
+
+bool AXVirtualView::IsOffscreen() const {
+ // TODO(nektar): Implement.
+ return false;
+}
+
+const ui::AXUniqueId& AXVirtualView::GetUniqueId() const {
+ return unique_id_;
+}
+
+bool AXVirtualView::HandleAccessibleAction(
+ const ui::AXActionData& action_data) {
+ return false;
+}
+
+View* AXVirtualView::GetOwnerView() const {
+ if (parent_view_)
+ return parent_view_->view();
+
+ if (virtual_parent_view_)
+ return virtual_parent_view_->GetOwnerView();
+
+ // This virtual view hasn't been added to a parent view yet.
+ return nullptr;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_virtual_view.h b/chromium/ui/views/accessibility/ax_virtual_view.h
new file mode 100644
index 00000000000..73edd0b1666
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_virtual_view.h
@@ -0,0 +1,170 @@
+// 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_VIRTUAL_VIEW_H_
+#define UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/ax_platform_node_delegate_base.h"
+#include "ui/accessibility/platform/ax_unique_id.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/views_export.h"
+
+namespace ui {
+
+struct AXActionData;
+class AXUniqueId;
+
+} // namespace ui
+
+namespace views {
+
+class View;
+class ViewAccessibility;
+
+// Implements a virtual view that is used only for accessibility.
+//
+// Some composite widgets such as tree and table views may utilize lightweight
+// UI objects instead of actual views for displaying and managing their
+// contents. We need a corresponding virtual accessibility view to expose
+// information about these lightweight Ui objects to accessibility. An
+// AXVirtualView is owned by its parent, which could either be a
+// ViewAccessibility or an AXVirtualView.
+class VIEWS_EXPORT AXVirtualView : public ui::AXPlatformNodeDelegateBase {
+ public:
+ AXVirtualView();
+ ~AXVirtualView() override;
+
+ //
+ // Methods for managing parent - child relationships.
+ //
+
+ // Adds |view| as a child of this virtual view, optionally at |index|.
+ // We take ownership of our children.
+ void AddChildView(std::unique_ptr<AXVirtualView> view);
+ void AddChildViewAt(std::unique_ptr<AXVirtualView> view, int index);
+
+ // Moves |view| to the specified |index|. A negative value for |index| moves
+ // |view| to the end.
+ void ReorderChildView(AXVirtualView* view, int index);
+
+ // Removes |view| from this virtual view. The view's parent will change to
+ // nullptr. Hands ownership back to the caller.
+ std::unique_ptr<AXVirtualView> RemoveChildView(AXVirtualView* view);
+
+ // Removes all the children from this virtual view.
+ // The virtual views are deleted.
+ void RemoveAllChildViews();
+
+ bool has_children() const { return !children_.empty(); }
+
+ const AXVirtualView* child_at(int index) const;
+ AXVirtualView* child_at(int index);
+
+ // Returns the parent ViewAccessibility if the parent is a real View and not
+ // an AXVirtualView. Returns nullptr otherwise.
+ const ViewAccessibility* parent_view() const { return parent_view_; }
+ ViewAccessibility* parent_view() { return parent_view_; }
+
+ // Returns the parent view if the parent is an AXVirtualView and not a real
+ // View. Returns nullptr otherwise.
+ const AXVirtualView* virtual_parent_view() const {
+ return virtual_parent_view_;
+ }
+ AXVirtualView* virtual_parent_view() { return virtual_parent_view_; }
+
+ // Returns true if |view| is contained within the hierarchy of this
+ // AXVirtualView, even as an indirect descendant. Will return true if |view|
+ // is also this AXVirtualView.
+ bool Contains(const AXVirtualView* view) const;
+
+ // Returns the index of |view|, or -1 if |view| is not a child of this virtual
+ // view.
+ int GetIndexOf(const AXVirtualView* view) const;
+
+ //
+ // Other methods.
+ //
+
+ const char* GetViewClassName() const;
+ gfx::NativeViewAccessible GetNativeObject() const;
+ void NotifyAccessibilityEvent(ax::mojom::Event event_type);
+ // Allows clients to modify the AXNodeData for this virtual view.
+ ui::AXNodeData& GetCustomData();
+
+ // ui::AXPlatformNodeDelegate
+ const ui::AXNodeData& GetData() const override;
+ int GetChildCount() override;
+ gfx::NativeViewAccessible ChildAtIndex(int index) override;
+ gfx::NativeViewAccessible GetNSWindow() override;
+ gfx::NativeViewAccessible GetParent() override;
+ gfx::Rect GetClippedScreenBoundsRect() const override;
+ gfx::Rect GetUnclippedScreenBoundsRect() const override;
+ gfx::NativeViewAccessible HitTestSync(int x, int y) override;
+ gfx::NativeViewAccessible GetFocus() override;
+ ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
+ bool AccessibilityPerformAction(const ui::AXActionData& data) override;
+ bool ShouldIgnoreHoveredStateForTesting() override;
+ bool IsOffscreen() const override;
+ const ui::AXUniqueId& GetUniqueId() const override;
+
+ protected:
+ // Handle a request from assistive technology to perform an action on this
+ // virtual view. Returns true on success, but note that the success/failure is
+ // not propagated to the client that requested the action, since the
+ // request is sometimes asynchronous. The right way to send a response is
+ // via NotifyAccessibilityEvent().
+ virtual bool HandleAccessibleAction(const ui::AXActionData& action_data);
+
+ private:
+ // Internal class name.
+ static const char kViewClassName[];
+
+ // Sets the parent ViewAccessibility if the parent is a real View and not an
+ // AXVirtualView. It is invalid to set both |parent_view_| and
+ // |virtual_parent_view_|.
+ void set_parent_view(ViewAccessibility* view_accessibility) {
+ DCHECK(!virtual_parent_view_);
+ parent_view_ = view_accessibility;
+ }
+
+ // Gets the real View that owns our shallowest virtual ancestor,, if any.
+ View* GetOwnerView() const;
+
+ // We own this, but it is reference-counted on some platforms so we can't use
+ // a unique_ptr. It is destroyed in the destructor.
+ ui::AXPlatformNode* ax_platform_node_;
+
+ // Weak. Owns us if not nullptr.
+ // Either |parent_view_| or |virtual_parent_view_| should be set but not both.
+ ViewAccessibility* parent_view_;
+
+ // Weak. Owns us if not nullptr.
+ // Either |parent_view_| or |virtual_parent_view_| should be set but not both.
+ AXVirtualView* virtual_parent_view_;
+
+ // We own our children.
+ std::vector<std::unique_ptr<AXVirtualView>> children_;
+
+ ui::AXUniqueId unique_id_;
+ ui::AXNodeData custom_data_;
+
+ friend class ViewAccessibility;
+ DISALLOW_COPY_AND_ASSIGN(AXVirtualView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_H_
diff --git a/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc b/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
new file mode 100644
index 00000000000..0a88e411bc0
--- /dev/null
+++ b/chromium/ui/views/accessibility/ax_virtual_view_unittest.cc
@@ -0,0 +1,347 @@
+// 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_virtual_view.h"
+
+#include "base/memory/ptr_util.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/accessibility/view_ax_platform_node_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace test {
+
+namespace {
+
+class TestButton : public Button {
+ public:
+ TestButton() : Button(NULL) {}
+ ~TestButton() override = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestButton);
+};
+
+} // namespace
+
+class AXVirtualViewTest : public ViewsTestBase {
+ public:
+ AXVirtualViewTest() = default;
+ ~AXVirtualViewTest() override = default;
+
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+
+ widget_ = new Widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.bounds = gfx::Rect(0, 0, 200, 200);
+ widget_->Init(params);
+ button_ = new TestButton;
+ button_->SetSize(gfx::Size(20, 20));
+ widget_->GetContentsView()->AddChildView(button_);
+ virtual_label_ = new AXVirtualView;
+ virtual_label_->GetCustomData().role = ax::mojom::Role::kStaticText;
+ virtual_label_->GetCustomData().SetName("Label");
+ button_->GetViewAccessibility().AddVirtualChildView(
+ base::WrapUnique(virtual_label_));
+ widget_->Show();
+ }
+
+ void TearDown() override {
+ if (!widget_->IsClosed())
+ widget_->Close();
+ ViewsTestBase::TearDown();
+ }
+
+ ViewAXPlatformNodeDelegate* GetButtonAccessibility() {
+ return static_cast<ViewAXPlatformNodeDelegate*>(
+ &button_->GetViewAccessibility());
+ }
+
+ protected:
+ Widget* widget_;
+ Button* button_;
+ // Weak, |button_| owns this.
+ AXVirtualView* virtual_label_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AXVirtualViewTest);
+};
+
+TEST_F(AXVirtualViewTest, AccessibilityRoleAndName) {
+ EXPECT_EQ(ax::mojom::Role::kButton, GetButtonAccessibility()->GetData().role);
+ EXPECT_EQ(ax::mojom::Role::kStaticText, virtual_label_->GetData().role);
+ EXPECT_EQ("Label", virtual_label_->GetData().GetStringAttribute(
+ ax::mojom::StringAttribute::kName));
+}
+
+// The focusable state of a virtual view should not depend on the focusable
+// state of the real view ancestor, however the enabled state should.
+TEST_F(AXVirtualViewTest, FocusableAndEnabledState) {
+ virtual_label_->GetCustomData().AddState(ax::mojom::State::kFocusable);
+ EXPECT_TRUE(GetButtonAccessibility()->GetData().HasState(
+ ax::mojom::State::kFocusable));
+ EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_EQ(ax::mojom::Restriction::kNone,
+ GetButtonAccessibility()->GetData().GetRestriction());
+ EXPECT_EQ(ax::mojom::Restriction::kNone,
+ virtual_label_->GetData().GetRestriction());
+
+ button_->SetFocusBehavior(View::FocusBehavior::NEVER);
+ EXPECT_FALSE(GetButtonAccessibility()->GetData().HasState(
+ ax::mojom::State::kFocusable));
+ EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_EQ(ax::mojom::Restriction::kNone,
+ GetButtonAccessibility()->GetData().GetRestriction());
+ EXPECT_EQ(ax::mojom::Restriction::kNone,
+ virtual_label_->GetData().GetRestriction());
+
+ button_->SetEnabled(false);
+ EXPECT_FALSE(GetButtonAccessibility()->GetData().HasState(
+ ax::mojom::State::kFocusable));
+ EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_EQ(ax::mojom::Restriction::kDisabled,
+ GetButtonAccessibility()->GetData().GetRestriction());
+ EXPECT_EQ(ax::mojom::Restriction::kDisabled,
+ virtual_label_->GetData().GetRestriction());
+
+ button_->SetEnabled(true);
+ button_->SetFocusBehavior(View::FocusBehavior::ALWAYS);
+ virtual_label_->GetCustomData().RemoveState(ax::mojom::State::kFocusable);
+ EXPECT_TRUE(GetButtonAccessibility()->GetData().HasState(
+ ax::mojom::State::kFocusable));
+ EXPECT_FALSE(
+ virtual_label_->GetData().HasState(ax::mojom::State::kFocusable));
+ EXPECT_EQ(ax::mojom::Restriction::kNone,
+ GetButtonAccessibility()->GetData().GetRestriction());
+ EXPECT_EQ(ax::mojom::Restriction::kNone,
+ virtual_label_->GetData().GetRestriction());
+}
+
+TEST_F(AXVirtualViewTest, VirtualLabelIsChildOfButton) {
+ EXPECT_EQ(1, GetButtonAccessibility()->GetChildCount());
+ EXPECT_EQ(0, virtual_label_->GetChildCount());
+ ASSERT_NE(nullptr, virtual_label_->GetParent());
+ EXPECT_EQ(button_->GetNativeViewAccessible(), virtual_label_->GetParent());
+ ASSERT_NE(nullptr, GetButtonAccessibility()->ChildAtIndex(0));
+ EXPECT_EQ(virtual_label_->GetNativeObject(),
+ GetButtonAccessibility()->ChildAtIndex(0));
+}
+
+TEST_F(AXVirtualViewTest, AddingAndRemovingVirtualChildren) {
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ EXPECT_EQ(1, virtual_label_->GetChildCount());
+ ASSERT_NE(nullptr, virtual_child_1->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
+ ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
+ EXPECT_EQ(2, virtual_label_->GetChildCount());
+ ASSERT_NE(nullptr, virtual_child_2->GetParent());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
+ ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->ChildAtIndex(1));
+
+ AXVirtualView* virtual_child_3 = new AXVirtualView;
+ virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
+ EXPECT_EQ(2, virtual_label_->GetChildCount());
+ EXPECT_EQ(0, virtual_child_1->GetChildCount());
+ EXPECT_EQ(1, virtual_child_2->GetChildCount());
+ ASSERT_NE(nullptr, virtual_child_3->GetParent());
+ EXPECT_EQ(virtual_child_2->GetNativeObject(), virtual_child_3->GetParent());
+ ASSERT_NE(nullptr, virtual_child_2->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ virtual_child_2->ChildAtIndex(0));
+
+ virtual_child_2->RemoveChildView(virtual_child_3);
+ EXPECT_EQ(0, virtual_child_2->GetChildCount());
+ EXPECT_EQ(2, virtual_label_->GetChildCount());
+
+ virtual_label_->RemoveAllChildViews();
+ EXPECT_EQ(0, virtual_label_->GetChildCount());
+}
+
+TEST_F(AXVirtualViewTest, ReorderingVirtualChildren) {
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ ASSERT_EQ(1, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
+ ASSERT_EQ(2, virtual_label_->GetChildCount());
+
+ virtual_label_->ReorderChildView(virtual_child_1, -1);
+ ASSERT_EQ(2, virtual_label_->GetChildCount());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_2->GetParent());
+ ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+ ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ virtual_label_->ChildAtIndex(1));
+
+ virtual_label_->ReorderChildView(virtual_child_1, 0);
+ ASSERT_EQ(2, virtual_label_->GetChildCount());
+ EXPECT_EQ(virtual_label_->GetNativeObject(), virtual_child_1->GetParent());
+ ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(0));
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ virtual_label_->ChildAtIndex(0));
+ ASSERT_NE(nullptr, virtual_label_->ChildAtIndex(1));
+ EXPECT_EQ(virtual_child_2->GetNativeObject(),
+ virtual_label_->ChildAtIndex(1));
+
+ virtual_label_->RemoveAllChildViews();
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+}
+
+TEST_F(AXVirtualViewTest, ContainsVirtualChild) {
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ ASSERT_EQ(1, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
+ ASSERT_EQ(2, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_3 = new AXVirtualView;
+ virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
+ ASSERT_EQ(1, virtual_child_2->GetChildCount());
+
+ EXPECT_TRUE(button_->GetViewAccessibility().Contains(virtual_label_));
+ EXPECT_TRUE(virtual_label_->Contains(virtual_label_));
+ EXPECT_TRUE(virtual_label_->Contains(virtual_child_1));
+ EXPECT_TRUE(virtual_label_->Contains(virtual_child_2));
+ EXPECT_TRUE(virtual_label_->Contains(virtual_child_3));
+ EXPECT_TRUE(virtual_child_2->Contains(virtual_child_2));
+ EXPECT_TRUE(virtual_child_2->Contains(virtual_child_3));
+
+ EXPECT_FALSE(virtual_child_1->Contains(virtual_label_));
+ EXPECT_FALSE(virtual_child_2->Contains(virtual_label_));
+ EXPECT_FALSE(virtual_child_3->Contains(virtual_child_2));
+
+ virtual_label_->RemoveAllChildViews();
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+}
+
+TEST_F(AXVirtualViewTest, GetIndexOfVirtualChild) {
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ ASSERT_EQ(1, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
+ ASSERT_EQ(2, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_3 = new AXVirtualView;
+ virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
+ ASSERT_EQ(1, virtual_child_2->GetChildCount());
+
+ EXPECT_EQ(-1, virtual_label_->GetIndexOf(virtual_label_));
+ EXPECT_EQ(0, virtual_label_->GetIndexOf(virtual_child_1));
+ EXPECT_EQ(1, virtual_label_->GetIndexOf(virtual_child_2));
+ EXPECT_EQ(-1, virtual_label_->GetIndexOf(virtual_child_3));
+ EXPECT_EQ(0, virtual_child_2->GetIndexOf(virtual_child_3));
+
+ virtual_label_->RemoveAllChildViews();
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+}
+
+// Verify that virtual views with invisible ancestors inherit the
+// ax::mojom::State::kInvisible state.
+TEST_F(AXVirtualViewTest, InvisibleVirtualViews) {
+ EXPECT_TRUE(widget_->IsVisible());
+ EXPECT_FALSE(GetButtonAccessibility()->GetData().HasState(
+ ax::mojom::State::kInvisible));
+ EXPECT_FALSE(
+ virtual_label_->GetData().HasState(ax::mojom::State::kInvisible));
+
+ button_->SetVisible(false);
+ EXPECT_TRUE(GetButtonAccessibility()->GetData().HasState(
+ ax::mojom::State::kInvisible));
+ EXPECT_TRUE(virtual_label_->GetData().HasState(ax::mojom::State::kInvisible));
+ button_->SetVisible(true);
+}
+
+TEST_F(AXVirtualViewTest, OverrideFocus) {
+ ViewAccessibility& button_accessibility = button_->GetViewAccessibility();
+ ASSERT_NE(nullptr, button_accessibility.GetNativeObject());
+ ASSERT_NE(nullptr, virtual_label_->GetNativeObject());
+
+ EXPECT_EQ(button_accessibility.GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+ button_accessibility.OverrideFocus(virtual_label_);
+ EXPECT_EQ(virtual_label_->GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+ button_accessibility.OverrideFocus(nullptr);
+ EXPECT_EQ(button_accessibility.GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+ AXVirtualView* virtual_child_1 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_1));
+ ASSERT_EQ(1, virtual_label_->GetChildCount());
+
+ AXVirtualView* virtual_child_2 = new AXVirtualView;
+ virtual_label_->AddChildView(base::WrapUnique(virtual_child_2));
+ ASSERT_EQ(2, virtual_label_->GetChildCount());
+
+ button_accessibility.OverrideFocus(virtual_child_1);
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+
+ AXVirtualView* virtual_child_3 = new AXVirtualView;
+ virtual_child_2->AddChildView(base::WrapUnique(virtual_child_3));
+ ASSERT_EQ(1, virtual_child_2->GetChildCount());
+
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+ button_accessibility.OverrideFocus(virtual_child_3);
+ EXPECT_EQ(virtual_child_3->GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+
+ // Test that calling GetFocus() from any object in the tree will return the
+ // same result.
+ EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_label_->GetFocus());
+ EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_child_1->GetFocus());
+ EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_child_2->GetFocus());
+ EXPECT_EQ(virtual_child_3->GetNativeObject(), virtual_child_3->GetFocus());
+
+ virtual_label_->RemoveChildView(virtual_child_2);
+ ASSERT_EQ(1, virtual_label_->GetChildCount());
+ EXPECT_EQ(button_accessibility.GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+ EXPECT_EQ(button_accessibility.GetNativeObject(), virtual_label_->GetFocus());
+ EXPECT_EQ(button_accessibility.GetNativeObject(),
+ virtual_child_1->GetFocus());
+
+ button_accessibility.OverrideFocus(virtual_child_1);
+ EXPECT_EQ(virtual_child_1->GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+ virtual_label_->RemoveAllChildViews();
+ ASSERT_EQ(0, virtual_label_->GetChildCount());
+ EXPECT_EQ(button_accessibility.GetNativeObject(),
+ button_accessibility.GetFocusedDescendant());
+}
+
+} // namespace test
+} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
index 0192ff9f743..e3cd96c1a75 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -46,18 +46,19 @@ void AXWidgetObjWrapper::GetChildren(
}
void AXWidgetObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
- out_node_data->id = GetUniqueId().Get();
+ out_node_data->id = GetUniqueId();
out_node_data->role = widget_->widget_delegate()->GetAccessibleWindowRole();
out_node_data->AddStringAttribute(
ax::mojom::StringAttribute::kName,
base::UTF16ToUTF8(
widget_->widget_delegate()->GetAccessibleWindowTitle()));
- out_node_data->location = gfx::RectF(widget_->GetWindowBoundsInScreen());
+ out_node_data->relative_bounds.bounds =
+ gfx::RectF(widget_->GetWindowBoundsInScreen());
out_node_data->state = 0;
}
-const ui::AXUniqueId& AXWidgetObjWrapper::GetUniqueId() const {
- return unique_id_;
+int32_t AXWidgetObjWrapper::GetUniqueId() const {
+ return unique_id_.Get();
}
void AXWidgetObjWrapper::OnWidgetDestroying(Widget* widget) {
diff --git a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
index 5110cfe5981..283efcb7b12 100644
--- a/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_widget_obj_wrapper.h
@@ -29,7 +29,7 @@ class AXWidgetObjWrapper : public AXAuraObjWrapper,
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- const ui::AXUniqueId& GetUniqueId() const final;
+ int32_t GetUniqueId() const final;
// WidgetObserver overrides.
void OnWidgetDestroying(Widget* widget) override;
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
index cd77dabfd1b..91c4ef7e03d 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -11,7 +11,6 @@
#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"
#include "ui/aura/window.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
@@ -19,26 +18,25 @@
namespace views {
-void FireLocationChanges(aura::Window* window) {
+// A helper to fire an event on a window, taking into account its associated
+// widget and that widget's root view.
+void FireEvent(aura::Window* window, ax::mojom::Event event_type) {
AXAuraObjCache::GetInstance()->FireEvent(
- AXAuraObjCache::GetInstance()->GetOrCreate(window),
- ax::mojom::Event::kLocationChanged);
+ AXAuraObjCache::GetInstance()->GetOrCreate(window), event_type);
Widget* widget = Widget::GetWidgetForNativeView(window);
if (widget) {
AXAuraObjCache::GetInstance()->FireEvent(
- AXAuraObjCache::GetInstance()->GetOrCreate(widget),
- ax::mojom::Event::kLocationChanged);
+ AXAuraObjCache::GetInstance()->GetOrCreate(widget), event_type);
views::View* root_view = widget->GetRootView();
if (root_view)
- root_view->NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged,
- true);
+ root_view->NotifyAccessibilityEvent(event_type, true);
}
aura::Window::Windows children = window->children();
for (size_t i = 0; i < children.size(); ++i)
- FireLocationChanges(children[i]);
+ FireEvent(children[i], ax::mojom::Event::kLocationChanged);
}
AXWindowObjWrapper::AXWindowObjWrapper(aura::Window* window)
@@ -85,7 +83,7 @@ void AXWindowObjWrapper::GetChildren(
}
void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
- out_node_data->id = GetUniqueId().Get();
+ out_node_data->id = GetUniqueId();
ax::mojom::Role role = window_->GetProperty(ui::kAXRoleOverride);
if (role != ax::mojom::Role::kNone)
out_node_data->role = role;
@@ -96,7 +94,9 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
base::UTF16ToUTF8(window_->GetTitle()));
if (!window_->IsVisible())
out_node_data->AddState(ax::mojom::State::kInvisible);
- out_node_data->location = gfx::RectF(window_->GetBoundsInScreen());
+
+ out_node_data->relative_bounds.bounds =
+ gfx::RectF(window_->GetBoundsInScreen());
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()) {
@@ -116,8 +116,8 @@ void AXWindowObjWrapper::Serialize(ui::AXNodeData* out_node_data) {
}
}
-const ui::AXUniqueId& AXWindowObjWrapper::GetUniqueId() const {
- return unique_id_;
+int32_t AXWindowObjWrapper::GetUniqueId() const {
+ return unique_id_.Get();
}
void AXWindowObjWrapper::OnWindowDestroyed(aura::Window* window) {
@@ -144,7 +144,7 @@ void AXWindowObjWrapper::OnWindowBoundsChanged(
if (window != window_)
return;
- FireLocationChanges(window_);
+ FireEvent(window_, ax::mojom::Event::kLocationChanged);
}
void AXWindowObjWrapper::OnWindowPropertyChanged(aura::Window* window,
@@ -167,7 +167,11 @@ void AXWindowObjWrapper::OnWindowTransformed(aura::Window* window,
if (window != window_)
return;
- FireLocationChanges(window_);
+ FireEvent(window_, ax::mojom::Event::kLocationChanged);
+}
+
+void AXWindowObjWrapper::OnWindowTitleChanged(aura::Window* window) {
+ FireEvent(window, ax::mojom::Event::kTextChanged);
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
index e996fa3a124..de813581891 100644
--- a/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
+++ b/chromium/ui/views/accessibility/ax_window_obj_wrapper.h
@@ -36,7 +36,7 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
AXAuraObjWrapper* GetParent() override;
void GetChildren(std::vector<AXAuraObjWrapper*>* out_children) override;
void Serialize(ui::AXNodeData* out_node_data) override;
- const ui::AXUniqueId& GetUniqueId() const final;
+ int32_t GetUniqueId() const final;
// WindowObserver overrides.
void OnWindowDestroyed(aura::Window* window) override;
@@ -52,6 +52,7 @@ class AXWindowObjWrapper : public AXAuraObjWrapper,
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
void OnWindowTransformed(aura::Window* window,
ui::PropertyChangeReason reason) override;
+ void OnWindowTitleChanged(aura::Window* window) override;
private:
aura::Window* window_;
diff --git a/chromium/ui/views/accessibility/view_accessibility.cc b/chromium/ui/views/accessibility/view_accessibility.cc
index db7109d7113..226bda50ed8 100644
--- a/chromium/ui/views/accessibility/view_accessibility.cc
+++ b/chromium/ui/views/accessibility/view_accessibility.cc
@@ -4,6 +4,10 @@
#include "ui/views/accessibility/view_accessibility.h"
+#include <algorithm>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/base/ui_features.h"
@@ -36,15 +40,89 @@ bool IsValidRoleForViews(ax::mojom::Role role) {
#if !BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY()
// static
std::unique_ptr<ViewAccessibility> ViewAccessibility::Create(View* view) {
+ // Cannot use std::make_unique because constructor is protected.
return base::WrapUnique(new ViewAccessibility(view));
}
#endif
ViewAccessibility::ViewAccessibility(View* view)
- : owner_view_(view), is_leaf_(false) {}
+ : view_(view),
+ focused_virtual_child_(nullptr),
+ is_leaf_(false),
+ is_ignored_(false) {}
ViewAccessibility::~ViewAccessibility() = default;
+void ViewAccessibility::AddVirtualChildView(
+ std::unique_ptr<AXVirtualView> virtual_view) {
+ DCHECK(virtual_view);
+ if (virtual_view->parent_view() == this)
+ return;
+ AddVirtualChildViewAt(std::move(virtual_view), virtual_child_count());
+}
+
+void ViewAccessibility::AddVirtualChildViewAt(
+ std::unique_ptr<AXVirtualView> virtual_view,
+ int index) {
+ DCHECK(virtual_view);
+ DCHECK(!virtual_view->parent_view()) << "This |view| already has a View "
+ "parent. Call RemoveVirtualChildView "
+ "first.";
+ DCHECK(!virtual_view->virtual_parent_view()) << "This |view| already has an "
+ "AXVirtualView parent. Call "
+ "RemoveChildView first.";
+ DCHECK_GE(index, 0);
+ DCHECK_LE(index, virtual_child_count());
+
+ virtual_view->set_parent_view(this);
+ virtual_children_.insert(virtual_children_.begin() + index,
+ std::move(virtual_view));
+}
+
+std::unique_ptr<AXVirtualView> ViewAccessibility::RemoveVirtualChildView(
+ AXVirtualView* virtual_view) {
+ DCHECK(virtual_view);
+ int cur_index = GetIndexOf(virtual_view);
+ if (cur_index < 0)
+ return {};
+
+ std::unique_ptr<AXVirtualView> child =
+ std::move(virtual_children_[cur_index]);
+ virtual_children_.erase(virtual_children_.begin() + cur_index);
+ child->set_parent_view(nullptr);
+ if (focused_virtual_child_ && child->Contains(focused_virtual_child_))
+ focused_virtual_child_ = nullptr;
+ return child;
+}
+
+void ViewAccessibility::RemoveAllVirtualChildViews() {
+ while (!virtual_children_.empty())
+ RemoveVirtualChildView(virtual_children_.back().get());
+}
+
+bool ViewAccessibility::Contains(const AXVirtualView* virtual_view) const {
+ DCHECK(virtual_view);
+ for (const auto& virtual_child : virtual_children_) {
+ // AXVirtualView::Contains() also checks if the provided virtual view is the
+ // same as |this|.
+ if (virtual_child->Contains(virtual_view))
+ return true;
+ }
+ return false;
+}
+
+int ViewAccessibility::GetIndexOf(const AXVirtualView* virtual_view) const {
+ DCHECK(virtual_view);
+ const auto iter =
+ std::find_if(virtual_children_.begin(), virtual_children_.end(),
+ [virtual_view](const auto& child) {
+ return child.get() == virtual_view;
+ });
+ return iter != virtual_children_.end()
+ ? static_cast<int>(iter - virtual_children_.begin())
+ : -1;
+}
+
const ui::AXUniqueId& ViewAccessibility::GetUniqueId() const {
return unique_id_;
}
@@ -52,14 +130,14 @@ const ui::AXUniqueId& ViewAccessibility::GetUniqueId() const {
void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
// Views may misbehave if their widget is closed; return an unknown role
// rather than possibly crashing.
- views::Widget* widget = owner_view_->GetWidget();
+ const views::Widget* widget = view_->GetWidget();
if (!widget || !widget->widget_delegate() || widget->IsClosed()) {
data->role = ax::mojom::Role::kUnknown;
data->SetRestriction(ax::mojom::Restriction::kDisabled);
return;
}
- owner_view_->GetAccessibleNodeData(data);
+ view_->GetAccessibleNodeData(data);
if (custom_data_.role != ax::mojom::Role::kUnknown)
data->role = custom_data_.role;
@@ -76,7 +154,7 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
if (!data->HasStringAttribute(ax::mojom::StringAttribute::kDescription)) {
base::string16 tooltip;
- owner_view_->GetTooltipText(gfx::Point(), &tooltip);
+ view_->GetTooltipText(gfx::Point(), &tooltip);
// Some screen readers announce the accessible description right after the
// accessible name. Only use the tooltip as the accessible description if
// it's different from the name, otherwise users might be puzzled as to why
@@ -88,30 +166,31 @@ void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
}
}
- data->location = gfx::RectF(owner_view_->GetBoundsInScreen());
+ data->relative_bounds.bounds = gfx::RectF(view_->GetBoundsInScreen());
data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
- owner_view_->GetClassName());
+ view_->GetClassName());
- if (owner_view_->IsAccessibilityFocusable())
+ if (view_->IsAccessibilityFocusable())
data->AddState(ax::mojom::State::kFocusable);
- if (!owner_view_->enabled())
+ if (!view_->enabled())
data->SetRestriction(ax::mojom::Restriction::kDisabled);
- if (!owner_view_->visible() && data->role != ax::mojom::Role::kAlert)
+ if (!view_->visible() && data->role != ax::mojom::Role::kAlert)
data->AddState(ax::mojom::State::kInvisible);
- if (owner_view_->context_menu_controller())
+ if (view_->context_menu_controller())
data->AddAction(ax::mojom::Action::kShowContextMenu);
}
-bool ViewAccessibility::IsLeaf() const {
- return is_leaf_;
+void ViewAccessibility::OverrideFocus(AXVirtualView* virtual_view) {
+ DCHECK(!virtual_view || Contains(virtual_view))
+ << "|virtual_view| must be nullptr or a descendant of this view.";
+ focused_virtual_child_ = virtual_view;
}
-void ViewAccessibility::OverrideRole(ax::mojom::Role role) {
- DCHECK(IsValidRoleForViews(role));
-
+void ViewAccessibility::OverrideRole(const ax::mojom::Role role) {
+ DCHECK(IsValidRoleForViews(role)) << "Invalid role for Views.";
custom_data_.role = role;
}
@@ -120,22 +199,33 @@ void ViewAccessibility::OverrideName(const std::string& name) {
}
void ViewAccessibility::OverrideName(const base::string16& name) {
- custom_data_.SetName(base::UTF16ToUTF8(name));
+ custom_data_.SetName(name);
}
void ViewAccessibility::OverrideDescription(const std::string& description) {
- DCHECK(!custom_data_.HasStringAttribute(
- ax::mojom::StringAttribute::kDescription));
- custom_data_.AddStringAttribute(ax::mojom::StringAttribute::kDescription,
- description);
+ custom_data_.SetDescription(description);
}
-void ViewAccessibility::OverrideIsLeaf() {
- is_leaf_ = true;
+void ViewAccessibility::OverrideDescription(const base::string16& description) {
+ custom_data_.SetDescription(description);
+}
+
+void ViewAccessibility::OverrideIsLeaf(bool value) {
+ is_leaf_ = value;
+}
+
+void ViewAccessibility::OverrideIsIgnored(bool value) {
+ is_ignored_ = value;
}
gfx::NativeViewAccessible ViewAccessibility::GetNativeObject() {
return nullptr;
}
+gfx::NativeViewAccessible ViewAccessibility::GetFocusedDescendant() {
+ if (focused_virtual_child_)
+ return focused_virtual_child_->GetNativeObject();
+ return view_->GetNativeViewAccessible();
+}
+
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_accessibility.h b/chromium/ui/views/accessibility/view_accessibility.h
index 903c4e5d2c6..43bc3434e54 100644
--- a/chromium/ui/views/accessibility/view_accessibility.h
+++ b/chromium/ui/views/accessibility/view_accessibility.h
@@ -6,13 +6,16 @@
#define UI_VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
#include <memory>
+#include <string>
#include "base/macros.h"
+#include "base/strings/string16.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/accessibility/ax_virtual_view.h"
#include "ui/views/views_export.h"
namespace views {
@@ -45,11 +48,21 @@ class VIEWS_EXPORT ViewAccessibility {
// Note that string attributes are only used if non-empty, so you can't
// override a string with the empty string.
//
- void OverrideRole(ax::mojom::Role role);
+
+ // Sets one of our virtual descendants as having the accessibility focus. This
+ // means that if this view has the system focus, it will set the accessibility
+ // focus to the provided descendant virtual view instead. Set this to nullptr
+ // if none of our virtual descendants should have the accessibility focus. It
+ // is illegal to set this to any virtual view that is currently not one of our
+ // descendants and this is enforced by a DCHECK.
+ void OverrideFocus(AXVirtualView* virtual_view);
+ void OverrideRole(const ax::mojom::Role role);
void OverrideName(const std::string& name);
void OverrideName(const base::string16& name);
void OverrideDescription(const std::string& description);
- void OverrideIsLeaf(); // Force this node to be treated as a leaf node.
+ void OverrideDescription(const base::string16& description);
+ void OverrideIsLeaf(bool value);
+ void OverrideIsIgnored(bool value);
virtual gfx::NativeViewAccessible GetNativeObject();
virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) {}
@@ -59,26 +72,78 @@ class VIEWS_EXPORT ViewAccessibility {
virtual const ui::AXUniqueId& GetUniqueId() const;
- bool IsLeaf() const;
+ View* view() const { return view_; }
+ AXVirtualView* FocusedVirtualChild() const { return focused_virtual_child_; }
+ bool IsLeaf() const { return is_leaf_; }
+ bool IsIgnored() const { return is_ignored_; }
+
+ //
+ // Methods for managing virtual views.
+ //
- bool is_ignored() const { return is_ignored_; }
- void set_is_ignored(bool ignored) { is_ignored_ = ignored; }
+ // Adds |virtual_view| as a child of this View, optionally at |index|.
+ // We take ownership of our virtual children.
+ void AddVirtualChildView(std::unique_ptr<AXVirtualView> virtual_view);
+ void AddVirtualChildViewAt(std::unique_ptr<AXVirtualView> virtual_view,
+ int index);
+
+ // Removes |virtual_view| from this View. The virtual view's parent will
+ // change to nullptr. Hands ownership back to the caller.
+ std::unique_ptr<AXVirtualView> RemoveVirtualChildView(
+ AXVirtualView* virtual_view);
+
+ // Removes all the virtual children from this View.
+ // The virtual views are deleted.
+ void RemoveAllVirtualChildViews();
+
+ int virtual_child_count() const {
+ return static_cast<int>(virtual_children_.size());
+ }
+
+ const AXVirtualView* virtual_child_at(int index) const {
+ DCHECK_GE(index, 0);
+ DCHECK_LT(index, virtual_child_count());
+ return virtual_children_[index].get();
+ }
+
+ // Returns true if |virtual_view| is contained within the hierarchy of this
+ // View, even as an indirect descendant.
+ bool Contains(const AXVirtualView* virtual_view) const;
+
+ // Returns the index of |virtual_view|, or -1 if |virtual_view| is not a child
+ // of this View.
+ int GetIndexOf(const AXVirtualView* virtual_view) const;
+
+ // Returns the native accessibility object associated with the AXVirtualView
+ // descendant that is currently focused. If no virtual descendants are
+ // present, or no virtual descendant has been marked as focused, returns the
+ // native accessibility object associated with this view.
+ gfx::NativeViewAccessible GetFocusedDescendant();
protected:
explicit ViewAccessibility(View* view);
- View* view() const { return owner_view_; }
-
private:
// Weak. Owns this.
- View* const owner_view_;
+ View* const view_;
+
+ // If there are any virtual children, they override any real children.
+ // We own our virtual children.
+ std::vector<std::unique_ptr<AXVirtualView>> virtual_children_;
+
+ // The virtual child that is currently focused.
+ // This is nullptr if no virtual child is focused.
+ // See also OverrideFocus() and GetFocusedDescendant().
+ AXVirtualView* focused_virtual_child_;
const ui::AXUniqueId unique_id_;
- // Contains data set explicitly via SetRole, SetName, etc. that overrides
- // anything provided by GetAccessibleNodeData().
+ // Contains data set explicitly via OverrideRole, OverrideName, etc. that
+ // overrides anything provided by GetAccessibleNodeData().
ui::AXNodeData custom_data_;
+ // If set to true, anything that is a descendant of this view will be hidden
+ // from accessibility.
bool is_leaf_;
// When true the view is ignored when generating the AX node hierarchy, but
@@ -87,7 +152,9 @@ class VIEWS_EXPORT ViewAccessibility {
// "ignored" would mean that the digits 1 - 9 would appear as if they were
// immediate children of the root. Likewise "internal" container views can be
// ignored, like a Widget's RootView, ClientView, etc.
- bool is_ignored_ = false;
+ // Similar to setting the role of an ARIA widget to "none" or
+ // "presentational".
+ bool is_ignored_;
DISALLOW_COPY_AND_ASSIGN(ViewAccessibility);
};
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 adc4575fd6e..e0629603c9b 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -9,10 +9,12 @@
#include "base/lazy_instance.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_role_properties.h"
+#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/platform/ax_platform_node.h"
+#include "ui/accessibility/platform/ax_unique_id.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"
@@ -28,6 +30,9 @@ base::LazyInstance<std::map<int32_t, ui::AXPlatformNode*>>::Leaky
// Information required to fire a delayed accessibility event.
struct QueuedEvent {
+ QueuedEvent(ax::mojom::Event type, int32_t node_id)
+ : type(type), node_id(node_id) {}
+
ax::mojom::Event type;
int32_t node_id;
};
@@ -106,8 +111,8 @@ int ViewAXPlatformNodeDelegate::menu_depth_ = 0;
ViewAXPlatformNodeDelegate::ViewAXPlatformNodeDelegate(View* view)
: ViewAccessibility(view) {
- ax_node_ = ui::AXPlatformNode::Create(this);
- DCHECK(ax_node_);
+ ax_platform_node_ = ui::AXPlatformNode::Create(this);
+ DCHECK(ax_platform_node_);
static bool first_time = true;
if (first_time) {
@@ -116,7 +121,8 @@ ViewAXPlatformNodeDelegate::ViewAXPlatformNodeDelegate(View* view)
first_time = false;
}
- g_unique_id_to_ax_platform_node.Get()[GetUniqueId().Get()] = ax_node_;
+ g_unique_id_to_ax_platform_node.Get()[GetUniqueId().Get()] =
+ ax_platform_node_;
}
ViewAXPlatformNodeDelegate::~ViewAXPlatformNodeDelegate() {
@@ -124,21 +130,23 @@ ViewAXPlatformNodeDelegate::~ViewAXPlatformNodeDelegate() {
ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
g_unique_id_to_ax_platform_node.Get().erase(GetUniqueId().Get());
- ax_node_->Destroy();
+ ax_platform_node_->Destroy();
}
gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNativeObject() {
- return ax_node_->GetNativeViewAccessible();
+ DCHECK(ax_platform_node_);
+ return ax_platform_node_->GetNativeViewAccessible();
}
void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent(
ax::mojom::Event event_type) {
+ DCHECK(ax_platform_node_);
if (g_is_queueing_events) {
- g_event_queue.Get().push_back({event_type, GetUniqueId().Get()});
+ g_event_queue.Get().emplace_back(event_type, GetUniqueId());
return;
}
- ax_node_->NotifyAccessibilityEvent(event_type);
+ ax_platform_node_->NotifyAccessibilityEvent(event_type);
// Some events have special handling.
switch (event_type) {
@@ -169,7 +177,7 @@ void ViewAXPlatformNodeDelegate::NotifyAccessibilityEvent(
#if defined(OS_MACOSX)
void ViewAXPlatformNodeDelegate::AnnounceText(base::string16& text) {
- ax_node_->AnnounceText(text);
+ ax_platform_node_->AnnounceText(text);
}
#endif
@@ -178,7 +186,7 @@ void ViewAXPlatformNodeDelegate::OnMenuItemActive() {
// currently selected item as focused, even though the actual focus is in the
// browser's currently focused textfield.
ui::AXPlatformNode::SetPopupFocusOverride(
- ax_node_->GetNativeViewAccessible());
+ ax_platform_node_->GetNativeViewAccessible());
}
void ViewAXPlatformNodeDelegate::OnMenuStart() {
@@ -197,7 +205,7 @@ void ViewAXPlatformNodeDelegate::OnMenuEnd() {
// ui::AXPlatformNodeDelegate
const ui::AXNodeData& ViewAXPlatformNodeDelegate::GetData() const {
- // Clear it, then populate it.
+ // Clear the data, then populate it.
data_ = ui::AXNodeData();
GetAccessibleNodeData(&data_);
@@ -227,8 +235,11 @@ const ui::AXNodeData& ViewAXPlatformNodeDelegate::GetData() const {
int ViewAXPlatformNodeDelegate::GetChildCount() {
if (IsLeaf())
return 0;
- int child_count = view()->child_count();
+ if (virtual_child_count())
+ return virtual_child_count();
+
+ int child_count = view()->child_count();
std::vector<Widget*> child_widgets;
bool is_tab_modal_showing;
PopulateChildWidgetVector(&child_widgets, &is_tab_modal_showing);
@@ -242,9 +253,15 @@ int ViewAXPlatformNodeDelegate::GetChildCount() {
}
gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::ChildAtIndex(int index) {
+ DCHECK_GE(index, 0) << "Child indices should be greater or equal to 0.";
+ DCHECK_LT(index, GetChildCount())
+ << "Child indices should be less than the child count.";
if (IsLeaf())
return nullptr;
+ if (virtual_child_count())
+ return virtual_child_at(index)->GetNativeObject();
+
// If this is a root view, our widget might have child widgets. Include
std::vector<Widget*> child_widgets;
bool is_tab_modal_showing;
@@ -258,7 +275,6 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::ChildAtIndex(int index) {
}
int child_widget_count = static_cast<int>(child_widgets.size());
-
if (index < view()->child_count()) {
return view()->child_at(index)->GetNativeViewAccessible();
} else if (index < view()->child_count() + child_widget_count) {
@@ -269,9 +285,8 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::ChildAtIndex(int index) {
return nullptr;
}
-gfx::NativeWindow ViewAXPlatformNodeDelegate::GetTopLevelWidget() {
- if (view()->GetWidget())
- return view()->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
+gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetNSWindow() {
+ NOTREACHED();
return nullptr;
}
@@ -350,7 +365,12 @@ gfx::NativeViewAccessible ViewAXPlatformNodeDelegate::GetFocus() {
View* focused_view =
focus_manager ? focus_manager->GetFocusedView() : nullptr;
- return focused_view ? focused_view->GetNativeViewAccessible() : nullptr;
+ if (!focused_view)
+ return nullptr;
+
+ // The accessibility focus will be either on the |focused_view| or on one of
+ // its virtual children.
+ return focused_view->GetViewAccessibility().GetFocusedDescendant();
}
ui::AXPlatformNode* ViewAXPlatformNodeDelegate::GetFromNodeID(int32_t id) {
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 8dea736b61f..35d2aa0ffb1 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate.h
@@ -5,21 +5,26 @@
#ifndef UI_VIEWS_ACCESSIBILITY_VIEW_AX_PLATFORM_NODE_DELEGATE_H_
#define UI_VIEWS_ACCESSIBILITY_VIEW_AX_PLATFORM_NODE_DELEGATE_H_
-#include <memory>
+#include <stdint.h>
#include "base/macros.h"
+#include "base/strings/string16.h"
#include "build/build_config.h"
-#include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_data.h"
-#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/accessibility/platform/ax_platform_node_delegate_base.h"
-#include "ui/accessibility/platform/ax_unique_id.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/accessibility/view_accessibility.h"
-#include "ui/views/views_export.h"
#include "ui/views/widget/widget_observer.h"
+namespace ui {
+
+struct AXActionData;
+class AXUniqueId;
+
+} // namespace ui
+
namespace views {
class View;
@@ -29,9 +34,8 @@ class Widget;
// |ViewAXPlatformNodeDelegate| to interface with the native accessibility
// toolkit. This class owns the |AXPlatformNode|, which implements those native
// APIs.
-class VIEWS_EXPORT ViewAXPlatformNodeDelegate
- : public ViewAccessibility,
- public ui::AXPlatformNodeDelegateBase {
+class ViewAXPlatformNodeDelegate : public ViewAccessibility,
+ public ui::AXPlatformNodeDelegateBase {
public:
~ViewAXPlatformNodeDelegate() override;
@@ -46,7 +50,7 @@ class VIEWS_EXPORT ViewAXPlatformNodeDelegate
const ui::AXNodeData& GetData() const override;
int GetChildCount() override;
gfx::NativeViewAccessible ChildAtIndex(int index) override;
- gfx::NativeWindow GetTopLevelWidget() override;
+ gfx::NativeViewAccessible GetNSWindow() override;
gfx::NativeViewAccessible GetParent() override;
gfx::Rect GetClippedScreenBoundsRect() const override;
gfx::Rect GetUnclippedScreenBoundsRect() const override;
@@ -56,8 +60,8 @@ class VIEWS_EXPORT ViewAXPlatformNodeDelegate
bool AccessibilityPerformAction(const ui::AXActionData& data) override;
bool ShouldIgnoreHoveredStateForTesting() override;
bool IsOffscreen() const override;
- const ui::AXUniqueId& GetUniqueId()
- const override; // Also in ViewAccessibility
+ // Also in |ViewAccessibility|.
+ const ui::AXUniqueId& GetUniqueId() const override;
protected:
explicit ViewAXPlatformNodeDelegate(View* view);
@@ -74,8 +78,8 @@ class VIEWS_EXPORT ViewAXPlatformNodeDelegate
void OnMenuEnd();
// We own this, but it is reference-counted on some platforms so we can't use
- // a scoped_ptr. It is dereferenced in the destructor.
- ui::AXPlatformNode* ax_node_;
+ // a unique_ptr. It is destroyed in the destructor.
+ ui::AXPlatformNode* ax_platform_node_;
mutable ui::AXNodeData data_;
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.h b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.h
index 75f679979b2..00506aba54e 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.h
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.h
@@ -17,6 +17,7 @@ class ViewAXPlatformNodeDelegateMac : public ViewAXPlatformNodeDelegate {
~ViewAXPlatformNodeDelegateMac() override;
// |ViewAXPlatformNodeDelegate| overrides:
+ gfx::NativeViewAccessible GetNSWindow() override;
gfx::NativeViewAccessible GetParent() override;
private:
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
index 993119fb012..de71650a132 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_mac.mm
@@ -6,6 +6,7 @@
#include <memory>
+#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -21,14 +22,37 @@ ViewAXPlatformNodeDelegateMac::ViewAXPlatformNodeDelegateMac(View* view)
ViewAXPlatformNodeDelegateMac::~ViewAXPlatformNodeDelegateMac() = default;
+gfx::NativeViewAccessible ViewAXPlatformNodeDelegateMac::GetNSWindow() {
+ auto* widget = view()->GetWidget();
+ if (!widget)
+ return nil;
+
+ auto* top_level_widget = widget->GetTopLevelWidget();
+ if (!top_level_widget)
+ return nil;
+
+ auto* bridge_host = BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ top_level_widget->GetNativeWindow());
+ if (!bridge_host)
+ return nil;
+
+ return bridge_host->GetNativeViewAccessibleForNSWindow();
+}
+
gfx::NativeViewAccessible ViewAXPlatformNodeDelegateMac::GetParent() {
if (view()->parent())
return view()->parent()->GetNativeViewAccessible();
- if (view()->GetWidget())
- return view()->GetWidget()->GetNativeView();
+ auto* widget = view()->GetWidget();
+ if (!widget)
+ return nil;
+
+ auto* bridge_host = BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ view()->GetWidget()->GetNativeWindow());
+ if (!bridge_host)
+ return nil;
- return nullptr;
+ return bridge_host->GetNativeViewAccessibleForNSView();
}
} // namespace views
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 09711e4e6f0..0f796ad1de2 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -5,10 +5,16 @@
#include "ui/views/accessibility/view_ax_platform_node_delegate.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_event_manager.h"
+#include "ui/views/accessibility/ax_event_observer.h"
#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h"
@@ -101,8 +107,8 @@ TEST_F(ViewAXPlatformNodeDelegateTest, RoleShouldMatch) {
}
TEST_F(ViewAXPlatformNodeDelegateTest, BoundsShouldMatch) {
- gfx::Rect bounds =
- gfx::ToEnclosingRect(button_accessibility()->GetData().location);
+ gfx::Rect bounds = gfx::ToEnclosingRect(
+ button_accessibility()->GetData().relative_bounds.bounds);
gfx::Rect screen_bounds =
button_accessibility()->GetUnclippedScreenBoundsRect();
@@ -174,13 +180,16 @@ class DerivedTestView : public View {
void OnBlur() override { SetVisible(false); }
};
-class AxTestViewsDelegate : public TestViewsDelegate {
+class TestAXEventObserver : public AXEventObserver {
public:
- AxTestViewsDelegate() = default;
- ~AxTestViewsDelegate() override = default;
+ TestAXEventObserver() { AXEventManager::Get()->AddObserver(this); }
- void NotifyAccessibilityEvent(View* view,
- ax::mojom::Event event_type) override {
+ ~TestAXEventObserver() override {
+ AXEventManager::Get()->RemoveObserver(this);
+ }
+
+ // AXEventObserver:
+ void OnViewEvent(View* view, ax::mojom::Event event_type) override {
AXAuraObjCache* ax = AXAuraObjCache::GetInstance();
std::vector<AXAuraObjWrapper*> out_children;
AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget());
@@ -188,24 +197,17 @@ class AxTestViewsDelegate : public TestViewsDelegate {
}
private:
- DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestAXEventObserver);
};
-class ViewAccessibilityTest : public ViewsTestBase {
- public:
- ViewAccessibilityTest() = default;
- ~ViewAccessibilityTest() override = default;
- void SetUp() override {
- std::unique_ptr<TestViewsDelegate> views_delegate(
- new AxTestViewsDelegate());
- set_views_delegate(std::move(views_delegate));
- ViewsTestBase::SetUp();
- }
-};
+using ViewAccessibilityTest = ViewsTestBase;
// Check if the destruction of the widget ends successfully if |view|'s
// visibility changed during destruction.
TEST_F(ViewAccessibilityTest, LayoutCalledInvalidateRootView) {
+ // TODO: Construct a real AutomationManagerAura rather than using this
+ // observer to simulate it.
+ TestAXEventObserver observer;
std::unique_ptr<Widget> widget(new Widget);
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
diff --git a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
index b279a468af7..6e37a3a15de 100644
--- a/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
+++ b/chromium/ui/views/accessibility/view_ax_platform_node_delegate_win_unittest.cc
@@ -363,7 +363,7 @@ TEST_F(ViewAXPlatformNodeDelegateWinTest, Overrides) {
alert_view->GetViewAccessibility().OverrideRole(ax::mojom::Role::kAlert);
alert_view->GetViewAccessibility().OverrideName(L"Name");
alert_view->GetViewAccessibility().OverrideDescription("Description");
- alert_view->GetViewAccessibility().OverrideIsLeaf();
+ alert_view->GetViewAccessibility().OverrideIsLeaf(true);
contents_view->AddChildView(alert_view);
// Descendant should be ignored because the parent uses OverrideIsLeaf().
diff --git a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc
index 1ce501ed80f..4fcb3ffb378 100644
--- a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc
+++ b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.cc
@@ -163,19 +163,6 @@ FloodFillInkDropRipple::~FloodFillInkDropRipple() {
AbortAllAnimations();
}
-void FloodFillInkDropRipple::HostSizeChanged(const gfx::Size& new_size) {
- root_layer_.SetBounds(CalculateClipBounds(new_size, clip_insets_));
- switch (target_ink_drop_state()) {
- case InkDropState::ACTION_PENDING:
- case InkDropState::ALTERNATE_ACTION_PENDING:
- case InkDropState::ACTIVATED:
- painted_layer_.SetTransform(GetMaxSizeTargetTransform());
- break;
- default:
- break;
- }
-}
-
void FloodFillInkDropRipple::SnapToActivated() {
InkDropRipple::SnapToActivated();
SetOpacity(visible_opacity_);
diff --git a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h
index 6642f447430..3a63a8a67d3 100644
--- a/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h
+++ b/chromium/ui/views/animation/flood_fill_ink_drop_ripple.h
@@ -66,7 +66,6 @@ class VIEWS_EXPORT FloodFillInkDropRipple : public InkDropRipple {
~FloodFillInkDropRipple() override;
// InkDropRipple:
- void HostSizeChanged(const gfx::Size& new_size) override;
void SnapToActivated() override;
ui::Layer* GetRootLayer() override;
diff --git a/chromium/ui/views/animation/ink_drop_host.h b/chromium/ui/views/animation/ink_drop_host.h
deleted file mode 100644
index 8360d62fd07..00000000000
--- a/chromium/ui/views/animation/ink_drop_host.h
+++ /dev/null
@@ -1,66 +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_ANIMATION_INK_DROP_HOST_H_
-#define UI_VIEWS_ANIMATION_INK_DROP_HOST_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/views/views_export.h"
-
-namespace ui {
-class Layer;
-} // namespace ui
-
-namespace views {
-
-class InkDrop;
-class InkDropRipple;
-class InkDropHighlight;
-
-// Used by the InkDrop to add and remove the ink drop layers from a host's layer
-// tree. Typically the ink drop layer is added to a View's layer but it can also
-// be added to a View's ancestor layer.
-//
-// Note: Some Views do not own a Layer, but you can use
-// View::SetLayer(new ui::Layer(ui::LAYER_NOT_DRAWN)) to force the View to have
-// a lightweight Layer that can parent the ink drop layer.
-class VIEWS_EXPORT InkDropHost {
- public:
- InkDropHost() {}
- virtual ~InkDropHost() {}
-
- // Adds the |ink_drop_layer| in to a visible layer tree.
- virtual void AddInkDropLayer(ui::Layer* ink_drop_layer) = 0;
-
- // Removes |ink_drop_layer| from the layer tree.
- virtual void RemoveInkDropLayer(ui::Layer* ink_drop_layer) = 0;
-
- // Returns a configured InkDrop. In general subclasses will return an
- // InkDropImpl instance that will use the CreateInkDropRipple() and
- // CreateInkDropHighlight() methods to create the visual effects.
- //
- // Subclasses should override this if they need to configure any properties
- // specific to the InkDrop instance. e.g. the AutoHighlightMode of an
- // InkDropImpl instance.
- virtual std::unique_ptr<InkDrop> CreateInkDrop() = 0;
-
- // Creates and returns the visual effect used for press. Used by InkDropImpl
- // instances.
- virtual std::unique_ptr<InkDropRipple> CreateInkDropRipple() const = 0;
-
- // Creates and returns the visual effect used for hover and focus. Used by
- // InkDropImpl instances.
- // Note: InkDropHostView does not accept null return values.
- virtual std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InkDropHost);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_ANIMATION_INK_DROP_HOST_H_
diff --git a/chromium/ui/views/animation/ink_drop_host_view.cc b/chromium/ui/views/animation/ink_drop_host_view.cc
index b98691b786e..9b8181553ae 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view.cc
@@ -9,6 +9,7 @@
#include "ui/events/scoped_target_handler.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_impl.h"
@@ -19,38 +20,24 @@
#include "ui/views/view_properties.h"
namespace views {
-namespace {
-
-// The scale factor to compute the large size of the default
-// SquareInkDropRipple.
-constexpr float kLargeInkDropScale = 1.333f;
-
-// Default opacity of the ink drop when it is visible.
-constexpr float kInkDropVisibleOpacity = 0.175f;
-
-// Default corner radii used for the SquareInkDropRipple.
-constexpr int kInkDropSmallCornerRadius = 2;
-constexpr int kInkDropLargeCornerRadius = 4;
-
-} // namespace
// An EventHandler that is guaranteed to be invoked and is not prone to
// InkDropHostView descendents who do not call
-// InkDropHostView::OnGestureEvent(). Only one instance of this class can exist
-// at any given time for each ink drop host view.
-//
-// TODO(bruthig): Consider getting rid of this class.
-class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
+// InkDropHostView::OnGestureEvent() and InkDropHostView::OnMouseEvent().
+// Only one instance of this class can exist at any given time for each ink drop
+// host view.
+class InkDropHostView::InkDropEventHandler : public ui::EventHandler {
public:
- explicit InkDropGestureHandler(InkDropHostView* host_view)
- : target_handler_(new ui::ScopedTargetHandler(host_view, this)),
+ explicit InkDropEventHandler(InkDropHostView* host_view)
+ : target_handler_(
+ std::make_unique<ui::ScopedTargetHandler>(host_view, this)),
host_view_(host_view) {}
- ~InkDropGestureHandler() override {}
+ ~InkDropEventHandler() override = default;
// ui::EventHandler:
void OnGestureEvent(ui::GestureEvent* event) override {
- if (!host_view_->enabled())
+ if (!host_view_->enabled() || host_view_->ink_drop_mode_ != InkDropMode::ON)
return;
InkDropState current_ink_drop_state =
@@ -63,8 +50,7 @@ class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
return;
ink_drop_state = InkDropState::ACTION_PENDING;
// The ui::ET_GESTURE_TAP_DOWN event needs to be marked as handled so
- // that
- // subsequent events for the gesture are sent to |this|.
+ // that subsequent events for the gesture are sent to |this|.
event->SetHandled();
break;
case ui::ET_GESTURE_LONG_PRESS:
@@ -99,6 +85,23 @@ class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
host_view_->AnimateInkDrop(ink_drop_state, event);
}
+ void OnMouseEvent(ui::MouseEvent* event) override {
+ switch (event->type()) {
+ case ui::ET_MOUSE_ENTERED:
+ host_view_->GetInkDrop()->SetHovered(true);
+ break;
+ case ui::ET_MOUSE_EXITED:
+ host_view_->GetInkDrop()->SetHovered(false);
+ break;
+ case ui::ET_MOUSE_DRAGGED:
+ host_view_->GetInkDrop()->SetHovered(
+ host_view_->GetLocalBounds().Contains(event->location()));
+ break;
+ default:
+ break;
+ }
+ }
+
private:
// Allows |this| to handle all GestureEvents on |host_view_|.
std::unique_ptr<ui::ScopedTargetHandler> target_handler_;
@@ -106,24 +109,11 @@ class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
// The host view to cache ui::Events to when animating the ink drop.
InkDropHostView* host_view_;
- DISALLOW_COPY_AND_ASSIGN(InkDropGestureHandler);
+ DISALLOW_COPY_AND_ASSIGN(InkDropEventHandler);
};
-// static
-
-gfx::Size InkDropHostView::CalculateLargeInkDropSize(
- const gfx::Size& small_size) {
- return gfx::ScaleToCeiledSize(gfx::Size(small_size), kLargeInkDropScale);
-}
-
InkDropHostView::InkDropHostView()
- : ink_drop_mode_(InkDropMode::OFF),
- ink_drop_(nullptr),
- ink_drop_visible_opacity_(kInkDropVisibleOpacity),
- ink_drop_small_corner_radius_(kInkDropSmallCornerRadius),
- ink_drop_large_corner_radius_(kInkDropLargeCornerRadius),
- old_paint_to_layer_(false),
- destroying_(false) {}
+ : ink_drop_event_handler_(std::make_unique<InkDropEventHandler>(this)) {}
InkDropHostView::~InkDropHostView() {
// TODO(bruthig): Improve InkDropImpl to be safer about calling back to
@@ -160,57 +150,42 @@ std::unique_ptr<InkDrop> InkDropHostView::CreateInkDrop() {
}
std::unique_ptr<InkDropRipple> InkDropHostView::CreateInkDropRipple() const {
+ if (GetProperty(kHighlightPathKey)) {
+ return std::make_unique<views::FloodFillInkDropRipple>(
+ size(), gfx::Insets(), GetInkDropCenterBasedOnLastEvent(),
+ GetInkDropBaseColor(), ink_drop_visible_opacity());
+ }
+
return CreateDefaultInkDropRipple(
GetMirroredRect(GetContentsBounds()).CenterPoint());
}
std::unique_ptr<InkDropHighlight> InkDropHostView::CreateInkDropHighlight()
const {
+ if (GetProperty(kHighlightPathKey)) {
+ return std::make_unique<views::InkDropHighlight>(
+ size(), 0, gfx::RectF(GetMirroredRect(GetLocalBounds())).CenterPoint(),
+ GetInkDropBaseColor());
+ }
return CreateDefaultInkDropHighlight(
gfx::RectF(GetMirroredRect(GetContentsBounds())).CenterPoint());
}
std::unique_ptr<views::InkDropMask> InkDropHostView::CreateInkDropMask() const {
- if (gfx::Path* highlight_path = GetProperty(kHighlightPathKey))
+ if (SkPath* highlight_path = GetProperty(kHighlightPathKey))
return std::make_unique<views::PathInkDropMask>(size(), *highlight_path);
return nullptr;
}
-std::unique_ptr<InkDropRipple> InkDropHostView::CreateDefaultInkDropRipple(
- const gfx::Point& center_point,
- const gfx::Size& size) const {
- std::unique_ptr<InkDropRipple> ripple(new SquareInkDropRipple(
- CalculateLargeInkDropSize(size), ink_drop_large_corner_radius_, size,
- ink_drop_small_corner_radius_, center_point, GetInkDropBaseColor(),
- ink_drop_visible_opacity()));
- return ripple;
-}
-
-std::unique_ptr<InkDropHighlight>
-InkDropHostView::CreateDefaultInkDropHighlight(const gfx::PointF& center_point,
- const gfx::Size& size) const {
- std::unique_ptr<InkDropHighlight> highlight(
- new InkDropHighlight(size, ink_drop_small_corner_radius_, center_point,
- GetInkDropBaseColor()));
- highlight->set_explode_size(gfx::SizeF(CalculateLargeInkDropSize(size)));
- return highlight;
+SkColor InkDropHostView::GetInkDropBaseColor() const {
+ NOTREACHED();
+ return gfx::kPlaceholderColor;
}
void InkDropHostView::SetInkDropMode(InkDropMode ink_drop_mode) {
ink_drop_mode_ = ink_drop_mode;
ink_drop_ = nullptr;
-
- if (ink_drop_mode_ != InkDropMode::ON)
- gesture_handler_ = nullptr;
- else if (!gesture_handler_)
- gesture_handler_ = std::make_unique<InkDropGestureHandler>(this);
-}
-
-gfx::Point InkDropHostView::GetInkDropCenterBasedOnLastEvent() const {
- return last_ripple_triggering_event_
- ? last_ripple_triggering_event_->location()
- : GetMirroredRect(GetContentsBounds()).CenterPoint();
}
void InkDropHostView::AnimateInkDrop(InkDropState state,
@@ -245,7 +220,6 @@ void InkDropHostView::ViewHierarchyChanged(
void InkDropHostView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
if (ink_drop_)
ink_drop_->HostSizeChanged(size());
- UpdateInkDropMaskLayerSize(size());
}
void InkDropHostView::VisibilityChanged(View* starting_from, bool is_visible) {
@@ -266,26 +240,38 @@ void InkDropHostView::OnBlur() {
GetInkDrop()->SetFocused(false);
}
-void InkDropHostView::OnMouseEvent(ui::MouseEvent* event) {
- switch (event->type()) {
- case ui::ET_MOUSE_ENTERED:
- GetInkDrop()->SetHovered(true);
- break;
- case ui::ET_MOUSE_EXITED:
- GetInkDrop()->SetHovered(false);
- break;
- case ui::ET_MOUSE_DRAGGED:
- GetInkDrop()->SetHovered(GetLocalBounds().Contains(event->location()));
- break;
- default:
- break;
- }
- View::OnMouseEvent(event);
+std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() {
+ auto ink_drop = std::make_unique<InkDropImpl>(this, size());
+ ink_drop->SetAutoHighlightMode(
+ InkDropImpl::AutoHighlightMode::HIDE_ON_RIPPLE);
+ return ink_drop;
}
-SkColor InkDropHostView::GetInkDropBaseColor() const {
- NOTREACHED();
- return gfx::kPlaceholderColor;
+std::unique_ptr<InkDropImpl>
+InkDropHostView::CreateDefaultFloodFillInkDropImpl() {
+ std::unique_ptr<views::InkDropImpl> ink_drop = CreateDefaultInkDropImpl();
+ ink_drop->SetAutoHighlightMode(
+ views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE);
+ return ink_drop;
+}
+
+std::unique_ptr<InkDropRipple> InkDropHostView::CreateDefaultInkDropRipple(
+ const gfx::Point& center_point,
+ const gfx::Size& size) const {
+ auto ripple = std::make_unique<SquareInkDropRipple>(
+ CalculateLargeInkDropSize(size), ink_drop_large_corner_radius_, size,
+ ink_drop_small_corner_radius_, center_point, GetInkDropBaseColor(),
+ ink_drop_visible_opacity());
+ return ripple;
+}
+
+std::unique_ptr<InkDropHighlight>
+InkDropHostView::CreateDefaultInkDropHighlight(const gfx::PointF& center_point,
+ const gfx::Size& size) const {
+ auto highlight = std::make_unique<InkDropHighlight>(
+ size, ink_drop_small_corner_radius_, center_point, GetInkDropBaseColor());
+ highlight->set_explode_size(gfx::SizeF(CalculateLargeInkDropSize(size)));
+ return highlight;
}
bool InkDropHostView::HasInkDrop() const {
@@ -303,6 +289,12 @@ InkDrop* InkDropHostView::GetInkDrop() {
return ink_drop_.get();
}
+gfx::Point InkDropHostView::GetInkDropCenterBasedOnLastEvent() const {
+ return last_ripple_triggering_event_
+ ? last_ripple_triggering_event_->location()
+ : GetMirroredRect(GetContentsBounds()).CenterPoint();
+}
+
void InkDropHostView::InstallInkDropMask(ui::Layer* ink_drop_layer) {
ink_drop_mask_ = CreateInkDropMask();
if (ink_drop_mask_)
@@ -313,25 +305,13 @@ void InkDropHostView::ResetInkDropMask() {
ink_drop_mask_.reset();
}
-void InkDropHostView::UpdateInkDropMaskLayerSize(const gfx::Size& new_size) {
- if (ink_drop_mask_)
- ink_drop_mask_->UpdateLayerSize(new_size);
-}
-
-std::unique_ptr<InkDropImpl> InkDropHostView::CreateDefaultInkDropImpl() {
- auto ink_drop = std::make_unique<InkDropImpl>(this, size());
- ink_drop->SetAutoHighlightMode(
- InkDropImpl::AutoHighlightMode::HIDE_ON_RIPPLE);
- return ink_drop;
-}
-
-std::unique_ptr<InkDropImpl>
-InkDropHostView::CreateDefaultFloodFillInkDropImpl() {
- std::unique_ptr<views::InkDropImpl> ink_drop =
- InkDropHostView::CreateDefaultInkDropImpl();
- ink_drop->SetAutoHighlightMode(
- views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE);
- return ink_drop;
+// static
+gfx::Size InkDropHostView::CalculateLargeInkDropSize(
+ const gfx::Size& small_size) {
+ // The scale factor to compute the large size of the default
+ // SquareInkDropRipple.
+ constexpr float kLargeInkDropScale = 1.333f;
+ return gfx::ScaleToCeiledSize(gfx::Size(small_size), kLargeInkDropScale);
}
} // namespace views
diff --git a/chromium/ui/views/animation/ink_drop_host_view.h b/chromium/ui/views/animation/ink_drop_host_view.h
index 14929b2564b..f374839b019 100644
--- a/chromium/ui/views/animation/ink_drop_host_view.h
+++ b/chromium/ui/views/animation/ink_drop_host_view.h
@@ -10,25 +10,37 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/views/animation/ink_drop.h"
-#include "ui/views/animation/ink_drop_host.h"
#include "ui/views/view.h"
+namespace gfx {
+class PointF;
+} // namespace gfx
+
+namespace ui {
+class Layer;
+class LocatedEvent;
+} // namespace ui
+
namespace views {
+
+class InkDrop;
+class InkDropHighlight;
class InkDropImpl;
class InkDropMask;
+class InkDropRipple;
+enum class InkDropState;
namespace test {
class InkDropHostViewTestApi;
} // namespace test
// A view that provides InkDropHost functionality.
-class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
+class VIEWS_EXPORT InkDropHostView : public View {
public:
// Used in SetInkDropMode() to specify whether the ink drop effect is enabled
// or not for the view. In case of having an ink drop, it also specifies
- // whether the default gesture event handler for the ink drop should be
- // installed or the subclass will handle gesture events itself.
+ // whether the default event handler for the ink drop should be installed or
+ // the subclass will handle ink drop events itself.
enum class InkDropMode {
OFF,
ON,
@@ -38,12 +50,28 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
InkDropHostView();
~InkDropHostView() override;
- // Overridden from InkDropHost:
- void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
- void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
- std::unique_ptr<InkDrop> CreateInkDrop() override;
- std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
- std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const override;
+ // Adds the |ink_drop_layer| in to a visible layer tree.
+ virtual void AddInkDropLayer(ui::Layer* ink_drop_layer);
+
+ // Removes |ink_drop_layer| from the layer tree.
+ virtual void RemoveInkDropLayer(ui::Layer* ink_drop_layer);
+
+ // Returns a configured InkDrop. In general subclasses will return an
+ // InkDropImpl instance that will use the CreateInkDropRipple() and
+ // CreateInkDropHighlight() methods to create the visual effects.
+ //
+ // Subclasses should override this if they need to configure any properties
+ // specific to the InkDrop instance. e.g. the AutoHighlightMode of an
+ // InkDropImpl instance.
+ virtual std::unique_ptr<InkDrop> CreateInkDrop();
+
+ // Creates and returns the visual effect used for press. Used by InkDropImpl
+ // instances.
+ virtual std::unique_ptr<InkDropRipple> CreateInkDropRipple() const;
+
+ // Creates and returns the visual effect used for hover and focus. Used by
+ // InkDropImpl instances.
+ virtual std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const;
// Subclasses can override to return a mask for the ink drop. By default,
// returns nullptr (i.e no mask).
@@ -51,6 +79,9 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
// https://crbug.com/713359.
virtual std::unique_ptr<views::InkDropMask> CreateInkDropMask() const;
+ // Returns the base color for the ink drop.
+ virtual SkColor GetInkDropBaseColor() const;
+
// Toggle to enable/disable an InkDrop on this View. Descendants can override
// CreateInkDropHighlight() and CreateInkDropRipple() to change the look/feel
// of the InkDrop.
@@ -88,9 +119,24 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
// Size used for the default SquareInkDropRipple.
static constexpr int kDefaultInkDropSize = 24;
- // Returns a large ink drop size based on the |small_size| that works well
- // with the SquareInkDropRipple animation durations.
- static gfx::Size CalculateLargeInkDropSize(const gfx::Size& small_size);
+ // Called after a new InkDrop instance is created.
+ virtual void OnInkDropCreated() {}
+
+ // View:
+ void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) override;
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+ void VisibilityChanged(View* starting_from, bool is_visible) override;
+ void OnFocus() override;
+ void OnBlur() override;
+
+ // Returns an InkDropImpl with default configuration. The base implementation
+ // of CreateInkDrop() delegates to this function.
+ std::unique_ptr<InkDropImpl> CreateDefaultInkDropImpl();
+
+ // Returns an InkDropImpl configured to work well with a flood-fill ink drop
+ // ripple.
+ std::unique_ptr<InkDropImpl> CreateDefaultFloodFillInkDropImpl();
// Returns the default InkDropRipple centered on |center_point|.
std::unique_ptr<InkDropRipple> CreateDefaultInkDropRipple(
@@ -104,26 +150,6 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
const gfx::Size& size = gfx::Size(kDefaultInkDropSize,
kDefaultInkDropSize)) const;
- // Returns the point of the |last_ripple_triggering_event_| if it was a
- // LocatedEvent, otherwise the center point of the local bounds is returned.
- gfx::Point GetInkDropCenterBasedOnLastEvent() const;
-
- // View:
- void ViewHierarchyChanged(
- const ViewHierarchyChangedDetails& details) override;
- void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
- void VisibilityChanged(View* starting_from, bool is_visible) override;
- void OnFocus() override;
- void OnBlur() override;
- void OnMouseEvent(ui::MouseEvent* event) override;
-
- // Overrideable methods to allow views to provide minor tweaks to the default
- // ink drop.
- virtual SkColor GetInkDropBaseColor() const;
-
- // Called after a new InkDrop instance is created.
- virtual void OnInkDropCreated() {}
-
// Returns true if an ink drop instance has been created.
bool HasInkDrop() const;
@@ -132,58 +158,54 @@ class VIEWS_EXPORT InkDropHostView : public View, public InkDropHost {
// subclasses should be able to call SetInkDropMode() during construction.
InkDrop* GetInkDrop();
+ // Returns the point of the |last_ripple_triggering_event_| if it was a
+ // LocatedEvent, otherwise the center point of the local bounds is returned.
+ gfx::Point GetInkDropCenterBasedOnLastEvent() const;
+
// Initializes and sets a mask on |ink_drop_layer|. No-op if
// CreateInkDropMask() returns null.
void InstallInkDropMask(ui::Layer* ink_drop_layer);
void ResetInkDropMask();
- // Updates the ink drop mask layer size to |new_size|. It does nothing if
- // |ink_drop_mask_| is null.
- void UpdateInkDropMaskLayerSize(const gfx::Size& new_size);
-
- // Returns an InkDropImpl configured to work well with a
- // flood-fill ink drop ripple.
- std::unique_ptr<InkDropImpl> CreateDefaultFloodFillInkDropImpl();
-
- // Returns an InkDropImpl with default configuration. The base implementation
- // of CreateInkDrop() delegates to this function.
- std::unique_ptr<InkDropImpl> CreateDefaultInkDropImpl();
+ // Returns a large ink drop size based on the |small_size| that works well
+ // with the SquareInkDropRipple animation durations.
+ static gfx::Size CalculateLargeInkDropSize(const gfx::Size& small_size);
private:
- class InkDropGestureHandler;
- friend class InkDropGestureHandler;
+ class InkDropEventHandler;
friend class test::InkDropHostViewTestApi;
// The last user Event to trigger an ink drop ripple animation.
std::unique_ptr<ui::LocatedEvent> last_ripple_triggering_event_;
// Defines what type of |ink_drop_| to create.
- InkDropMode ink_drop_mode_;
+ InkDropMode ink_drop_mode_ = InkDropMode::OFF;
// Should not be accessed directly. Use GetInkDrop() instead.
std::unique_ptr<InkDrop> ink_drop_;
// Intentionally declared after |ink_drop_| so that it doesn't access a
// destroyed |ink_drop_| during destruction.
- std::unique_ptr<InkDropGestureHandler> gesture_handler_;
+ const std::unique_ptr<InkDropEventHandler> ink_drop_event_handler_;
- float ink_drop_visible_opacity_;
+ float ink_drop_visible_opacity_ = 0.175f;
// Radii used for the SquareInkDropRipple.
- int ink_drop_small_corner_radius_;
- int ink_drop_large_corner_radius_;
+ int ink_drop_small_corner_radius_ = 2;
+ int ink_drop_large_corner_radius_ = 4;
// Determines whether the view was already painting to layer before adding ink
// drop layer.
- bool old_paint_to_layer_;
+ bool old_paint_to_layer_ = false;
- bool destroying_;
+ bool destroying_ = false;
std::unique_ptr<views::InkDropMask> ink_drop_mask_;
DISALLOW_COPY_AND_ASSIGN(InkDropHostView);
};
+
} // namespace views
-#endif // UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_
+#endif // UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_ \ No newline at end of file
diff --git a/chromium/ui/views/animation/ink_drop_host_view_unittest.cc b/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
index 2fa11e3a7aa..85c8b6e85a4 100644
--- a/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_host_view_unittest.cc
@@ -5,6 +5,7 @@
#include "ui/views/animation/ink_drop_host_view.h"
#include "base/macros.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
@@ -16,6 +17,7 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/animation/test/ink_drop_host_view_test_api.h"
+#include "ui/views/animation/test/test_ink_drop.h"
namespace views {
namespace test {
@@ -30,6 +32,8 @@ class TestInkDropHostView : public InkDropHostView {
int on_ink_drop_created_count() const { return on_ink_drop_created_count_; }
+ TestInkDrop* last_created_inkdrop() const { return last_created_inkdrop_; }
+
protected:
SkColor GetInkDropBaseColor() const override {
return gfx::kPlaceholderColor;
@@ -38,8 +42,14 @@ class TestInkDropHostView : public InkDropHostView {
// InkDropHostView:
void OnInkDropCreated() override { ++on_ink_drop_created_count_; }
+ std::unique_ptr<InkDrop> CreateInkDrop() override {
+ last_created_inkdrop_ = new TestInkDrop();
+ return base::WrapUnique(last_created_inkdrop_);
+ }
+
private:
int on_ink_drop_created_count_ = 0;
+ TestInkDrop* last_created_inkdrop_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TestInkDropHostView);
};
@@ -59,6 +69,8 @@ class InkDropHostViewTest : public testing::Test {
std::unique_ptr<base::AutoReset<gfx::Animation::RichAnimationRenderMode>>
animation_mode_reset_;
+ void MouseEventTriggersInkDropHelper(InkDropMode ink_drop_mode);
+
private:
DISALLOW_COPY_AND_ASSIGN(InkDropHostViewTest);
};
@@ -70,6 +82,30 @@ InkDropHostViewTest::InkDropHostViewTest()
InkDropHostViewTest::~InkDropHostViewTest() {}
+void InkDropHostViewTest::MouseEventTriggersInkDropHelper(
+ InkDropMode ink_drop_mode) {
+ test_api_.SetInkDropMode(ink_drop_mode);
+ host_view_.SetEnabled(true);
+
+ // Call GetInkDrop() to make sure the test CreateInkDrop() is created.
+ test_api_.GetInkDrop();
+ if (ink_drop_mode != InkDropMode::OFF)
+ EXPECT_FALSE(host_view_.last_created_inkdrop()->is_hovered());
+ else
+ EXPECT_EQ(host_view_.last_created_inkdrop(), nullptr);
+
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_ENTERED, gfx::Point(0, 0),
+ gfx::Point(0, 0), ui::EventTimeForNow(),
+ ui::EF_IS_SYNTHESIZED, 0);
+
+ host_view_.GetTargetHandler()->OnEvent(&mouse_event);
+
+ if (ink_drop_mode != InkDropMode::OFF)
+ EXPECT_TRUE(host_view_.last_created_inkdrop()->is_hovered());
+ else
+ EXPECT_EQ(host_view_.last_created_inkdrop(), nullptr);
+}
+
// Verifies the return value of GetInkDropCenterBasedOnLastEvent() for a null
// Event.
TEST_F(InkDropHostViewTest, GetInkDropCenterBasedOnLastEventForNullEvent) {
@@ -118,22 +154,22 @@ TEST_F(InkDropHostViewTest, OnInkDropCreatedOnlyNotfiedOnCreation) {
EXPECT_EQ(2, host_view_.on_ink_drop_created_count());
}
-// Verifies that SetInkDropMode() sets up gesture handling properly.
-TEST_F(InkDropHostViewTest, SetInkDropModeGestureHandler) {
- EXPECT_FALSE(test_api_.HasGestureHandler());
-
- test_api_.SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
- EXPECT_FALSE(test_api_.HasGestureHandler());
-
- test_api_.SetInkDropMode(InkDropMode::ON);
- EXPECT_TRUE(test_api_.HasGestureHandler());
+// Verifies that mouse events trigger ink drops when ink drop mode is ON.
+TEST_F(InkDropHostViewTest, MouseEventsTriggerInkDropsWhenInkDropIsOn) {
+ MouseEventTriggersInkDropHelper(InkDropMode::ON);
+}
- // Enabling gesture handler the second time should just work (no crash).
- test_api_.SetInkDropMode(InkDropMode::ON);
- EXPECT_TRUE(test_api_.HasGestureHandler());
+// Verifies that mouse events trigger ink drops when ink drop mode is
+// ON_NO_GESTURE_HANDLER.
+TEST_F(InkDropHostViewTest,
+ MouseEventsTriggerInkDropsWhenInkDropIsOnNoGestureHandler) {
+ MouseEventTriggersInkDropHelper(InkDropMode::ON_NO_GESTURE_HANDLER);
+}
- test_api_.SetInkDropMode(InkDropMode::OFF);
- EXPECT_FALSE(test_api_.HasGestureHandler());
+// Verifies that mouse events do not trigger ink drops when ink drop mode is
+// OFF.
+TEST_F(InkDropHostViewTest, MouseEventsDontTriggerInkDropsWhenInkDropIsOff) {
+ MouseEventTriggersInkDropHelper(InkDropMode::OFF);
}
// Verifies that ink drops are not shown when the host is disabled.
@@ -152,6 +188,24 @@ TEST_F(InkDropHostViewTest,
InkDropState::HIDDEN);
}
+// Verifies that ink drops are not triggered by gesture events when ink drop
+// mode is ON_NO_GESTURE_EVENT or OFF.
+TEST_F(InkDropHostViewTest,
+ GestureEventsDontTriggerInkDropsWhenInkDropModeIsNotOn) {
+ for (auto ink_drop_mode :
+ {InkDropMode::ON_NO_GESTURE_HANDLER, InkDropMode::OFF}) {
+ test_api_.SetInkDropMode(ink_drop_mode);
+ ui::GestureEvent gesture_event(
+ 0.f, 0.f, 0, ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+
+ host_view_.GetTargetHandler()->OnEvent(&gesture_event);
+
+ EXPECT_EQ(test_api_.GetInkDrop()->GetTargetInkDropState(),
+ InkDropState::HIDDEN);
+ }
+}
+
#if defined(OS_WIN)
TEST_F(InkDropHostViewTest, NoInkDropOnTouchOrGestureEvents) {
host_view_.SetSize(gfx::Size(20, 20));
diff --git a/chromium/ui/views/animation/ink_drop_impl.cc b/chromium/ui/views/animation/ink_drop_impl.cc
index 7e00a268fd2..a28b1b82e7f 100644
--- a/chromium/ui/views/animation/ink_drop_impl.cc
+++ b/chromium/ui/views/animation/ink_drop_impl.cc
@@ -8,7 +8,7 @@
#include "base/timer/timer.h"
#include "ui/compositor/layer.h"
#include "ui/views/animation/ink_drop_highlight.h"
-#include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/animation/ink_drop_host_view.h"
#include "ui/views/animation/square_ink_drop_ripple.h"
#include "ui/views/style/platform_style.h"
@@ -584,7 +584,8 @@ InkDropImpl::HighlightStateFactory::CreateVisibleState(
return nullptr;
}
-InkDropImpl::InkDropImpl(InkDropHost* ink_drop_host, const gfx::Size& host_size)
+InkDropImpl::InkDropImpl(InkDropHostView* ink_drop_host,
+ const gfx::Size& host_size)
: ink_drop_host_(ink_drop_host),
root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)),
root_layer_added_to_host_(false),
@@ -629,8 +630,25 @@ void InkDropImpl::HostSizeChanged(const gfx::Size& new_size) {
// when a mask layer is applied to it. This will not affect clipping if no
// mask layer is set.
root_layer_->SetBounds(gfx::Rect(new_size));
- if (ink_drop_ripple_)
- ink_drop_ripple_->HostSizeChanged(new_size);
+
+ const bool create_ink_drop_ripple = !!ink_drop_ripple_;
+ const InkDropState state = GetTargetInkDropState();
+ DestroyInkDropRipple();
+
+ if (highlight_) {
+ bool visible = highlight_->IsFadingInOrVisible();
+ DestroyInkDropHighlight();
+ // Both the ripple and the highlight must have been destroyed before
+ // recreating either of them otherwise the mask will not get recreated.
+ CreateInkDropHighlight();
+ if (visible)
+ highlight_->FadeIn(base::TimeDelta());
+ }
+
+ if (create_ink_drop_ripple) {
+ CreateInkDropRipple();
+ ink_drop_ripple_->SnapToState(state);
+ }
}
InkDropState InkDropImpl::GetTargetInkDropState() const {
diff --git a/chromium/ui/views/animation/ink_drop_impl.h b/chromium/ui/views/animation/ink_drop_impl.h
index 05862e299d8..82061d7e778 100644
--- a/chromium/ui/views/animation/ink_drop_impl.h
+++ b/chromium/ui/views/animation/ink_drop_impl.h
@@ -22,7 +22,7 @@ class InkDropImplTestApi;
} // namespace test
class InkDropRipple;
-class InkDropHost;
+class InkDropHostView;
class InkDropHighlight;
// A functional implementation of an InkDrop.
@@ -50,7 +50,7 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
//
// By default the highlight will be made visible while |this| is hovered but
// not focused and the NONE AutoHighlightMode will be used.
- InkDropImpl(InkDropHost* ink_drop_host, const gfx::Size& host_size);
+ InkDropImpl(InkDropHostView* ink_drop_host, const gfx::Size& host_size);
~InkDropImpl() override;
// Auto highlighting is a mechanism to show/hide the highlight based on the
@@ -274,7 +274,7 @@ class VIEWS_EXPORT InkDropImpl : public InkDrop,
// The host of the ink drop. Used to create the ripples and highlights, and to
// add/remove the root layer to/from it.
- InkDropHost* ink_drop_host_;
+ InkDropHostView* ink_drop_host_;
// The root Layer that parents the InkDropRipple layers and the
// InkDropHighlight layers. The |root_layer_| is the one that is added and
diff --git a/chromium/ui/views/animation/ink_drop_impl_unittest.cc b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
index e485be3aba9..d5d6ecf641d 100644
--- a/chromium/ui/views/animation/ink_drop_impl_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_impl_unittest.cc
@@ -14,6 +14,7 @@
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/animation/animation_test_api.h"
+#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/animation/test/ink_drop_impl_test_api.h"
#include "ui/views/animation/test/test_ink_drop_host.h"
#include "ui/views/test/platform_test_helper.h"
@@ -32,6 +33,10 @@ class InkDropImplTest : public testing::Test {
InkDropImpl* ink_drop() { return ink_drop_.get(); }
+ InkDropRipple* ink_drop_ripple() { return ink_drop_->ink_drop_ripple_.get(); }
+
+ InkDropHighlight* ink_drop_highlight() { return ink_drop_->highlight_.get(); }
+
test::InkDropImplTestApi* test_api() { return test_api_.get(); }
// Runs all the pending tasks in |task_runner_|. This can be used to progress
@@ -293,6 +298,30 @@ TEST_F(InkDropImplTest, SuccessfulAnimationEndedDuringDestruction) {
DestroyInkDrop();
}
+// Make sure the InkDropRipple and InkDropHighlight get recreated when the host
+// size changes (https:://crbug.com/899104).
+TEST_F(InkDropImplTest, RippleAndHighlightRecreatedOnSizeChange) {
+ test_api()->SetShouldHighlight(true);
+ ink_drop()->AnimateToState(InkDropState::ACTIVATED);
+ EXPECT_EQ(1, ink_drop_host()->num_ink_drop_ripples_created());
+ EXPECT_EQ(1, ink_drop_host()->num_ink_drop_highlights_created());
+ EXPECT_EQ(ink_drop_host()->last_ink_drop_ripple(), ink_drop_ripple());
+ EXPECT_EQ(ink_drop_host()->last_ink_drop_highlight(), ink_drop_highlight());
+
+ const gfx::Rect bounds(5, 6, 7, 8);
+ ink_drop_host()->SetBoundsRect(bounds);
+ // SetBoundsRect() calls HostSizeChanged(), but only when
+ // InkDropHostView::ink_drop_ is set, but it's not in testing. So call this
+ // function manually.
+ ink_drop()->HostSizeChanged(ink_drop_host()->size());
+ EXPECT_EQ(2, ink_drop_host()->num_ink_drop_ripples_created());
+ EXPECT_EQ(2, ink_drop_host()->num_ink_drop_highlights_created());
+ EXPECT_EQ(ink_drop_host()->last_ink_drop_ripple(), ink_drop_ripple());
+ EXPECT_EQ(ink_drop_host()->last_ink_drop_highlight(), ink_drop_highlight());
+ EXPECT_EQ(bounds.size(), ink_drop_ripple()->GetRootLayer()->size());
+ EXPECT_EQ(bounds.size(), ink_drop_highlight()->layer()->size());
+}
+
////////////////////////////////////////////////////////////////////////////////
//
// Common AutoHighlightMode tests
diff --git a/chromium/ui/views/animation/ink_drop_mask.cc b/chromium/ui/views/animation/ink_drop_mask.cc
index 63c93c61b4a..eea9824bcc2 100644
--- a/chromium/ui/views/animation/ink_drop_mask.cc
+++ b/chromium/ui/views/animation/ink_drop_mask.cc
@@ -24,10 +24,6 @@ InkDropMask::~InkDropMask() {
layer_.set_delegate(nullptr);
}
-void InkDropMask::UpdateLayerSize(const gfx::Size& new_layer_size) {
- layer_.SetBounds(gfx::Rect(new_layer_size));
-}
-
void InkDropMask::OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) {}
@@ -78,7 +74,7 @@ void CircleInkDropMask::OnPaintLayer(const ui::PaintContext& context) {
// PathInkDropMask
PathInkDropMask::PathInkDropMask(const gfx::Size& layer_size,
- const gfx::Path& path)
+ const SkPath& path)
: InkDropMask(layer_size), path_(path) {}
void PathInkDropMask::OnPaintLayer(const ui::PaintContext& context) {
diff --git a/chromium/ui/views/animation/ink_drop_mask.h b/chromium/ui/views/animation/ink_drop_mask.h
index 1a3fa87e066..8631269a403 100644
--- a/chromium/ui/views/animation/ink_drop_mask.h
+++ b/chromium/ui/views/animation/ink_drop_mask.h
@@ -24,10 +24,6 @@ class VIEWS_EXPORT InkDropMask : public ui::LayerDelegate {
public:
~InkDropMask() override;
- // Should be called whenever the masked layer is resized so that the mask
- // layer size always matches that of the layer it is masking.
- void UpdateLayerSize(const gfx::Size& new_layer_size);
-
ui::Layer* layer() { return &layer_; }
protected:
@@ -80,13 +76,13 @@ class VIEWS_EXPORT CircleInkDropMask : public InkDropMask {
// 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);
+ PathInkDropMask(const gfx::Size& layer_size, const SkPath& path);
private:
// InkDropMask:
void OnPaintLayer(const ui::PaintContext& context) override;
- gfx::Path path_;
+ SkPath path_;
DISALLOW_COPY_AND_ASSIGN(PathInkDropMask);
};
diff --git a/chromium/ui/views/animation/ink_drop_ripple.cc b/chromium/ui/views/animation/ink_drop_ripple.cc
index ea16770dd00..3b6ae08cb51 100644
--- a/chromium/ui/views/animation/ink_drop_ripple.cc
+++ b/chromium/ui/views/animation/ink_drop_ripple.cc
@@ -30,8 +30,6 @@ InkDropRipple::InkDropRipple()
InkDropRipple::~InkDropRipple() {}
-void InkDropRipple::HostSizeChanged(const gfx::Size& new_size) {}
-
void InkDropRipple::AnimateToState(InkDropState ink_drop_state) {
// Does not return early if |target_ink_drop_state_| == |ink_drop_state| for
// two reasons.
@@ -70,6 +68,20 @@ void InkDropRipple::AnimateToState(InkDropState ink_drop_state) {
// AnimationEndedCallback which can delete |this|.
}
+void InkDropRipple::SnapToState(InkDropState ink_drop_state) {
+ switch (ink_drop_state) {
+ case InkDropState::HIDDEN:
+ SnapToHidden();
+ break;
+ case InkDropState::ACTIVATED:
+ SnapToActivated();
+ break;
+ default:
+ AbortAllAnimations();
+ target_ink_drop_state_ = ink_drop_state;
+ }
+}
+
void InkDropRipple::SnapToActivated() {
AbortAllAnimations();
// |animation_observer| will be deleted when AnimationEndedCallback() returns
diff --git a/chromium/ui/views/animation/ink_drop_ripple.h b/chromium/ui/views/animation/ink_drop_ripple.h
index 645abff0204..e47be1dc82b 100644
--- a/chromium/ui/views/animation/ink_drop_ripple.h
+++ b/chromium/ui/views/animation/ink_drop_ripple.h
@@ -54,16 +54,15 @@ class VIEWS_EXPORT InkDropRipple {
// AnimationStarted(s2).
void set_observer(InkDropRippleObserver* observer) { observer_ = observer; }
- // Called by ink drop whenever its host's size is changed in order to give the
- // ripple an opportunity to handle dynamic host resizes.
- virtual void HostSizeChanged(const gfx::Size& new_size);
-
// Animates from the current InkDropState to the new |ink_drop_state|.
//
// NOTE: GetTargetInkDropState() should return the new |ink_drop_state| value
// to any observers being notified as a result of the call.
void AnimateToState(InkDropState ink_drop_state);
+ // Snaps from the current InkDropState to the new |ink_drop_state|.
+ void SnapToState(InkDropState ink_drop_state);
+
InkDropState target_ink_drop_state() const { return target_ink_drop_state_; }
// Immediately aborts all in-progress animations and hides the ink drop.
diff --git a/chromium/ui/views/animation/ink_drop_unittest.cc b/chromium/ui/views/animation/ink_drop_unittest.cc
index 4cee71e8dd7..903eef90840 100644
--- a/chromium/ui/views/animation/ink_drop_unittest.cc
+++ b/chromium/ui/views/animation/ink_drop_unittest.cc
@@ -12,7 +12,7 @@
#include "ui/base/test/material_design_controller_test_api.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/views/animation/ink_drop.h"
-#include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/animation/ink_drop_host_view.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_state.h"
#include "ui/views/animation/ink_drop_stub.h"
diff --git a/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc b/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc
index d42c821125a..cffabb85ff9 100644
--- a/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc
+++ b/chromium/ui/views/animation/square_ink_drop_ripple_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
@@ -266,7 +267,7 @@ TEST_F(SquareInkDropRippleCalculateTransformsTest, RippleIsPixelAligned) {
SCOPED_TRACE(testing::Message()
<< "target_size=" << target_size << " dsf=" << dsf);
host_view->layer()->GetCompositor()->SetScaleAndSize(
- dsf, gfx::Size(100, 100), viz::LocalSurfaceId());
+ dsf, gfx::Size(100, 100), viz::LocalSurfaceIdAllocation());
SquareInkDropRippleTestApi::InkDropTransforms transforms;
test_api.CalculateRectTransforms(gfx::Size(target_size, target_size), 0,
diff --git a/chromium/ui/views/bubble/bubble_border.cc b/chromium/ui/views/bubble/bubble_border.cc
index 88e4653b928..60d6ed5ac06 100644
--- a/chromium/ui/views/bubble/bubble_border.cc
+++ b/chromium/ui/views/bubble/bubble_border.cc
@@ -12,7 +12,6 @@
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "third_party/skia/include/core/SkPath.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
@@ -35,9 +34,6 @@ namespace {
// key the cache.
typedef std::tuple<int, SkColor> ShadowCacheKey;
-// The border corner radius for material design bubble borders.
-constexpr int kMaterialDesignCornerRadius = 2;
-
// The border is stroked at 1px, but for the purposes of reserving space we have
// to deal in dip coordinates, so round up to 1dip.
constexpr int kBorderThicknessDip = 1;
@@ -172,7 +168,8 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& anchor_rect,
}
int BubbleBorder::GetBorderCornerRadius() const {
- return corner_radius_.value_or(kMaterialDesignCornerRadius);
+ constexpr int kCornerRadius = 2;
+ return corner_radius_.value_or(kCornerRadius);
}
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) {
diff --git a/chromium/ui/views/bubble/bubble_border_unittest.cc b/chromium/ui/views/bubble/bubble_border_unittest.cc
index 54476123fc1..f4f1c908206 100644
--- a/chromium/ui/views/bubble/bubble_border_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_border_unittest.cc
@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "base/strings/stringprintf.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/test/views_test_base.h"
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
index 434ae1ea7db..447cab79b78 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -8,7 +8,6 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/default_style.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect.h"
@@ -17,7 +16,6 @@
#include "ui/views/layout/layout_manager.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/view_properties.h"
-#include "ui/views/views_delegate.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_client_view.h"
@@ -135,7 +133,6 @@ bool BubbleDialogDelegateView::ShouldShowCloseButton() const {
ClientView* BubbleDialogDelegateView::CreateClientView(Widget* widget) {
DialogClientView* client = new DialogClientView(widget, GetContentsView());
- widget->non_client_view()->set_mirror_client_in_rtl(mirror_arrow_in_rtl_);
return client;
}
@@ -149,7 +146,7 @@ NonClientFrameView* BubbleDialogDelegateView::CreateNonClientFrameView(
frame->SetFootnoteView(CreateFootnoteView());
BubbleBorder::Arrow adjusted_arrow = arrow();
- if (base::i18n::IsRTL() && mirror_arrow_in_rtl_)
+ if (base::i18n::IsRTL())
adjusted_arrow = BubbleBorder::horizontal_mirror(adjusted_arrow);
std::unique_ptr<BubbleBorder> border =
std::make_unique<BubbleBorder>(adjusted_arrow, GetShadow(), color());
@@ -193,7 +190,7 @@ void BubbleDialogDelegateView::OnWidgetActivationChanged(Widget* widget,
// Install |mac_bubble_closer_| the first time the widget becomes active.
if (active && !mac_bubble_closer_ && GetWidget()) {
mac_bubble_closer_ = std::make_unique<ui::BubbleCloser>(
- GetWidget()->GetNativeWindow(),
+ GetWidget()->GetNativeWindow().GetNativeNSWindow(),
base::BindRepeating(&BubbleDialogDelegateView::OnDeactivate,
base::Unretained(this)));
}
@@ -224,7 +221,7 @@ void BubbleDialogDelegateView::SetHighlightedButton(
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)
+ if (visible && highlighted_button != highlighted_button_tracker_.view())
UpdateHighlightedButton(false);
highlighted_button_tracker_.SetView(highlighted_button);
if (visible)
@@ -266,16 +263,6 @@ void BubbleDialogDelegateView::OnAnchorBoundsChanged() {
SizeToContents();
}
-void BubbleDialogDelegateView::EnableFocusTraversalFromAnchorView() {
- DCHECK(GetWidget());
- DCHECK(GetAnchorView());
- GetWidget()->SetFocusTraversableParent(
- anchor_widget()->GetFocusTraversable());
- GetWidget()->SetFocusTraversableParentView(GetAnchorView());
- GetAnchorView()->SetProperty(kAnchoredDialogKey,
- static_cast<BubbleDialogDelegateView*>(this));
-}
-
BubbleDialogDelegateView::BubbleDialogDelegateView()
: BubbleDialogDelegateView(nullptr, BubbleBorder::TOP_LEFT) {}
@@ -286,8 +273,6 @@ BubbleDialogDelegateView::BubbleDialogDelegateView(View* anchor_view,
anchor_view_tracker_(std::make_unique<ViewTracker>()),
anchor_widget_(nullptr),
arrow_(arrow),
- mirror_arrow_in_rtl_(
- ViewsDelegate::GetInstance()->ShouldMirrorArrowsInRTL()),
shadow_(shadow),
color_explicitly_set_(false),
accept_events_(true),
@@ -377,8 +362,12 @@ void BubbleDialogDelegateView::SetAnchorView(View* anchor_view) {
// point. (It's safe to skip this, since if we were to update the
// bounds when |anchor_view| is NULL, the bubble won't move.)
OnAnchorBoundsChanged();
+ }
- EnableFocusTraversalFromAnchorView();
+ if (anchor_view) {
+ // Make sure that focus can move into here from the anchor view (but not
+ // out, focus will cycle inside the dialog once it gets here).
+ anchor_view->SetProperty(kAnchoredDialogKey, this);
}
}
diff --git a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
index 8d6561420c6..a5b2d11c96b 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -77,8 +77,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
BubbleBorder::Arrow arrow() const { return arrow_; }
void SetArrow(BubbleBorder::Arrow arrow);
- void set_mirror_arrow_in_rtl(bool mirror) { mirror_arrow_in_rtl_ = mirror; }
-
BubbleBorder::Shadow GetShadow() const;
void set_shadow(BubbleBorder::Shadow shadow) { shadow_ = shadow; }
@@ -121,11 +119,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// bounds change as a result of the widget's bounds changing.
void OnAnchorBoundsChanged();
- // If this is called, enables focus to traverse from the anchor view
- // to inside this dialog and back out. This may become the default in
- // the future.
- void EnableFocusTraversalFromAnchorView();
-
protected:
BubbleDialogDelegateView();
// |shadow| usually doesn't need to be explicitly set, just uses the default
@@ -210,9 +203,6 @@ class VIEWS_EXPORT BubbleDialogDelegateView : public DialogDelegateView,
// The arrow's location on the bubble.
BubbleBorder::Arrow arrow_;
- // Automatically mirror the arrow in RTL layout.
- bool mirror_arrow_in_rtl_;
-
// Bubble border shadow to use.
BubbleBorder::Shadow shadow_;
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 cf205c20d3f..dd72bf4f8e6 100644
--- a/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_dialog_delegate_view_unittest.cc
@@ -132,25 +132,6 @@ TEST_F(BubbleDialogDelegateViewTest, CreateDelegate) {
EXPECT_TRUE(bubble_observer.widget_closed());
}
-TEST_F(BubbleDialogDelegateViewTest, MirrorArrowInRtl) {
- std::string default_locale = base::i18n::GetConfiguredLocale();
- std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
- for (bool rtl : {false, true}) {
- base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
- EXPECT_EQ(rtl, base::i18n::IsRTL());
- for (bool mirror : {false, true}) {
- TestBubbleDialogDelegateView* bubble =
- new TestBubbleDialogDelegateView(anchor_widget->GetContentsView());
- bubble->set_mirror_arrow_in_rtl(mirror);
- BubbleDialogDelegateView::CreateBubble(bubble);
- EXPECT_EQ(rtl && mirror ? BubbleBorder::horizontal_mirror(bubble->arrow())
- : bubble->arrow(),
- bubble->GetBubbleFrameView()->bubble_border()->arrow());
- }
- }
- base::i18n::SetICUDefaultLocale(default_locale);
-}
-
TEST_F(BubbleDialogDelegateViewTest, CloseAnchorWidget) {
std::unique_ptr<Widget> anchor_widget(CreateTestWidget());
BubbleDialogDelegateView* bubble_delegate =
diff --git a/chromium/ui/views/bubble/bubble_frame_view.cc b/chromium/ui/views/bubble/bubble_frame_view.cc
index 02aa4a05ff8..b8142736255 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view.cc
@@ -25,6 +25,7 @@
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/bubble/footnote_container_view.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/image_view.h"
@@ -68,21 +69,6 @@ int GetOffScreenLength(const gfx::Rect& available_bounds,
} // namespace
-// A container that changes visibility with its contents.
-class FootnoteContainerView : public View {
- public:
- FootnoteContainerView() {}
-
- // View:
- void ChildVisibilityChanged(View* child) override {
- DCHECK_EQ(child_count(), 1);
- SetVisible(child->visible());
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FootnoteContainerView);
-};
-
// static
const char BubbleFrameView::kViewClassName[] = "BubbleFrameView";
@@ -134,7 +120,7 @@ Button* BubbleFrameView::CreateCloseButton(ButtonListener* listener) {
close_button->SizeToPreferredSize();
// Let the close button use a circular inkdrop shape.
- auto highlight_path = std::make_unique<gfx::Path>();
+ auto highlight_path = std::make_unique<SkPath>();
highlight_path->addOval(gfx::RectToSkRect(gfx::Rect(close_button->size())));
close_button->SetProperty(kHighlightPathKey, highlight_path.release());
@@ -449,6 +435,10 @@ void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
void BubbleFrameView::SetBubbleBorder(std::unique_ptr<BubbleBorder> border) {
bubble_border_ = border.get();
+
+ if (footnote_container_)
+ footnote_container_->SetCornerRadius(border->GetBorderCornerRadius());
+
SetBorder(std::move(border));
// Update the background, which relies on the border.
@@ -460,15 +450,9 @@ void BubbleFrameView::SetFootnoteView(View* view) {
return;
DCHECK(!footnote_container_);
- footnote_container_ = new FootnoteContainerView();
- footnote_container_->SetLayoutManager(
- std::make_unique<BoxLayout>(BoxLayout::kVertical, footnote_margins_, 0));
- footnote_container_->SetBackground(
- CreateSolidBackground(gfx::kGoogleGrey050));
- footnote_container_->SetBorder(
- CreateSolidSidedBorder(1, 0, 0, 0, gfx::kGoogleGrey200));
- footnote_container_->AddChildView(view);
- footnote_container_->SetVisible(view->visible());
+ int radius = bubble_border_ ? bubble_border_->GetBorderCornerRadius() : 0;
+ footnote_container_ =
+ new FootnoteContainerView(footnote_margins_, view, radius);
AddChildView(footnote_container_);
}
diff --git a/chromium/ui/views/bubble/bubble_frame_view.h b/chromium/ui/views/bubble/bubble_frame_view.h
index bfb407a231f..40175e1385c 100644
--- a/chromium/ui/views/bubble/bubble_frame_view.h
+++ b/chromium/ui/views/bubble/bubble_frame_view.h
@@ -18,6 +18,7 @@
namespace views {
class BubbleBorder;
+class FootnoteContainerView;
class ImageView;
// The non-client frame view of bubble-styled widgets.
@@ -183,7 +184,7 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView,
Button* close_;
// A view to contain the footnote view, if it exists.
- View* footnote_container_;
+ FootnoteContainerView* footnote_container_;
// Whether the close button was clicked.
bool close_button_clicked_;
diff --git a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
index 38930c39de0..bd244a5bfc9 100644
--- a/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/chromium/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -19,6 +19,7 @@
#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/bubble/footnote_container_view.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/metrics.h"
#include "ui/views/test/test_layout_provider.h"
diff --git a/chromium/ui/views/bubble/footnote_container_view.cc b/chromium/ui/views/bubble/footnote_container_view.cc
new file mode 100644
index 00000000000..e8a28b3b035
--- /dev/null
+++ b/chromium/ui/views/bubble/footnote_container_view.cc
@@ -0,0 +1,78 @@
+// 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/bubble/footnote_container_view.h"
+
+#include "cc/paint/paint_flags.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace views {
+
+namespace {
+
+// A solid color background where the bottom two corners are rounded.
+class HalfRoundedRectBackground : public Background {
+ public:
+ explicit HalfRoundedRectBackground(SkColor color, float radius)
+ : radius_(radius) {
+ SetNativeControlColor(color);
+ }
+ ~HalfRoundedRectBackground() override = default;
+
+ // Background:
+ void Paint(gfx::Canvas* canvas, View* view) const override {
+ cc::PaintFlags flags;
+ flags.setAntiAlias(true);
+ flags.setStyle(cc::PaintFlags::kFill_Style);
+ flags.setColor(get_color());
+ // Draw a rounded rect that spills outside of the clipping area, so that the
+ // rounded corners only show in the bottom 2 corners.
+ gfx::RectF spilling_rect(view->GetLocalBounds());
+ spilling_rect.set_y(spilling_rect.x() - radius_);
+ spilling_rect.set_height(spilling_rect.height() + radius_);
+ canvas->DrawRoundRect(spilling_rect, radius_, flags);
+ }
+
+ private:
+ float radius_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(HalfRoundedRectBackground);
+};
+
+} // namespace
+
+FootnoteContainerView::FootnoteContainerView(const gfx::Insets& margins,
+ View* child_view,
+ float corner_radius) {
+ SetLayoutManager(
+ std::make_unique<BoxLayout>(BoxLayout::kVertical, margins, 0));
+ SetCornerRadius(corner_radius);
+ SetBorder(CreateSolidSidedBorder(1, 0, 0, 0, gfx::kGoogleGrey200));
+ AddChildView(child_view);
+ SetVisible(child_view->visible());
+}
+
+FootnoteContainerView::~FootnoteContainerView() = default;
+
+void FootnoteContainerView::SetCornerRadius(float corner_radius) {
+ // TODO(crbug.com/893598): Finalize dark mode color.
+ SkColor background_color = GetNativeTheme()->SystemDarkModeEnabled()
+ ? gfx::kGoogleGrey800
+ : gfx::kGoogleGrey050;
+ SetBackground(std::make_unique<HalfRoundedRectBackground>(background_color,
+ corner_radius));
+}
+
+void FootnoteContainerView::ChildVisibilityChanged(View* child) {
+ DCHECK_EQ(child_count(), 1);
+ SetVisible(child->visible());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/bubble/footnote_container_view.h b/chromium/ui/views/bubble/footnote_container_view.h
new file mode 100644
index 00000000000..2b4bea9235f
--- /dev/null
+++ b/chromium/ui/views/bubble/footnote_container_view.h
@@ -0,0 +1,32 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_BUBBLE_FOOTNOTE_CONTAINER_VIEW_H_
+#define UI_VIEWS_BUBBLE_FOOTNOTE_CONTAINER_VIEW_H_
+
+#include "ui/views/view.h"
+
+namespace views {
+
+// A container that changes visibility with its contents, and draws a solid
+// background with rounded corners at the bottom.
+class FootnoteContainerView : public View {
+ public:
+ FootnoteContainerView(const gfx::Insets& margins,
+ View* child_view,
+ float corner_radius);
+ ~FootnoteContainerView() override;
+
+ void SetCornerRadius(float corner_radius);
+
+ // View:
+ void ChildVisibilityChanged(View* child) override;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FootnoteContainerView);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_BUBBLE_FOOTNOTE_CONTAINER_VIEW_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 5451da8d177..0a06d9a9bd1 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -13,6 +13,7 @@
#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/cocoa/accessibility_focus_overrider.h"
#include "ui/base/ime/input_method_delegate.h"
#include "ui/compositor/layer_owner.h"
#include "ui/views/cocoa/bridge_factory_host.h"
@@ -26,6 +27,7 @@
#include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
@class NativeWidgetMacNSWindow;
+@class NSAccessibilityRemoteUIElement;
@class NSView;
namespace ui {
@@ -47,14 +49,16 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
public DialogObserver,
public FocusChangeListener,
public ui::internal::InputMethodDelegate,
+ public ui::AccessibilityFocusOverrider::Client,
public ui::LayerDelegate,
public ui::LayerOwner,
public ui::AcceleratedWidgetMacNSView {
public:
- // Retrieves the bridge host associated with the given NSWindow. Returns null
- // if the supplied handle has no associated Widget.
+ // Retrieves the bridge host associated with the given NativeWindow. Returns
+ // null if the supplied handle has no associated Widget.
static BridgedNativeWidgetHostImpl* GetFromNativeWindow(
gfx::NativeWindow window);
+ static BridgedNativeWidgetHostImpl* GetFromNativeView(gfx::NativeView view);
// Unique integer id handles are used to bridge between the
// BridgedNativeWidgetHostImpl in one process and the BridgedNativeWidgetHost
@@ -87,6 +91,12 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// NSWindow. Otherwise, it mirrors the id and bounds of the child window.
NativeWidgetMacNSWindow* GetLocalNSWindow() const;
+ // Return the accessibility object for the content NSView.
+ gfx::NativeViewAccessible GetNativeViewAccessibleForNSView() const;
+
+ // Return the accessibility object for the NSWindow.
+ gfx::NativeViewAccessible GetNativeViewAccessibleForNSWindow() const;
+
// The mojo interface through which to communicate with the underlying
// NSWindow and NSView.
views_bridge_mac::mojom::BridgedNativeWidget* bridge() const;
@@ -196,7 +206,7 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
void RankNSViewsRecursive(View* view, std::map<NSView*, int>* rank) const;
// BridgedNativeWidgetHostHelper:
- NSView* GetNativeViewAccessible() override;
+ id GetNativeViewAccessible() override;
void DispatchKeyEvent(ui::KeyEvent* event) override;
bool DispatchKeyEventToMenuController(ui::KeyEvent* event) override;
void GetWordAt(const gfx::Point& location_in_content,
@@ -212,9 +222,9 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// views_bridge_mac::mojom::BridgedNativeWidgetHost:
void OnVisibilityChanged(bool visible) override;
void OnWindowNativeThemeChanged() override;
- void SetViewSize(const gfx::Size& new_size) override;
+ void OnViewSizeChanged(const gfx::Size& new_size) override;
void SetKeyboardAccessible(bool enabled) override;
- void SetIsFirstResponder(bool is_first_responder) override;
+ void OnIsFirstResponderChanged(bool is_first_responder) override;
void OnMouseCaptureActiveChanged(bool capture_is_active) override;
void OnScrollEvent(std::unique_ptr<ui::Event> event) override;
void OnMouseEvent(std::unique_ptr<ui::Event> event) override;
@@ -255,6 +265,9 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
bool GetCanWindowBecomeKey(bool* can_window_become_key) override;
bool GetAlwaysRenderWindowAsKey(bool* always_render_as_key) override;
bool GetCanWindowClose(bool* can_window_close) override;
+ bool GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
+ float* titlebar_height) override;
+ void OnFocusWindowToolbar() override;
// views_bridge_mac::mojom::BridgedNativeWidgetHost, synchronous callbacks:
void DispatchKeyEventRemote(std::unique_ptr<ui::Event> event,
@@ -281,6 +294,11 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
void GetAlwaysRenderWindowAsKey(
GetAlwaysRenderWindowAsKeyCallback callback) override;
void GetCanWindowClose(GetCanWindowCloseCallback callback) override;
+ void GetWindowFrameTitlebarHeight(
+ GetWindowFrameTitlebarHeightCallback callback) override;
+ void GetAccessibilityTokens(const std::vector<uint8_t>& window_token,
+ const std::vector<uint8_t>& view_token,
+ GetAccessibilityTokensCallback callback) override;
// DialogObserver:
void OnDialogModelChanged() override;
@@ -294,6 +312,9 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
ui::KeyEvent* key,
base::OnceCallback<void(bool)> ack_callback) override;
+ // ui::AccessibilityFocusOverrider::Client:
+ id GetAccessibilityFocusedUIElement() override;
+
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override;
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
@@ -325,6 +346,16 @@ class VIEWS_EXPORT BridgedNativeWidgetHostImpl
// process.
views_bridge_mac::mojom::BridgedNativeWidgetAssociatedPtr bridge_ptr_;
+ // Remote accessibility objects corresponding to the NSWindow and its root
+ // NSView.
+ base::scoped_nsobject<NSAccessibilityRemoteUIElement>
+ remote_window_accessible_;
+ base::scoped_nsobject<NSAccessibilityRemoteUIElement> remote_view_accessible_;
+
+ // Used to force the NSApplication's focused accessibility element to be the
+ // views::Views accessibility tree when the NSView for this is focused.
+ ui::AccessibilityFocusOverrider accessibility_focus_overrider_;
+
// 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.
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 63f9be6db98..6267200e448 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -4,8 +4,11 @@
#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
+#include <utility>
+
#include "base/mac/foundation_util.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+#include "ui/base/cocoa/remote_accessibility_api.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_factory.h"
@@ -59,7 +62,8 @@ uint64_t g_last_bridged_native_widget_id = 0;
// static
BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromNativeWindow(
- gfx::NativeWindow window) {
+ gfx::NativeWindow native_window) {
+ NSWindow* window = native_window.GetNativeNSWindow();
if (NativeWidgetMacNSWindow* widget_window =
base::mac::ObjCCast<NativeWidgetMacNSWindow>(window)) {
return GetFromId([widget_window bridgedNativeWidgetId]);
@@ -68,6 +72,12 @@ BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromNativeWindow(
}
// static
+BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromNativeView(
+ gfx::NativeView native_view) {
+ return GetFromNativeWindow([native_view.GetNativeNSView() window]);
+}
+
+// static
BridgedNativeWidgetHostImpl* BridgedNativeWidgetHostImpl::GetFromId(
uint64_t bridged_native_widget_id) {
auto found = GetIdToWidgetHostImplMap().find(bridged_native_widget_id);
@@ -80,6 +90,7 @@ BridgedNativeWidgetHostImpl::BridgedNativeWidgetHostImpl(NativeWidgetMac* owner)
: widget_id_(++g_last_bridged_native_widget_id),
native_widget_mac_(owner),
root_view_id_(ui::NSViewIds::GetNewId()),
+ accessibility_focus_overrider_(this),
host_mojo_binding_(this) {
DCHECK(GetIdToWidgetHostImplMap().find(widget_id_) ==
GetIdToWidgetHostImplMap().end());
@@ -115,6 +126,20 @@ NativeWidgetMacNSWindow* BridgedNativeWidgetHostImpl::GetLocalNSWindow() const {
return local_window_.get();
}
+gfx::NativeViewAccessible
+BridgedNativeWidgetHostImpl::GetNativeViewAccessibleForNSView() const {
+ if (bridge_impl_)
+ return bridge_impl_->ns_view();
+ return remote_view_accessible_.get();
+}
+
+gfx::NativeViewAccessible
+BridgedNativeWidgetHostImpl::GetNativeViewAccessibleForNSWindow() const {
+ if (bridge_impl_)
+ return bridge_impl_->ns_window();
+ return remote_window_accessible_.get();
+}
+
views_bridge_mac::mojom::BridgedNativeWidget*
BridgedNativeWidgetHostImpl::bridge() const {
if (bridge_ptr_)
@@ -138,11 +163,17 @@ void BridgedNativeWidgetHostImpl::CreateRemoteBridge(
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_];
+ // Create a local invisible window that will be used as the gfx::NativeWindow
+ // handle to track this window in this process.
+ {
+ auto local_window_create_params =
+ views_bridge_mac::mojom::CreateWindowParams::New();
+ local_window_create_params->style_mask = NSBorderlessWindowMask;
+ local_window_ = BridgedNativeWidgetImpl::CreateNSWindow(
+ local_window_create_params.get());
+ [local_window_ setBridgedNativeWidgetId:widget_id_];
+ [local_window_ setAlphaValue:0.0];
+ }
// Initialize |bridge_ptr_| to point to a bridge created by |factory|.
views_bridge_mac::mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr;
@@ -442,7 +473,7 @@ NSView* BridgedNativeWidgetHostImpl::GetGlobalCaptureView() {
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl, views_bridge_mac::BridgedNativeWidgetHostHelper:
-NSView* BridgedNativeWidgetHostImpl::GetNativeViewAccessible() {
+id BridgedNativeWidgetHostImpl::GetNativeViewAccessible() {
return root_view_ ? root_view_->GetNativeViewAccessible() : nil;
}
@@ -478,7 +509,17 @@ void BridgedNativeWidgetHostImpl::OnBridgeFactoryHostDestroying(
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.
+
+ // Because the process hosting this window has ended, close the window by
+ // sending the window close messages that the bridge would have sent.
+ OnWindowWillClose();
+ // Explicitly propagate this message to all children (they are also observers,
+ // but may not be destroyed before |this| is destroyed, which would violate
+ // tear-down assumptions). This would have been done by the bridge, had it
+ // shut down cleanly.
+ while (!children_.empty())
+ children_.front()->OnBridgeFactoryHostDestroying(host);
+ OnWindowHasClosed();
}
////////////////////////////////////////////////////////////////////////////////
@@ -544,7 +585,7 @@ bool BridgedNativeWidgetHostImpl::GetHasMenuController(
return true;
}
-void BridgedNativeWidgetHostImpl::SetViewSize(const gfx::Size& new_size) {
+void BridgedNativeWidgetHostImpl::OnViewSizeChanged(const gfx::Size& new_size) {
root_view_->SetSize(new_size);
}
@@ -555,11 +596,18 @@ void BridgedNativeWidgetHostImpl::SetKeyboardAccessible(bool enabled) {
focus_manager->SetKeyboardAccessible(enabled);
}
-void BridgedNativeWidgetHostImpl::SetIsFirstResponder(bool is_first_responder) {
- if (is_first_responder)
+void BridgedNativeWidgetHostImpl::OnIsFirstResponderChanged(
+ bool is_first_responder) {
+ accessibility_focus_overrider_.SetViewIsFirstResponder(is_first_responder);
+ if (is_first_responder) {
root_view_->GetWidget()->GetFocusManager()->RestoreFocusedView();
- else
- root_view_->GetWidget()->GetFocusManager()->StoreFocusedView(true);
+ } else {
+ // Do not call ClearNativeFocus because that will re-make the
+ // BridgedNativeWidget first responder (and this is called to indicate that
+ // it is no longer first responder).
+ root_view_->GetWidget()->GetFocusManager()->StoreFocusedView(
+ false /* clear_native_focus */);
+ }
}
void BridgedNativeWidgetHostImpl::OnMouseCaptureActiveChanged(bool is_active) {
@@ -741,6 +789,7 @@ void BridgedNativeWidgetHostImpl::OnWindowKeyStatusChanged(
bool is_key,
bool is_content_first_responder,
bool full_keyboard_access_enabled) {
+ accessibility_focus_overrider_.SetWindowIsKey(is_key);
is_window_key_ = is_key;
Widget* widget = native_widget_mac_->GetWidget();
if (!widget->OnNativeWidgetActivationChanged(is_key))
@@ -832,6 +881,18 @@ bool BridgedNativeWidgetHostImpl::GetCanWindowClose(bool* can_window_close) {
return true;
}
+bool BridgedNativeWidgetHostImpl::GetWindowFrameTitlebarHeight(
+ bool* override_titlebar_height,
+ float* titlebar_height) {
+ native_widget_mac_->GetWindowFrameTitlebarHeight(override_titlebar_height,
+ titlebar_height);
+ return true;
+}
+
+void BridgedNativeWidgetHostImpl::OnFocusWindowToolbar() {
+ native_widget_mac_->OnFocusWindowToolbar();
+}
+
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl,
// views_bridge_mac::mojom::BridgedNativeWidgetHost synchronous callbacks:
@@ -935,6 +996,31 @@ void BridgedNativeWidgetHostImpl::GetCanWindowClose(
std::move(callback).Run(can_window_close);
}
+void BridgedNativeWidgetHostImpl::GetWindowFrameTitlebarHeight(
+ GetWindowFrameTitlebarHeightCallback callback) {
+ bool override_titlebar_height = false;
+ float titlebar_height = 0;
+ GetWindowFrameTitlebarHeight(&override_titlebar_height, &titlebar_height);
+ std::move(callback).Run(override_titlebar_height, titlebar_height);
+}
+
+void BridgedNativeWidgetHostImpl::GetAccessibilityTokens(
+ const std::vector<uint8_t>& window_token,
+ const std::vector<uint8_t>& view_token,
+ GetAccessibilityTokensCallback callback) {
+ remote_window_accessible_ =
+ ui::RemoteAccessibility::GetRemoteElementFromToken(window_token);
+ remote_view_accessible_ =
+ ui::RemoteAccessibility::GetRemoteElementFromToken(view_token);
+ [remote_view_accessible_ setWindowUIElement:remote_window_accessible_.get()];
+ [remote_view_accessible_
+ setTopLevelUIElement:remote_window_accessible_.get()];
+
+ id element_id = GetNativeViewAccessible();
+ std::move(callback).Run(
+ getpid(), ui::RemoteAccessibility::GetTokenForLocalElement(element_id));
+}
+
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl, DialogObserver:
@@ -982,6 +1068,13 @@ ui::EventDispatchDetails BridgedNativeWidgetHostImpl::DispatchKeyEventPostIME(
}
////////////////////////////////////////////////////////////////////////////////
+// BridgedNativeWidgetHostImpl, AccessibilityFocusOverrider::Client:
+
+id BridgedNativeWidgetHostImpl::GetAccessibilityFocusedUIElement() {
+ return [GetNativeViewAccessible() accessibilityFocusedUIElement];
+}
+
+////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetHostImpl, LayerDelegate:
void BridgedNativeWidgetHostImpl::OnPaintLayer(
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 38f71672f2e..8617012253b 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -66,7 +66,7 @@ class BridgedNativeWidgetUITest : public test::WidgetTest {
}
NSWindow* test_window() {
- return widget_->GetNativeWindow();
+ return widget_->GetNativeWindow().GetNativeNSWindow();
}
protected:
@@ -296,7 +296,7 @@ TEST_F(BridgedNativeWidgetUITest, DISABLED_HitTest) {
const NSPoint bottom_right_point = {398, 2};
const NSPoint right_of_bottom_right = {398 + 10, 2};
- NSWindow* window = widget.GetNativeWindow();
+ NSWindow* window = widget.GetNativeWindow().GetNativeNSWindow();
EXPECT_FALSE([window ignoresMouseEvents]);
// OSX uses both the alpha value of the window and the underlying CALayer to
diff --git a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
index 3a2248849fd..00df4d7ab79 100644
--- a/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/chromium/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -23,7 +23,6 @@
#include "ui/base/ime/input_method.h"
#include "ui/base/material_design/material_design_controller.h"
#import "ui/base/test/cocoa_helper.h"
-#include "ui/base/test/material_design_controller_test_api.h"
#include "ui/events/test/cocoa_test_event_utils.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#import "ui/views/cocoa/bridged_native_widget_host_impl.h"
@@ -313,9 +312,8 @@ class MockNativeWidgetMac : public NativeWidgetMac {
backing:NSBackingStoreBuffered
defer:NO]);
bridge_host_for_testing()->CreateLocalBridge(window);
- if (BridgedNativeWidgetHostImpl* parent =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow(
- [params.parent window])) {
+ if (auto* parent =
+ BridgedNativeWidgetHostImpl::GetFromNativeView(params.parent)) {
bridge_host_for_testing()->SetParent(parent);
}
bridge_host_for_testing()->InitWindow(params);
@@ -359,7 +357,8 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
// corresponding |key_code|.
NSEvent* VkeyKeyDown(ui::KeyboardCode key_code) {
return cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true /* keyDown */, key_code, 0);
+ widget_->GetNativeWindow().GetNativeNSWindow(), true /* keyDown */,
+ key_code, 0);
}
// Generate an autoreleased KeyDown NSEvent* using the given keycode, and
@@ -373,9 +372,6 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
void SetUp() override {
ui::CocoaTest::SetUp();
- // MaterialDesignController leaks state across tests. See
- // http://crbug.com/656871.
- ui::test::MaterialDesignControllerTestAPI::Uninitialize();
ui::MaterialDesignController::Initialize();
init_params_.native_widget = native_widget_mac_;
@@ -402,7 +398,6 @@ class BridgedNativeWidgetTestBase : public ui::CocoaTest {
// be sure to destroy the widget (which will destroy its NSWindow)
// beforehand.
widget_.reset();
- ui::test::MaterialDesignControllerTestAPI::Uninitialize();
ui::CocoaTest::TearDown();
}
@@ -1124,7 +1119,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
// First an insertText: message with key 'a' is generated.
SetKeyDownEvent(cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true, ui::VKEY_A, 0));
+ widget_->GetNativeWindow().GetNativeNSWindow(), true, ui::VKEY_A, 0));
[ns_view_ insertText:@"a" replacementRange:EmptyRange()];
[dummy_text_view_ insertText:@"a" replacementRange:EmptyRange()];
SetKeyDownEvent(nil);
@@ -1135,7 +1130,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
// keys, setMarkedText action message is generated which replaces the earlier
// inserted 'a'.
SetKeyDownEvent(cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true, ui::VKEY_RIGHT, 0));
+ widget_->GetNativeWindow().GetNativeNSWindow(), true, ui::VKEY_RIGHT, 0));
[ns_view_ setMarkedText:@"à"
selectedRange:NSMakeRange(0, 1)
replacementRange:NSMakeRange(3, 1)];
@@ -1152,7 +1147,8 @@ TEST_F(BridgedNativeWidgetTest, TextInput_AccentedCharacter) {
// On pressing enter, the marked text is confirmed.
SetKeyDownEvent(cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0));
+ widget_->GetNativeWindow().GetNativeNSWindow(), true, ui::VKEY_RETURN,
+ 0));
[ns_view_ insertText:@"à" replacementRange:EmptyRange()];
[dummy_text_view_ insertText:@"à" replacementRange:EmptyRange()];
SetKeyDownEvent(nil);
@@ -1740,7 +1736,7 @@ TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) {
// Everything happens with this one event.
NSEvent* return_with_fake_ime = cocoa_test_event_utils::SynthesizeKeyEvent(
- widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0);
+ widget_->GetNativeWindow().GetNativeNSWindow(), true, ui::VKEY_RETURN, 0);
InterpretKeyEventsCallback generate_return_and_fake_ime = base::BindRepeating(
[](int* saw_return_count, id view) {
@@ -1835,7 +1831,7 @@ typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest;
TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) {
BridgedNativeWidgetTestWindow* window =
base::mac::ObjCCastStrict<BridgedNativeWidgetTestWindow>(
- widget_->GetNativeWindow());
+ widget_->GetNativeWindow().GetNativeNSWindow());
[window setIgnoreToggleFullScreen:YES];
widget_->Show();
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac.h b/chromium/ui/views/cocoa/drag_drop_client_mac.h
index e93d8a09441..1cfc235f8a6 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac.h
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac.h
@@ -21,7 +21,7 @@
// OSExchangeData into the pasteboard.
VIEWS_EXPORT
@interface CocoaDragDropDataProvider : NSObject<NSPasteboardItemDataProvider>
-- (id)initWithData:(const ui::OSExchangeData&)data;
+- (instancetype)initWithData:(const ui::OSExchangeData&)data;
@end
namespace gfx {
diff --git a/chromium/ui/views/cocoa/drag_drop_client_mac.mm b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
index 2df33355f9e..b22753402dc 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac.mm
@@ -15,15 +15,15 @@
#import "ui/views_bridge_mac/bridged_native_widget_impl.h"
@interface CocoaDragDropDataProvider ()
-- (id)initWithData:(const ui::OSExchangeData&)data;
-- (id)initWithPasteboard:(NSPasteboard*)pasteboard;
+- (instancetype)initWithData:(const ui::OSExchangeData&)data;
+- (instancetype)initWithPasteboard:(NSPasteboard*)pasteboard;
@end
@implementation CocoaDragDropDataProvider {
std::unique_ptr<ui::OSExchangeData> data_;
}
-- (id)initWithData:(const ui::OSExchangeData&)data {
+- (instancetype)initWithData:(const ui::OSExchangeData&)data {
if ((self = [super init])) {
data_.reset(new OSExchangeData(
std::unique_ptr<OSExchangeData::Provider>(data.provider().Clone())));
@@ -31,7 +31,7 @@
return self;
}
-- (id)initWithPasteboard:(NSPasteboard*)pasteboard {
+- (instancetype)initWithPasteboard:(NSPasteboard*)pasteboard {
if ((self = [super init])) {
data_ = ui::OSExchangeDataProviderMac::CreateDataFromPasteboard(pasteboard);
}
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 4202d53a348..4f49c8bd382 100644
--- a/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/chromium/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -56,7 +56,7 @@ using base::ASCIIToUTF16;
@synthesize draggingFormation;
@synthesize springLoadingHighlight;
-- (id)initWithPasteboard:(NSPasteboard*)pasteboard {
+- (instancetype)initWithPasteboard:(NSPasteboard*)pasteboard {
if ((self = [super init])) {
pasteboard_ = pasteboard;
}
@@ -188,10 +188,9 @@ class DragDropClientMacTest : public WidgetTest {
gfx::Rect bounds(0, 0, 100, 100);
widget_->SetBounds(bounds);
- bridge_ = BridgedNativeWidgetImpl::GetFromNativeWindow(
- widget_->GetNativeWindow());
bridge_host_ = BridgedNativeWidgetHostImpl::GetFromNativeWindow(
widget_->GetNativeWindow());
+ bridge_ = bridge_host_->bridge_impl();
widget_->Show();
target_ = new DragDropView();
diff --git a/chromium/ui/views/controls/animated_icon_view.cc b/chromium/ui/views/controls/animated_icon_view.cc
deleted file mode 100644
index 68453c7fac2..00000000000
--- a/chromium/ui/views/controls/animated_icon_view.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2017 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_icon_view.h"
-
-#include "ui/compositor/compositor.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-AnimatedIconView::AnimatedIconView(const gfx::VectorIcon& icon)
- : icon_(icon),
- color_(gfx::kPlaceholderColor),
- duration_(gfx::GetDurationOfAnimation(icon)) {
- UpdateStaticImage();
-}
-
-AnimatedIconView::~AnimatedIconView() {
- if (compositor_ && compositor_->HasAnimationObserver(this))
- compositor_->RemoveAnimationObserver(this);
-}
-
-void AnimatedIconView::SetColor(SkColor color) {
- if (color_ != color) {
- color_ = color;
- UpdateStaticImage();
- }
-}
-
-void AnimatedIconView::Animate(State target) {
- SetState(target);
- if (!IsAnimating()) {
- compositor_ = GetWidget()->GetCompositor();
- compositor_->AddAnimationObserver(this);
- }
- start_time_ = base::TimeTicks::Now();
-}
-
-void AnimatedIconView::SetState(State state) {
- state_ = state;
- UpdateStaticImage();
-}
-
-bool AnimatedIconView::IsAnimating() const {
- return start_time_ != base::TimeTicks();
-}
-
-void AnimatedIconView::OnPaint(gfx::Canvas* canvas) {
- if (!IsAnimating()) {
- views::ImageView::OnPaint(canvas);
- return;
- }
-
- auto timestamp = base::TimeTicks::Now();
- base::TimeDelta elapsed = timestamp - start_time_;
- if (state_ == END)
- elapsed = start_time_ + duration_ - timestamp;
-
- canvas->Translate(GetImageBounds().OffsetFromOrigin());
- gfx::PaintVectorIcon(canvas, icon_, color_, elapsed);
-}
-
-void AnimatedIconView::OnAnimationStep(base::TimeTicks timestamp) {
- base::TimeDelta elapsed = timestamp - start_time_;
- if (elapsed > duration_) {
- compositor_->RemoveAnimationObserver(this);
- compositor_ = nullptr;
- start_time_ = base::TimeTicks();
- }
-
- SchedulePaint();
-}
-
-void AnimatedIconView::OnCompositingShuttingDown(ui::Compositor* compositor) {
- DCHECK_EQ(compositor, compositor_);
- compositor_->RemoveAnimationObserver(this);
- compositor_ = nullptr;
-}
-
-void AnimatedIconView::UpdateStaticImage() {
- gfx::IconDescription description(
- icon_, 0, color_, state_ == START ? base::TimeDelta() : duration_,
- gfx::kNoneIcon);
- SetImage(gfx::CreateVectorIcon(description));
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/animated_icon_view.h b/chromium/ui/views/controls/animated_icon_view.h
deleted file mode 100644
index 2f0eddf5dde..00000000000
--- a/chromium/ui/views/controls/animated_icon_view.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2017 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_ICON_VIEW_H_
-#define UI_VIEWS_CONTROLS_ANIMATED_ICON_VIEW_H_
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "ui/compositor/compositor_animation_observer.h"
-#include "ui/gfx/vector_icon_types.h"
-#include "ui/views/controls/image_view.h"
-
-namespace views {
-
-// This class hosts a vector icon that defines transitions. It can be in the
-// start steady state, the end steady state, or transitioning in between.
-class VIEWS_EXPORT AnimatedIconView : public views::ImageView,
- public ui::CompositorAnimationObserver {
- public:
- enum State {
- START,
- END,
- };
-
- explicit AnimatedIconView(const gfx::VectorIcon& icon);
- ~AnimatedIconView() override;
-
- void SetColor(SkColor color);
-
- // Animates to the end or start state.
- void Animate(State target);
-
- // Jumps to the end or start state.
- void SetState(State state);
-
- bool IsAnimating() const;
-
- // views::ImageView
- void OnPaint(gfx::Canvas* canvas) override;
-
- // ui::CompositorAnimationObserver
- void OnAnimationStep(base::TimeTicks timestamp) override;
- void OnCompositingShuttingDown(ui::Compositor* compositor) override;
-
- private:
- void UpdateStaticImage();
-
- const gfx::VectorIcon& icon_;
- SkColor color_;
-
- // Tracks the last time Animate() was called.
- base::TimeTicks start_time_;
-
- // The amount of time that must elapse until all transitions are done, i.e.
- // the length of the animation.
- const base::TimeDelta duration_;
-
- // The current state, or when transitioning the goal state.
- State state_ = START;
-
- // The compositor that |this| is observing, if and when there is an active
- // animation. Otherwise it is null.
- ui::Compositor* compositor_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(AnimatedIconView);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_ANIMATED_ICON_VIEW_H_
diff --git a/chromium/ui/views/controls/animated_image_view.cc b/chromium/ui/views/controls/animated_image_view.cc
index 2d56a88b440..bb379bc3d7e 100644
--- a/chromium/ui/views/controls/animated_image_view.cc
+++ b/chromium/ui/views/controls/animated_image_view.cc
@@ -7,8 +7,8 @@
#include <utility>
#include "base/logging.h"
+#include "cc/paint/skottie_wrapper.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/skottie_wrapper.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -52,21 +52,17 @@ void AnimatedImageView::Play() {
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);
+ SetCompositorFromWidget();
animated_image_->Start();
}
void AnimatedImageView::Stop() {
+ if (state_ == State::kStopped)
+ return;
+
DCHECK(animated_image_);
- if (compositor_)
- compositor_->RemoveAnimationObserver(this);
+ ClearCurrentCompositor();
animated_image_->Stop();
state_ = State::kStopped;
@@ -99,27 +95,21 @@ const char* AnimatedImageView::GetClassName() const {
}
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;
+ ClearCurrentCompositor();
+
+ // Restore the Play() state with the new compositor.
+ if (state_ == State::kPlaying)
+ SetCompositorFromWidget();
}
}
void AnimatedImageView::RemovedFromWidget() {
if (compositor_) {
Stop();
- if (compositor_->HasAnimationObserver(this))
- compositor_->RemoveAnimationObserver(this);
- compositor_ = nullptr;
+ ClearCurrentCompositor();
}
}
@@ -131,6 +121,22 @@ void AnimatedImageView::OnAnimationStep(base::TimeTicks timestamp) {
void AnimatedImageView::OnCompositingShuttingDown(ui::Compositor* compositor) {
if (compositor_ == compositor) {
Stop();
+ ClearCurrentCompositor();
+ }
+}
+
+void AnimatedImageView::SetCompositorFromWidget() {
+ DCHECK(!compositor_);
+ auto* widget = GetWidget();
+ DCHECK(widget);
+ compositor_ = widget->GetCompositor();
+ DCHECK(!compositor_->HasAnimationObserver(this));
+ compositor_->AddAnimationObserver(this);
+}
+
+void AnimatedImageView::ClearCurrentCompositor() {
+ if (compositor_) {
+ DCHECK(compositor_->HasAnimationObserver(this));
compositor_->RemoveAnimationObserver(this);
compositor_ = nullptr;
}
diff --git a/chromium/ui/views/controls/animated_image_view.h b/chromium/ui/views/controls/animated_image_view.h
index c62fe5c3723..f3868c28a97 100644
--- a/chromium/ui/views/controls/animated_image_view.h
+++ b/chromium/ui/views/controls/animated_image_view.h
@@ -48,7 +48,8 @@ class VIEWS_EXPORT AnimatedImageView : public ImageViewBase,
void SetAnimatedImage(
std::unique_ptr<gfx::SkiaVectorAnimation> animated_image);
- // Plays the animation in loop.
+ // Plays the animation in loop and must only be called when this view has
+ // access to a widget.
void Play();
// Stops any animation and resets it to the start frame.
@@ -61,13 +62,15 @@ class VIEWS_EXPORT AnimatedImageView : public ImageViewBase,
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;
+ void SetCompositorFromWidget();
+ void ClearCurrentCompositor();
+
// Overridden from ImageViewBase:
gfx::Size GetImageSize() const override;
diff --git a/chromium/ui/views/controls/button/blue_button.cc b/chromium/ui/views/controls/button/blue_button.cc
deleted file mode 100644
index fcebb90db00..00000000000
--- a/chromium/ui/views/controls/button/blue_button.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/button/blue_button.h"
-
-#include <utility>
-
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/views/controls/button/label_button_border.h"
-#include "ui/views/resources/grit/views_resources.h"
-
-namespace views {
-
-// static
-const char BlueButton::kViewClassName[] = "views/BlueButton";
-
-BlueButton::BlueButton(ButtonListener* listener, const base::string16& text)
- : LabelButton(listener, text) {
- // Inherit STYLE_BUTTON insets, minimum size, alignment, etc.
- SetStyleDeprecated(STYLE_BUTTON);
- UpdateThemedBorder();
-}
-
-BlueButton::~BlueButton() {}
-
-void BlueButton::ResetColorsFromNativeTheme() {
- LabelButton::ResetColorsFromNativeTheme();
- if (!color_utils::IsInvertedColorScheme()) {
- SetTextColor(STATE_NORMAL, GetNativeTheme()->
- GetSystemColor(ui::NativeTheme::kColorId_BlueButtonEnabledColor));
- SetTextColor(STATE_HOVERED, GetNativeTheme()->
- GetSystemColor(ui::NativeTheme::kColorId_BlueButtonHoverColor));
- SetTextColor(STATE_PRESSED, GetNativeTheme()->
- GetSystemColor(ui::NativeTheme::kColorId_BlueButtonPressedColor));
- SetTextColor(STATE_DISABLED, GetNativeTheme()->
- GetSystemColor(ui::NativeTheme::kColorId_BlueButtonDisabledColor));
-
- label()->SetShadows(gfx::ShadowValues(
- 1, gfx::ShadowValue(
- gfx::Vector2d(0, 1), 0,
- GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_BlueButtonShadowColor))));
- }
-}
-
-const char* BlueButton::GetClassName() const {
- return BlueButton::kViewClassName;
-}
-
-std::unique_ptr<LabelButtonBorder> BlueButton::CreateDefaultBorder() const {
- // Insets for splitting the images.
- const gfx::Insets insets(5);
- std::unique_ptr<LabelButtonAssetBorder> button_border(
- new LabelButtonAssetBorder(style()));
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- button_border->SetPainter(false, STATE_NORMAL, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_NORMAL), insets));
- button_border->SetPainter(false, STATE_HOVERED, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_HOVER), insets));
- button_border->SetPainter(false, STATE_PRESSED, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_PRESSED), insets));
- button_border->SetPainter(false, STATE_DISABLED, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
- button_border->SetPainter(true, STATE_NORMAL, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_NORMAL), insets));
- button_border->SetPainter(true, STATE_HOVERED, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_HOVER), insets));
- button_border->SetPainter(true, STATE_PRESSED, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_FOCUSED_PRESSED), insets));
- button_border->SetPainter(true, STATE_DISABLED, Painter::CreateImagePainter(
- *rb.GetImageSkiaNamed(IDR_BLUE_BUTTON_DISABLED), insets));
- return std::move(button_border);
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/button/blue_button.h b/chromium/ui/views/controls/button/blue_button.h
deleted file mode 100644
index ec414de1790..00000000000
--- a/chromium/ui/views/controls/button/blue_button.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_BUTTON_BLUE_BUTTON_H_
-#define UI_VIEWS_CONTROLS_BUTTON_BLUE_BUTTON_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "ui/views/controls/button/label_button.h"
-
-namespace views {
-
-// A class representing a blue button.
-class VIEWS_EXPORT BlueButton : public LabelButton {
- public:
- static const char kViewClassName[];
-
- BlueButton(ButtonListener* listener, const base::string16& text);
- ~BlueButton() override;
-
- private:
- // Overridden from LabelButton:
- void ResetColorsFromNativeTheme() override;
- const char* GetClassName() const override;
- std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const override;
-
- DISALLOW_COPY_AND_ASSIGN(BlueButton);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_CONTROLS_BUTTON_BLUE_BUTTON_H_
diff --git a/chromium/ui/views/controls/button/blue_button_unittest.cc b/chromium/ui/views/controls/button/blue_button_unittest.cc
deleted file mode 100644
index f516f44d0ed..00000000000
--- a/chromium/ui/views/controls/button/blue_button_unittest.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/button/blue_button.h"
-
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "cc/paint/skia_paint_canvas.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/skia_util.h"
-#include "ui/views/controls/button/label_button_border.h"
-#include "ui/views/test/widget_test.h"
-
-namespace views {
-
-using BlueButtonTest = test::WidgetTest;
-
-TEST_F(BlueButtonTest, Border) {
- // The buttons must be added to a Widget so that borders are correctly
- // applied once the NativeTheme is determined.
- Widget* widget = CreateTopLevelPlatformWidget();
-
- // Compared to a normal LabelButton...
- LabelButton* button = new LabelButton(nullptr, base::ASCIIToUTF16("foo"));
- EXPECT_EQ(Button::STYLE_TEXTBUTTON, button->style());
- // Focus painter by default.
- EXPECT_TRUE(button->focus_painter_.get());
-
- // Switch to the same style as BlueButton for a more compelling comparison.
- button->SetStyleDeprecated(Button::STYLE_BUTTON);
- EXPECT_EQ(Button::STYLE_BUTTON, button->style());
- EXPECT_FALSE(button->focus_painter_.get());
-
- widget->GetContentsView()->AddChildView(button);
- button->SizeToPreferredSize();
-
- SkBitmap button_bitmap;
- button_bitmap.allocN32Pixels(button->size().width(), button->size().height(),
- true /* opaque */);
- cc::SkiaPaintCanvas button_paint_canvas(button_bitmap);
- gfx::Canvas button_canvas(&button_paint_canvas, 1.f);
- button->border()->Paint(*button, &button_canvas);
-
- // ... a special blue border should be used.
- BlueButton* blue_button = new BlueButton(nullptr, base::ASCIIToUTF16("foo"));
- EXPECT_EQ(Button::STYLE_BUTTON, blue_button->style());
- EXPECT_FALSE(blue_button->focus_painter_.get());
-
- widget->GetContentsView()->AddChildView(blue_button);
- blue_button->SizeToPreferredSize();
-
- SkBitmap blue_button_bitmap;
- blue_button_bitmap.allocN32Pixels(blue_button->size().width(),
- blue_button->size().height(),
- true /* opaque */);
- cc::SkiaPaintCanvas blue_button_paint_canvas(blue_button_bitmap);
- gfx::Canvas blue_button_canvas(&blue_button_paint_canvas, 1.f);
- blue_button->border()->Paint(*blue_button, &blue_button_canvas);
- EXPECT_EQ(button->GetText(), blue_button->GetText());
- EXPECT_EQ(button->size(), blue_button->size());
- EXPECT_FALSE(gfx::BitmapsAreEqual(button_bitmap, blue_button_bitmap));
-
- widget->CloseNow();
-}
-
-} // namespace views
diff --git a/chromium/ui/views/controls/button/button.cc b/chromium/ui/views/controls/button/button.cc
index ebf086404e3..ad5ab5f0470 100644
--- a/chromium/ui/views/controls/button/button.cc
+++ b/chromium/ui/views/controls/button/button.cc
@@ -15,7 +15,6 @@
#include "ui/native_theme/native_theme.h"
#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_impl.h"
-#include "ui/views/controls/button/blue_button.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/button/label_button.h"
@@ -44,6 +43,30 @@ const int kHoverFadeDurationMs = 150;
} // namespace
////////////////////////////////////////////////////////////////////////////////
+// WidgetObserverButtonBridge:
+Button::WidgetObserverButtonBridge::WidgetObserverButtonBridge(Button* button)
+ : owner_(button) {
+ DCHECK(button->GetWidget());
+ button->GetWidget()->AddObserver(this);
+}
+
+Button::WidgetObserverButtonBridge::~WidgetObserverButtonBridge() {
+ if (owner_)
+ owner_->GetWidget()->RemoveObserver(this);
+}
+
+void Button::WidgetObserverButtonBridge::OnWidgetActivationChanged(
+ Widget* widget,
+ bool active) {
+ owner_->WidgetActivationChanged(widget, active);
+}
+
+void Button::WidgetObserverButtonBridge::OnWidgetDestroying(Widget* widget) {
+ widget->RemoveObserver(this);
+ owner_ = nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Button, static public:
// static
@@ -89,8 +112,6 @@ void Button::SetFocusForPlatform() {
void Button::SetTooltipText(const base::string16& tooltip_text) {
tooltip_text_ = tooltip_text;
- if (accessible_name_.empty())
- accessible_name_ = tooltip_text_;
OnSetTooltipText(tooltip_text);
TooltipTextChanged();
}
@@ -100,6 +121,10 @@ void Button::SetAccessibleName(const base::string16& name) {
NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
}
+const base::string16& Button::GetAccessibleName() const {
+ return accessible_name_.empty() ? tooltip_text_ : accessible_name_;
+}
+
void Button::SetState(ButtonState state) {
if (state == state_)
return;
@@ -129,6 +154,14 @@ void Button::SetState(ButtonState state) {
SchedulePaint();
}
+Button::ButtonState Button::GetVisualState() const {
+ if (PlatformStyle::kInactiveWidgetControlsAppearDisabled && GetWidget() &&
+ !GetWidget()->IsActive()) {
+ return STATE_DISABLED;
+ }
+ return state();
+}
+
void Button::StartThrobbing(int cycles_til_stop) {
if (!animate_on_state_change_)
return;
@@ -318,11 +351,6 @@ bool Button::OnKeyReleased(const ui::KeyEvent& event) {
}
void Button::OnGestureEvent(ui::GestureEvent* event) {
- if (state_ == STATE_DISABLED) {
- InkDropHostView::OnGestureEvent(event);
- return;
- }
-
if (event->type() == ui::ET_GESTURE_TAP && IsTriggerableEvent(*event)) {
// Set the button state to hot and start the animation fully faded in. The
// GESTURE_END event issued immediately after will set the state to
@@ -341,8 +369,6 @@ void Button::OnGestureEvent(ui::GestureEvent* event) {
event->type() == ui::ET_GESTURE_END) {
SetState(STATE_NORMAL);
}
- if (!event->handled())
- InkDropHostView::OnGestureEvent(event);
}
bool Button::AcceleratorPressed(const ui::Accelerator& accelerator) {
@@ -399,7 +425,7 @@ void Button::OnPaint(gfx::Canvas* canvas) {
void Button::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kButton;
- node_data->SetName(accessible_name_);
+ node_data->SetName(GetAccessibleName());
if (!enabled())
node_data->SetRestriction(ax::mojom::Restriction::kDisabled);
@@ -456,6 +482,15 @@ void Button::OnBlur() {
SchedulePaint();
}
+void Button::AddedToWidget() {
+ if (PlatformStyle::kInactiveWidgetControlsAppearDisabled)
+ widget_observer_ = std::make_unique<WidgetObserverButtonBridge>(this);
+}
+
+void Button::RemovedFromWidget() {
+ widget_observer_.reset();
+}
+
std::unique_ptr<InkDrop> Button::CreateInkDrop() {
std::unique_ptr<views::InkDropImpl> ink_drop = CreateDefaultInkDropImpl();
ink_drop->SetShowHighlightOnFocus(!focus_ring_);
@@ -568,4 +603,8 @@ bool Button::ShouldEnterHoveredState() {
return check_mouse_position && IsMouseHovered();
}
+void Button::WidgetActivationChanged(Widget* widget, bool active) {
+ StateChanged(state());
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/button/button.h b/chromium/ui/views/controls/button/button.h
index 050512ffa34..6cdedf42582 100644
--- a/chromium/ui/views/controls/button/button.h
+++ b/chromium/ui/views/controls/button/button.h
@@ -15,6 +15,7 @@
#include "ui/views/animation/ink_drop_state.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/painter.h"
+#include "ui/views/widget/widget_observer.h"
namespace views {
@@ -87,7 +88,7 @@ class VIEWS_EXPORT Button : public InkDropHostView,
void set_tag(int tag) { tag_ = tag; }
void SetAccessibleName(const base::string16& name);
- const base::string16& accessible_name() const { return accessible_name_; }
+ const base::string16& GetAccessibleName() const;
// Get/sets the current display state of the button.
ButtonState state() const { return state_; }
@@ -96,6 +97,9 @@ class VIEWS_EXPORT Button : public InkDropHostView,
// like event dispatching, focus traversals, etc. Calling SetEnabled(false)
// will also set the state of |this| to STATE_DISABLED.
void SetState(ButtonState state);
+ // Returns the visual appearance state of the button. This takes into account
+ // both the button's display state and the state of the containing widget.
+ ButtonState GetVisualState() const;
// Starts throbbing. See HoverAnimation for a description of cycles_til_stop.
// This method does nothing if |animate_on_state_change_| is false.
@@ -183,6 +187,8 @@ class VIEWS_EXPORT Button : public InkDropHostView,
const ViewHierarchyChangedDetails& details) override;
void OnFocus() override;
void OnBlur() override;
+ void AddedToWidget() override;
+ void RemovedFromWidget() override;
// Overridden from InkDropHostView:
std::unique_ptr<InkDrop> CreateInkDrop() override;
@@ -261,6 +267,28 @@ class VIEWS_EXPORT Button : public InkDropHostView,
private:
FRIEND_TEST_ALL_PREFIXES(BlueButtonTest, Border);
+ // Bridge class to allow Button to observe a Widget without being a
+ // WidgetObserver. This is desirable because many Button subclasses are
+ // themselves WidgetObservers, and if Button is a WidgetObserver, any change
+ // to its WidgetObserver overrides requires updating all the subclasses as
+ // well.
+ class WidgetObserverButtonBridge : public WidgetObserver {
+ public:
+ WidgetObserverButtonBridge(Button* owner);
+ ~WidgetObserverButtonBridge() override;
+
+ // WidgetObserver:
+ void OnWidgetActivationChanged(Widget* widget, bool active) override;
+ void OnWidgetDestroying(Widget* widget) override;
+
+ private:
+ Button* owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetObserverButtonBridge);
+ };
+
+ void WidgetActivationChanged(Widget* widget, bool active);
+
// The text shown in a tooltip.
base::string16 tooltip_text_;
@@ -306,6 +334,8 @@ class VIEWS_EXPORT Button : public InkDropHostView,
std::unique_ptr<Painter> focus_painter_;
+ std::unique_ptr<WidgetObserverButtonBridge> widget_observer_;
+
DISALLOW_COPY_AND_ASSIGN(Button);
};
diff --git a/chromium/ui/views/controls/button/button_unittest.cc b/chromium/ui/views/controls/button/button_unittest.cc
index 067653b4945..2164d40e437 100644
--- a/chromium/ui/views/controls/button/button_unittest.cc
+++ b/chromium/ui/views/controls/button/button_unittest.cc
@@ -13,7 +13,7 @@
#include "ui/display/screen.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
-#include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/animation/ink_drop_host_view.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/test/ink_drop_host_view_test_api.h"
#include "ui/views/animation/test/test_ink_drop.h"
@@ -29,6 +29,7 @@
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget_utils.h"
#if defined(USE_AURA)
#include "ui/aura/test/test_cursor_client.h"
@@ -78,7 +79,7 @@ class TestButton : public Button, public ButtonListener {
void OnClickCanceled(const ui::Event& event) override { canceled_ = true; }
- // InkDropHostView:
+ // Button:
void AddInkDropLayer(ui::Layer* ink_drop_layer) override {
++ink_drop_layer_add_count_;
Button::AddInkDropLayer(ink_drop_layer);
@@ -177,7 +178,7 @@ class ButtonTest : public ViewsTestBase {
// Tests that hover state changes correctly when visiblity/enableness changes.
TEST_F(ButtonTest, HoverStateOnVisibilityChange) {
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
generator.PressLeftButton();
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
@@ -226,8 +227,7 @@ TEST_F(ButtonTest, HoverStateOnVisibilityChange) {
// Disabling cursor events occurs for touch events and the Ash magnifier. There
// is no touch on desktop Mac. Tracked in http://crbug.com/445520.
#if !defined(OS_MACOSX) || defined(USE_AURA)
- aura::test::TestCursorClient cursor_client(
- widget()->GetNativeView()->GetRootWindow());
+ aura::test::TestCursorClient cursor_client(GetRootWindow(widget()));
// In Aura views, no new hover effects are invoked if mouse events
// are disabled.
@@ -250,7 +250,7 @@ TEST_F(ButtonTest, HoverStateOnVisibilityChange) {
// Tests that the hover state is preserved during a view hierarchy update of a
// button's child View.
TEST_F(ButtonTest, HoverStatePreservedOnDescendantViewHierarchyChange) {
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
generator.MoveMouseTo(button()->GetBoundsInScreen().CenterPoint());
EXPECT_EQ(Button::STATE_HOVERED, button()->state());
@@ -343,8 +343,7 @@ void PerformGesture(Button* button, ui::EventType event_type) {
// Tests that gesture events correctly change the button state.
TEST_F(ButtonTest, GestureEventsSetState) {
- aura::test::TestCursorClient cursor_client(
- widget()->GetNativeView()->GetRootWindow());
+ aura::test::TestCursorClient cursor_client(GetRootWindow(widget()));
EXPECT_EQ(Button::STATE_NORMAL, button()->state());
@@ -364,10 +363,10 @@ TEST_F(ButtonTest, GestureEventsSetState) {
TEST_F(ButtonTest, AsButton) {
base::string16 text;
- LabelButton label_button(NULL, text);
+ LabelButton label_button(nullptr, text);
EXPECT_TRUE(Button::AsButton(&label_button));
- ImageButton image_button(NULL);
+ ImageButton image_button(nullptr);
EXPECT_TRUE(Button::AsButton(&image_button));
Checkbox checkbox(text);
@@ -376,10 +375,10 @@ TEST_F(ButtonTest, AsButton) {
RadioButton radio_button(text, 0);
EXPECT_TRUE(Button::AsButton(&radio_button));
- MenuButton menu_button(text, NULL, false);
+ MenuButton menu_button(text, nullptr);
EXPECT_TRUE(Button::AsButton(&menu_button));
- ToggleButton toggle_button(NULL);
+ ToggleButton toggle_button(nullptr);
EXPECT_TRUE(Button::AsButton(&toggle_button));
Label label;
@@ -400,8 +399,8 @@ TEST_F(ButtonTest, ButtonClickTogglesInkDrop) {
TestInkDrop* ink_drop = new TestInkDrop();
CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
- generator.set_current_location(gfx::Point(50, 50));
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
+ generator.set_current_screen_location(gfx::Point(50, 50));
generator.PressLeftButton();
EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop->GetTargetInkDropState());
@@ -415,8 +414,8 @@ TEST_F(ButtonTest, CaptureLossHidesInkDrop) {
TestInkDrop* ink_drop = new TestInkDrop();
CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
- generator.set_current_location(gfx::Point(50, 50));
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
+ generator.set_current_screen_location(gfx::Point(50, 50));
generator.PressLeftButton();
EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop->GetTargetInkDropState());
@@ -487,7 +486,7 @@ TEST_F(ButtonTest, HideInkDropHighlightOnDisable) {
TestInkDrop* ink_drop = new TestInkDrop();
CreateButtonWithInkDrop(base::WrapUnique(ink_drop), false);
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
generator.MoveMouseToInHost(10, 10);
EXPECT_TRUE(ink_drop->is_hovered());
button()->SetEnabled(false);
@@ -522,7 +521,7 @@ TEST_F(ButtonTest, HideInkDropHighlightWhenRemoved) {
// Make sure that the button ink drop is hidden after the button gets removed.
widget()->SetContentsView(&test_container);
test_container.AddChildView(button());
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
generator.MoveMouseToInHost(2, 2);
EXPECT_TRUE(ink_drop->is_hovered());
// Set ink-drop state to ACTIVATED to make sure that removing the container
diff --git a/chromium/ui/views/controls/button/checkbox.cc b/chromium/ui/views/controls/button/checkbox.cc
index 1a84d97ab26..1b688c6184e 100644
--- a/chromium/ui/views/controls/button/checkbox.cc
+++ b/chromium/ui/views/controls/button/checkbox.cc
@@ -164,7 +164,7 @@ SkColor Checkbox::GetIconImageColor(int icon_state) const {
const SkColor active_color =
(icon_state & IconState::CHECKED)
? GetNativeTheme()->GetSystemColor(
- ui::NativeTheme::kColorId_FocusedBorderColor)
+ ui::NativeTheme::kColorId_ProminentButtonColor)
// When unchecked, the icon color matches push button text color.
: style::GetColor(*this, style::CONTEXT_BUTTON_MD,
style::STYLE_PRIMARY);
diff --git a/chromium/ui/views/controls/button/image_button_factory.cc b/chromium/ui/views/controls/button/image_button_factory.cc
index baf33d4ef8d..9932416dc82 100644
--- a/chromium/ui/views/controls/button/image_button_factory.cc
+++ b/chromium/ui/views/controls/button/image_button_factory.cc
@@ -14,8 +14,9 @@
namespace views {
-ImageButton* CreateVectorImageButton(ButtonListener* listener) {
- ImageButton* button = new ImageButton(listener);
+namespace {
+
+void ConfigureVectorImageButton(ImageButton* button) {
button->SetInkDropMode(Button::InkDropMode::ON);
button->set_has_ink_drop_action_on_click(true);
button->SetImageAlignment(ImageButton::ALIGN_CENTER,
@@ -23,21 +24,62 @@ ImageButton* CreateVectorImageButton(ButtonListener* listener) {
button->SetFocusPainter(nullptr);
button->SetBorder(CreateEmptyBorder(
LayoutProvider::Get()->GetInsetsMetric(INSETS_VECTOR_IMAGE_BUTTON)));
+}
+
+} // namespace
+
+ImageButton* CreateVectorImageButton(ButtonListener* listener) {
+ ImageButton* button = new ImageButton(listener);
+ ConfigureVectorImageButton(button);
+ return button;
+}
+
+ToggleImageButton* CreateVectorToggleImageButton(ButtonListener* listener) {
+ ToggleImageButton* button = new ToggleImageButton(listener);
+ ConfigureVectorImageButton(button);
return button;
}
void SetImageFromVectorIcon(ImageButton* button,
const gfx::VectorIcon& icon,
SkColor related_text_color) {
+ SetImageFromVectorIcon(button, icon, GetDefaultSizeOfVectorIcon(icon),
+ related_text_color);
+}
+
+void SetImageFromVectorIcon(ImageButton* button,
+ const gfx::VectorIcon& icon,
+ int dip_size,
+ SkColor related_text_color) {
const SkColor icon_color =
color_utils::DeriveDefaultIconColor(related_text_color);
const SkColor disabled_color =
SkColorSetA(icon_color, gfx::kDisabledControlAlpha);
- button->SetImage(Button::STATE_NORMAL,
- gfx::CreateVectorIcon(icon, icon_color));
- button->SetImage(Button::STATE_DISABLED,
- gfx::CreateVectorIcon(icon, disabled_color));
+ const gfx::ImageSkia& normal_image =
+ gfx::CreateVectorIcon(icon, dip_size, icon_color);
+ const gfx::ImageSkia& disabled_image =
+ gfx::CreateVectorIcon(icon, dip_size, disabled_color);
+
+ button->SetImage(Button::STATE_NORMAL, normal_image);
+ button->SetImage(Button::STATE_DISABLED, disabled_image);
button->set_ink_drop_base_color(icon_color);
}
+void SetToggledImageFromVectorIcon(ToggleImageButton* button,
+ const gfx::VectorIcon& icon,
+ int dip_size,
+ SkColor related_text_color) {
+ const SkColor icon_color =
+ color_utils::DeriveDefaultIconColor(related_text_color);
+ const SkColor disabled_color =
+ SkColorSetA(icon_color, gfx::kDisabledControlAlpha);
+ const gfx::ImageSkia normal_image =
+ gfx::CreateVectorIcon(icon, dip_size, icon_color);
+ const gfx::ImageSkia disabled_image =
+ gfx::CreateVectorIcon(icon, dip_size, disabled_color);
+
+ button->SetToggledImage(Button::STATE_NORMAL, &normal_image);
+ button->SetToggledImage(Button::STATE_DISABLED, &disabled_image);
+}
+
} // views
diff --git a/chromium/ui/views/controls/button/image_button_factory.h b/chromium/ui/views/controls/button/image_button_factory.h
index 2bb9a229bd4..0ce421eee68 100644
--- a/chromium/ui/views/controls/button/image_button_factory.h
+++ b/chromium/ui/views/controls/button/image_button_factory.h
@@ -17,11 +17,18 @@ namespace views {
class ButtonListener;
class ImageButton;
+class ToggleImageButton;
// Creates an ImageButton with an ink drop and a centered image in preparation
// for applying a vector icon with SetImageFromVectorIcon below.
VIEWS_EXPORT ImageButton* CreateVectorImageButton(ButtonListener* listener);
+// Creates a ToggleImageButton with an ink drop and a centered image in
+// preperation for applying a vector icon from SetImageFromVectorIcon and
+// SetToggledImageFromVectorIcon below.
+VIEWS_EXPORT ToggleImageButton* CreateVectorToggleImageButton(
+ ButtonListener* listener);
+
// Sets images on |button| for STATE_NORMAL and STATE_DISABLED from the given
// vector icon and color. |related_text_color| is normally the main text color
// used in the parent view, and the actual color used is derived from that. Call
@@ -31,6 +38,20 @@ VIEWS_EXPORT void SetImageFromVectorIcon(
const gfx::VectorIcon& icon,
SkColor related_text_color = gfx::kGoogleGrey900);
+// As above, but creates the images at the given size.
+VIEWS_EXPORT void SetImageFromVectorIcon(
+ ImageButton* button,
+ const gfx::VectorIcon& icon,
+ int dip_size,
+ SkColor related_text_color = gfx::kGoogleGrey900);
+
+// As above, but sets the toggled images for a toggled image button.
+VIEWS_EXPORT void SetToggledImageFromVectorIcon(
+ ToggleImageButton* button,
+ const gfx::VectorIcon& icon,
+ int dip_size,
+ SkColor related_text_color = gfx::kGoogleGrey900);
+
} // namespace views
#endif // UI_VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_FACTORY_H_
diff --git a/chromium/ui/views/controls/button/image_button_factory_unittest.cc b/chromium/ui/views/controls/button/image_button_factory_unittest.cc
index 6a2e776d07d..f56c56cf044 100644
--- a/chromium/ui/views/controls/button/image_button_factory_unittest.cc
+++ b/chromium/ui/views/controls/button/image_button_factory_unittest.cc
@@ -20,7 +20,6 @@ TEST_F(ImageButtonFactoryTest, CreateVectorImageButton) {
ImageButton* button = CreateVectorImageButton(nullptr);
EXPECT_EQ(ImageButton::ALIGN_CENTER, button->h_alignment_);
EXPECT_EQ(ImageButton::ALIGN_MIDDLE, button->v_alignment_);
- EXPECT_TRUE(test::InkDropHostViewTestApi(button).HasGestureHandler());
delete button;
}
diff --git a/chromium/ui/views/controls/button/label_button.cc b/chromium/ui/views/controls/button/label_button.cc
index 60907bd19cd..8fd404aa239 100644
--- a/chromium/ui/views/controls/button/label_button.cc
+++ b/chromium/ui/views/controls/button/label_button.cc
@@ -11,6 +11,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "build/build_config.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
@@ -28,12 +29,16 @@
#include "ui/views/layout/layout_provider.h"
#include "ui/views/painter.h"
#include "ui/views/style/platform_style.h"
+#include "ui/views/view_properties.h"
#include "ui/views/window/dialog_delegate.h"
namespace views {
+namespace {
+// The length of the hover fade animation.
+constexpr int kHoverAnimationDurationMs = 170;
+} // namespace
// static
-const int LabelButton::kHoverAnimationDurationMs = 170;
const char LabelButton::kViewClassName[] = "LabelButton";
LabelButton::LabelButton(ButtonListener* listener,
@@ -386,6 +391,10 @@ std::unique_ptr<InkDrop> LabelButton::CreateInkDrop() {
}
std::unique_ptr<views::InkDropRipple> LabelButton::CreateInkDropRipple() const {
+ // Views that use a highlight path use the base style and do not need the
+ // overrides in this file.
+ if (GetProperty(views::kHighlightPathKey))
+ return InkDropHostView::CreateInkDropRipple();
return ShouldUseFloodFillInkDrop()
? std::make_unique<views::FloodFillInkDropRipple>(
size(), GetInkDropCenterBasedOnLastEvent(),
@@ -396,6 +405,10 @@ std::unique_ptr<views::InkDropRipple> LabelButton::CreateInkDropRipple() const {
std::unique_ptr<views::InkDropHighlight> LabelButton::CreateInkDropHighlight()
const {
+ // Views that use a highlight path use the base style and do not need the
+ // overrides in this file.
+ if (GetProperty(views::kHighlightPathKey))
+ return InkDropHostView::CreateInkDropHighlight();
return ShouldUseFloodFillInkDrop()
? std::make_unique<views::InkDropHighlight>(
size(), ink_drop_small_corner_radius(),
@@ -405,6 +418,12 @@ std::unique_ptr<views::InkDropHighlight> LabelButton::CreateInkDropHighlight()
gfx::RectF(image()->GetMirroredBounds()).CenterPoint());
}
+void LabelButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ if (is_default())
+ node_data->AddState(ax::mojom::State::kDefault);
+ Button::GetAccessibleNodeData(node_data);
+}
+
void LabelButton::StateChanged(ButtonState old_state) {
const gfx::Size previous_image_size(image_->GetPreferredSize());
UpdateImage();
@@ -484,7 +503,7 @@ void LabelButton::UpdateStyleToIndicateDefaultStatus() {
}
void LabelButton::UpdateImage() {
- image_->SetImage(GetImage(state()));
+ image_->SetImage(GetImage(GetVisualState()));
ResetCachedPreferredSize();
}
diff --git a/chromium/ui/views/controls/button/label_button.h b/chromium/ui/views/controls/button/label_button.h
index b2323dae3d9..1a1ab365ad7 100644
--- a/chromium/ui/views/controls/button/label_button.h
+++ b/chromium/ui/views/controls/button/label_button.h
@@ -28,9 +28,6 @@ class LabelButtonLabel;
// LabelButton is a button with text and an icon, it's not focusable by default.
class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
public:
- // The length of the hover fade animation.
- static const int kHoverAnimationDurationMs;
-
static const char kViewClassName[];
// Creates a LabelButton with ButtonPressed() events sent to |listener| and
@@ -101,6 +98,7 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
std::unique_ptr<InkDrop> CreateInkDrop() override;
std::unique_ptr<InkDropRipple> CreateInkDropRipple() const override;
std::unique_ptr<InkDropHighlight> CreateInkDropHighlight() const override;
+ void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
protected:
ImageView* image() const { return image_; }
diff --git a/chromium/ui/views/controls/button/label_button_unittest.cc b/chromium/ui/views/controls/button/label_button_unittest.cc
index 966ab6fec75..af7f28da1a0 100644
--- a/chromium/ui/views/controls/button/label_button_unittest.cc
+++ b/chromium/ui/views/controls/button/label_button_unittest.cc
@@ -22,12 +22,14 @@
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/text_utils.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/view_accessibility.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/layout/layout_provider.h"
#include "ui/views/style/platform_style.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
+#include "ui/views/widget/widget_utils.h"
using base::ASCIIToUTF16;
@@ -212,6 +214,30 @@ TEST_F(LabelButtonTest, AccessibleState) {
EXPECT_EQ(tooltip_text, tooltip);
}
+// Test View::GetAccessibleNodeData() for default buttons.
+TEST_F(LabelButtonTest, AccessibleDefaultState) {
+ {
+ // If SetIsDefault() is not called, the ax default state should not be set.
+ ui::AXNodeData ax_data;
+ button_->GetViewAccessibility().GetAccessibleNodeData(&ax_data);
+ EXPECT_FALSE(ax_data.HasState(ax::mojom::State::kDefault));
+ }
+
+ {
+ button_->SetIsDefault(true);
+ ui::AXNodeData ax_data;
+ button_->GetViewAccessibility().GetAccessibleNodeData(&ax_data);
+ EXPECT_TRUE(ax_data.HasState(ax::mojom::State::kDefault));
+ }
+
+ {
+ button_->SetIsDefault(false);
+ ui::AXNodeData ax_data;
+ button_->GetViewAccessibility().GetAccessibleNodeData(&ax_data);
+ EXPECT_FALSE(ax_data.HasState(ax::mojom::State::kDefault));
+ }
+}
+
TEST_F(LabelButtonTest, Image) {
const int small_size = 50, large_size = 100;
const gfx::ImageSkia small_image = CreateTestImage(small_size, small_size);
@@ -583,7 +609,7 @@ class InkDropLabelButtonTest : public ViewsTestBase {
};
TEST_F(InkDropLabelButtonTest, HoverStateAfterMouseEnterAndExitEvents) {
- ui::test::EventGenerator event_generator(widget_->GetNativeWindow());
+ ui::test::EventGenerator event_generator(GetRootWindow(widget_.get()));
const gfx::Point out_of_bounds_point(button_->bounds().bottom_right() +
gfx::Vector2d(1, 1));
const gfx::Point in_bounds_point(button_->bounds().CenterPoint());
diff --git a/chromium/ui/views/controls/button/md_text_button.cc b/chromium/ui/views/controls/button/md_text_button.cc
index 0d9f69cab39..c47cf87dcda 100644
--- a/chromium/ui/views/controls/button/md_text_button.cc
+++ b/chromium/ui/views/controls/button/md_text_button.cc
@@ -17,7 +17,6 @@
#include "ui/views/animation/ink_drop_painted_layer_delegates.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
-#include "ui/views/controls/button/blue_button.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/painter.h"
diff --git a/chromium/ui/views/controls/button/menu_button.cc b/chromium/ui/views/controls/button/menu_button.cc
index 7f38894e57c..23e59877636 100644
--- a/chromium/ui/views/controls/button/menu_button.cc
+++ b/chromium/ui/views/controls/button/menu_button.cc
@@ -4,185 +4,34 @@
#include "ui/views/controls/button/menu_button.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/base/dragdrop/drag_drop_types.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
-#include "ui/events/event_utils.h"
#include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image.h"
#include "ui/gfx/text_constants.h"
-#include "ui/resources/grit/ui_resources.h"
-#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/menu_button_listener.h"
#include "ui/views/mouse_constants.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
-
-using base::TimeTicks;
-using base::TimeDelta;
namespace views {
-
-// Default menu offset.
-static const int kDefaultMenuOffsetX = -2;
-static const int kDefaultMenuOffsetY = -4;
-
// static
const char MenuButton::kViewClassName[] = "MenuButton";
const int MenuButton::kMenuMarkerPaddingLeft = 3;
const int MenuButton::kMenuMarkerPaddingRight = -1;
-////////////////////////////////////////////////////////////////////////////////
-//
-// MenuButton::PressedLock
-//
-////////////////////////////////////////////////////////////////////////////////
-
-MenuButton::PressedLock::PressedLock(MenuButton* menu_button)
- : PressedLock(menu_button, false, nullptr) {}
-
-MenuButton::PressedLock::PressedLock(MenuButton* menu_button,
- bool is_sibling_menu_show,
- const ui::LocatedEvent* event)
- : menu_button_(menu_button->weak_factory_.GetWeakPtr()) {
- menu_button_->IncrementPressedLocked(is_sibling_menu_show, event);
-}
-
-MenuButton::PressedLock::~PressedLock() {
- if (menu_button_)
- menu_button_->DecrementPressedLocked();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// MenuButton - constructors, destructors, initialization
-//
-////////////////////////////////////////////////////////////////////////////////
-
MenuButton::MenuButton(const base::string16& text,
- MenuButtonListener* menu_button_listener,
- bool show_menu_marker)
+ MenuButtonListener* menu_button_listener)
: LabelButton(nullptr, text),
- menu_offset_(kDefaultMenuOffsetX, kDefaultMenuOffsetY),
- listener_(menu_button_listener),
- show_menu_marker_(show_menu_marker),
- menu_marker_(ui::ResourceBundle::GetSharedInstance()
- .GetImageNamed(IDR_MENU_DROPARROW)
- .ToImageSkia()),
- weak_factory_(this) {
+ menu_button_event_handler_(this, menu_button_listener) {
SetHorizontalAlignment(gfx::ALIGN_LEFT);
}
MenuButton::~MenuButton() = default;
-////////////////////////////////////////////////////////////////////////////////
-//
-// MenuButton - Public APIs
-//
-////////////////////////////////////////////////////////////////////////////////
-
bool MenuButton::Activate(const ui::Event* event) {
- if (listener_) {
- gfx::Rect lb = GetLocalBounds();
-
- // The position of the menu depends on whether or not the locale is
- // right-to-left.
- gfx::Point menu_position(lb.right(), lb.bottom());
- if (base::i18n::IsRTL())
- menu_position.set_x(lb.x());
-
- View::ConvertPointToScreen(this, &menu_position);
- if (base::i18n::IsRTL())
- menu_position.Offset(-menu_offset_.x(), menu_offset_.y());
- else
- menu_position.Offset(menu_offset_.x(), menu_offset_.y());
-
- int max_x_coordinate = GetMaximumScreenXCoordinate();
- if (max_x_coordinate && max_x_coordinate <= menu_position.x())
- menu_position.set_x(max_x_coordinate - 1);
-
- // We're about to show the menu from a mouse press. By showing from the
- // mouse press event we block RootView in mouse dispatching. This also
- // appears to cause RootView to get a mouse pressed BEFORE the mouse
- // release is seen, which means RootView sends us another mouse press no
- // matter where the user pressed. To force RootView to recalculate the
- // mouse target during the mouse press we explicitly set the mouse handler
- // to NULL.
- static_cast<internal::RootView*>(GetWidget()->GetRootView())
- ->SetMouseHandler(nullptr);
-
- DCHECK(increment_pressed_lock_called_ == nullptr);
- // Observe if IncrementPressedLocked() was called so we can trigger the
- // correct ink drop animations.
- bool increment_pressed_lock_called = false;
- increment_pressed_lock_called_ = &increment_pressed_lock_called;
-
- // Allow for OnMenuButtonClicked() to delete this.
- auto ref = weak_factory_.GetWeakPtr();
-
- // We don't set our state here. It's handled in the MenuController code or
- // by our click listener.
- listener_->OnMenuButtonClicked(this, menu_position, event);
-
- if (!ref) {
- // The menu was deleted while showing. Don't attempt any processing.
- return false;
- }
-
- increment_pressed_lock_called_ = nullptr;
-
- if (!increment_pressed_lock_called && pressed_lock_count_ == 0) {
- AnimateInkDrop(InkDropState::ACTION_TRIGGERED,
- ui::LocatedEvent::FromIfValid(event));
- }
-
- // We must return false here so that the RootView does not get stuck
- // sending all mouse pressed events to us instead of the appropriate
- // target.
- return false;
- }
-
- AnimateInkDrop(InkDropState::HIDDEN, ui::LocatedEvent::FromIfValid(event));
- return true;
+ return menu_button_event_handler_.Activate(event);
}
bool MenuButton::IsTriggerableEventType(const ui::Event& event) {
- if (event.IsMouseEvent()) {
- const ui::MouseEvent& mouseev = static_cast<const ui::MouseEvent&>(event);
- // Active on left mouse button only, to prevent a menu from being activated
- // when a right-click would also activate a context menu.
- if (!mouseev.IsOnlyLeftMouseButton())
- return false;
- // If dragging is supported activate on release, otherwise activate on
- // pressed.
- ui::EventType active_on =
- GetDragOperations(mouseev.location()) == ui::DragDropTypes::DRAG_NONE
- ? ui::ET_MOUSE_PRESSED
- : ui::ET_MOUSE_RELEASED;
- return event.type() == active_on;
- }
-
- return event.type() == ui::ET_GESTURE_TAP;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// MenuButton - Events
-//
-////////////////////////////////////////////////////////////////////////////////
-
-gfx::Size MenuButton::CalculatePreferredSize() const {
- gfx::Size prefsize = LabelButton::CalculatePreferredSize();
- if (show_menu_marker_) {
- prefsize.Enlarge(menu_marker_->width() + kMenuMarkerPaddingLeft +
- kMenuMarkerPaddingRight,
- 0);
- }
- return prefsize;
+ return menu_button_event_handler_.IsTriggerableEventType(event);
}
const char* MenuButton::GetClassName() const {
@@ -190,222 +39,48 @@ const char* MenuButton::GetClassName() const {
}
bool MenuButton::OnMousePressed(const ui::MouseEvent& event) {
- if (request_focus_on_press())
- RequestFocus();
- if (state() != STATE_DISABLED && HitTestPoint(event.location()) &&
- IsTriggerableEventType(event)) {
- if (IsTriggerableEvent(event))
- return Activate(&event);
- }
- return true;
+ return menu_button_event_handler_.OnMousePressed(event);
}
void MenuButton::OnMouseReleased(const ui::MouseEvent& event) {
- if (state() != STATE_DISABLED && IsTriggerableEvent(event) &&
- HitTestPoint(event.location()) && !InDrag()) {
- Activate(&event);
- } else {
- AnimateInkDrop(InkDropState::HIDDEN, &event);
- LabelButton::OnMouseReleased(event);
- }
-}
-
-void MenuButton::OnMouseEntered(const ui::MouseEvent& event) {
- if (pressed_lock_count_ == 0) // Ignore mouse movement if state is locked.
- LabelButton::OnMouseEntered(event);
-}
-
-void MenuButton::OnMouseExited(const ui::MouseEvent& event) {
- if (pressed_lock_count_ == 0) // Ignore mouse movement if state is locked.
- LabelButton::OnMouseExited(event);
-}
-
-void MenuButton::OnMouseMoved(const ui::MouseEvent& event) {
- if (pressed_lock_count_ == 0) // Ignore mouse movement if state is locked.
- LabelButton::OnMouseMoved(event);
-}
-
-void MenuButton::OnGestureEvent(ui::GestureEvent* event) {
- if (state() != STATE_DISABLED) {
- auto ref = weak_factory_.GetWeakPtr();
- if (IsTriggerableEvent(*event) && !Activate(event)) {
- if (!ref)
- return;
- // When |Activate()| returns |false|, it means the click was handled by
- // a button listener and has handled the gesture event. So, there is no
- // need to further process the gesture event here. However, if the
- // listener didn't run menu code, we should make sure to reset our state.
- if (state() == Button::STATE_HOVERED)
- SetState(Button::STATE_NORMAL);
- return;
- }
- if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
- event->SetHandled();
- if (pressed_lock_count_ == 0)
- SetState(Button::STATE_HOVERED);
- } else if (state() == Button::STATE_HOVERED &&
- (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
- event->type() == ui::ET_GESTURE_END) &&
- pressed_lock_count_ == 0) {
- SetState(Button::STATE_NORMAL);
- }
- }
- LabelButton::OnGestureEvent(event);
+ menu_button_event_handler_.OnMouseReleased(event);
}
bool MenuButton::OnKeyPressed(const ui::KeyEvent& event) {
- switch (event.key_code()) {
- case ui::VKEY_SPACE:
- // Alt-space on windows should show the window menu.
- if (event.IsAltDown())
- break;
- FALLTHROUGH;
- case ui::VKEY_RETURN:
- case ui::VKEY_UP:
- case ui::VKEY_DOWN: {
- // WARNING: we may have been deleted by the time Activate returns.
- Activate(&event);
- // This is to prevent the keyboard event from being dispatched twice. If
- // the keyboard event is not handled, we pass it to the default handler
- // which dispatches the event back to us causing the menu to get displayed
- // again. Return true to prevent this.
- return true;
- }
- default:
- break;
- }
- return false;
+ return menu_button_event_handler_.OnKeyPressed(event);
}
bool MenuButton::OnKeyReleased(const ui::KeyEvent& event) {
- // Override Button's implementation, which presses the button when
- // you press space and clicks it when you release space. For a MenuButton
- // we always activate the menu on key press.
- return false;
+ return menu_button_event_handler_.OnKeyReleased(event);
}
void MenuButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
- Button::GetAccessibleNodeData(node_data);
- node_data->role = ax::mojom::Role::kPopUpButton;
- node_data->SetHasPopup(ax::mojom::HasPopup::kMenu);
- if (enabled())
- node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kOpen);
-}
-
-void MenuButton::PaintMenuMarker(gfx::Canvas* canvas) {
- gfx::Insets insets = GetInsets();
-
- // Using the Views mirroring infrastructure incorrectly flips icon content.
- // Instead, manually mirror the position of the down arrow.
- gfx::Rect arrow_bounds(width() - insets.right() -
- menu_marker_->width() - kMenuMarkerPaddingRight,
- height() / 2 - menu_marker_->height() / 2,
- menu_marker_->width(),
- menu_marker_->height());
- arrow_bounds.set_x(GetMirroredXForRect(arrow_bounds));
- canvas->DrawImageInt(*menu_marker_, arrow_bounds.x(), arrow_bounds.y());
+ menu_button_event_handler_.GetAccessibleNodeData(node_data);
}
-gfx::Rect MenuButton::GetChildAreaBounds() {
- gfx::Size s = size();
-
- if (show_menu_marker_) {
- s.set_width(s.width() - menu_marker_->width() - kMenuMarkerPaddingLeft -
- kMenuMarkerPaddingRight);
- }
+void MenuButton::OnMouseEntered(const ui::MouseEvent& event) {}
+void MenuButton::OnMouseExited(const ui::MouseEvent& event) {}
+void MenuButton::OnMouseMoved(const ui::MouseEvent& event) {}
+void MenuButton::OnGestureEvent(ui::GestureEvent* event) {}
- return gfx::Rect(s);
+void MenuButton::LabelButtonStateChanged(ButtonState old_state) {
+ LabelButton::StateChanged(old_state);
}
bool MenuButton::IsTriggerableEvent(const ui::Event& event) {
- if (!IsTriggerableEventType(event))
- return false;
-
- TimeDelta delta = TimeTicks::Now() - menu_closed_time_;
- if (delta.InMilliseconds() < kMinimumMsBetweenButtonClicks)
- return false; // Not enough time since the menu closed.
-
- return true;
+ return menu_button_event_handler_.IsTriggerableEvent(event);
}
bool MenuButton::ShouldEnterPushedState(const ui::Event& event) {
- return IsTriggerableEventType(event);
+ return menu_button_event_handler_.ShouldEnterPushedState(event);
}
void MenuButton::StateChanged(ButtonState old_state) {
- if (pressed_lock_count_ != 0) {
- // The button's state was changed while it was supposed to be locked in a
- // pressed state. This shouldn't happen, but conceivably could if a caller
- // tries to switch from enabled to disabled or vice versa while the button
- // is pressed.
- if (state() == STATE_NORMAL)
- should_disable_after_press_ = false;
- else if (state() == STATE_DISABLED)
- should_disable_after_press_ = true;
- } else {
- LabelButton::StateChanged(old_state);
- }
+ menu_button_event_handler_.StateChanged(old_state);
}
void MenuButton::NotifyClick(const ui::Event& event) {
- // We don't forward events to the normal button listener, instead using the
- // MenuButtonListener.
- Activate(&event);
-}
-
-void MenuButton::PaintButtonContents(gfx::Canvas* canvas) {
- if (show_menu_marker_)
- PaintMenuMarker(canvas);
-}
-
-void MenuButton::IncrementPressedLocked(bool snap_ink_drop_to_activated,
- const ui::LocatedEvent* event) {
- ++pressed_lock_count_;
- if (increment_pressed_lock_called_)
- *increment_pressed_lock_called_ = true;
- should_disable_after_press_ = state() == STATE_DISABLED;
- if (state() != STATE_PRESSED) {
- if (snap_ink_drop_to_activated)
- GetInkDrop()->SnapToActivated();
- else
- AnimateInkDrop(InkDropState::ACTIVATED, event);
- }
- SetState(STATE_PRESSED);
- GetInkDrop()->SetHovered(false);
-}
-
-void MenuButton::DecrementPressedLocked() {
- --pressed_lock_count_;
- DCHECK_GE(pressed_lock_count_, 0);
-
- // If this was the last lock, manually reset state to the desired state.
- if (pressed_lock_count_ == 0) {
- menu_closed_time_ = TimeTicks::Now();
- ButtonState desired_state = STATE_NORMAL;
- if (should_disable_after_press_) {
- desired_state = STATE_DISABLED;
- should_disable_after_press_ = false;
- } else if (GetWidget() && !GetWidget()->dragged_view() &&
- ShouldEnterHoveredState()) {
- desired_state = STATE_HOVERED;
- GetInkDrop()->SetHovered(true);
- }
- SetState(desired_state);
- // The widget may be null during shutdown. If so, it doesn't make sense to
- // try to add an ink drop effect.
- if (GetWidget() && state() != STATE_PRESSED)
- AnimateInkDrop(InkDropState::DEACTIVATED, nullptr /* event */);
- }
-}
-
-int MenuButton::GetMaximumScreenXCoordinate() {
- if (!GetWidget()) {
- NOTREACHED();
- return 0;
- }
-
- gfx::Rect monitor_bounds = GetWidget()->GetWorkAreaBoundsInScreen();
- return monitor_bounds.right() - 1;
+ menu_button_event_handler_.NotifyClick(event);
}
-} // namespace views
+} // namespace views \ No newline at end of file
diff --git a/chromium/ui/views/controls/button/menu_button.h b/chromium/ui/views/controls/button/menu_button.h
index 8fb11e1cf9c..87e8faf7484 100644
--- a/chromium/ui/views/controls/button/menu_button.h
+++ b/chromium/ui/views/controls/button/menu_button.h
@@ -5,14 +5,10 @@
#ifndef UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
#define UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
-#include <string>
-
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/menu_button_event_handler.h"
namespace views {
@@ -27,23 +23,6 @@ class MenuButtonListener;
////////////////////////////////////////////////////////////////////////////////
class VIEWS_EXPORT MenuButton : public LabelButton {
public:
- // A scoped lock for keeping the MenuButton in STATE_PRESSED e.g., while a
- // menu is running. These are cumulative.
- class VIEWS_EXPORT PressedLock {
- public:
- explicit PressedLock(MenuButton* menu_button);
- // |event| is the event that caused the button to be pressed. May be null.
- PressedLock(MenuButton* menu_button,
- bool is_sibling_menu_show,
- const ui::LocatedEvent* event);
- ~PressedLock();
-
- private:
- base::WeakPtr<MenuButton> menu_button_;
-
- DISALLOW_COPY_AND_ASSIGN(PressedLock);
- };
-
static const char kViewClassName[];
// How much padding to put on the left and right of the menu marker.
@@ -52,104 +31,58 @@ class VIEWS_EXPORT MenuButton : public LabelButton {
// Create a Button.
MenuButton(const base::string16& text,
- MenuButtonListener* menu_button_listener,
- bool show_menu_marker);
+ MenuButtonListener* menu_button_listener);
~MenuButton() override;
- bool show_menu_marker() const { return show_menu_marker_; }
- void set_menu_marker(const gfx::ImageSkia* menu_marker) {
- menu_marker_ = menu_marker;
- }
- const gfx::ImageSkia* menu_marker() const { return menu_marker_; }
-
- const gfx::Point& menu_offset() const { return menu_offset_; }
- void set_menu_offset(int x, int y) { menu_offset_.SetPoint(x, y); }
-
- // Activate the button (called when the button is pressed). |event| is the
- // event triggering the activation, if any.
bool Activate(const ui::Event* event);
- // Returns true if the event is of the proper type to potentially trigger an
- // action. Since MenuButtons have properties other than event type (like
- // last menu open time) to determine if an event is valid to activate the
- // menu, this is distinct from IsTriggerableEvent().
+ // TODO(cyan): Move into MenuButtonEventHandler.
virtual bool IsTriggerableEventType(const ui::Event& event);
- // Overridden from View:
- gfx::Size CalculatePreferredSize() const override;
+ // View:
const char* GetClassName() const override;
bool OnMousePressed(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
- void OnMouseEntered(const ui::MouseEvent& event) override;
- void OnMouseExited(const ui::MouseEvent& event) override;
- void OnMouseMoved(const ui::MouseEvent& event) override;
- void OnGestureEvent(ui::GestureEvent* event) override;
bool OnKeyPressed(const ui::KeyEvent& event) override;
bool OnKeyReleased(const ui::KeyEvent& event) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
- protected:
- // Paint the menu marker image.
- void PaintMenuMarker(gfx::Canvas* canvas);
+ // Disallow overriding of these methods.
+ // No-op implementations as these are handled in MenuButtonEventHandler (and
+ // should not be handled here as well). To override these you need to subclass
+ // MenuButtonEventHandler and replace this event handler of the button.
+ void OnMouseEntered(const ui::MouseEvent& event) final;
+ void OnMouseExited(const ui::MouseEvent& event) final;
+ void OnMouseMoved(const ui::MouseEvent& event) final;
+
+ // Protected methods needed for MenuButtonEventHandler.
+ // TODO (cyan): Move these to a delegate interface.
+ using InkDropHostView::GetInkDrop;
+ using View::InDrag;
+ using View::GetDragOperations;
+ using Button::ShouldEnterHoveredState;
+ void LabelButtonStateChanged(ButtonState old_state);
+
+ // Button:
+ bool IsTriggerableEvent(const ui::Event& event) override;
- // Overridden from LabelButton:
- gfx::Rect GetChildAreaBounds() override;
+ MenuButtonEventHandler* menu_button_event_handler() {
+ return &menu_button_event_handler_;
+ }
- // Overridden from Button:
- bool IsTriggerableEvent(const ui::Event& event) override;
- bool ShouldEnterPushedState(const ui::Event& event) override;
+ protected:
void StateChanged(ButtonState old_state) override;
- void NotifyClick(const ui::Event& event) override;
- void PaintButtonContents(gfx::Canvas* canvas) override;
- // Offset of the associated menu position.
- gfx::Point menu_offset_;
+ // Button:
+ bool ShouldEnterPushedState(const ui::Event& event) final;
+ void NotifyClick(const ui::Event& event) final;
private:
- friend class PressedLock;
-
- // Increment/decrement the number of "pressed" locks this button has, and
- // set the state accordingly. The ink drop is snapped to the final ACTIVATED
- // state if |snap_ink_drop_to_activated| is true, otherwise the ink drop will
- // be animated to the ACTIVATED node_data. The ink drop is animated at the
- // location of |event| if non-null, otherwise at the default location.
- void IncrementPressedLocked(bool snap_ink_drop_to_activated,
- const ui::LocatedEvent* event);
- void DecrementPressedLocked();
-
- // Compute the maximum X coordinate for the current screen. MenuButtons
- // use this to make sure a menu is never shown off screen.
- int GetMaximumScreenXCoordinate();
-
- // We use a time object in order to keep track of when the menu was closed.
- // The time is used for simulating menu behavior for the menu button; that
- // is, if the menu is shown and the button is pressed, we need to close the
- // menu. There is no clean way to get the second click event because the
- // menu is displayed using a modal loop and, unlike regular menus in Windows,
- // the button is not part of the displayed menu.
- base::TimeTicks menu_closed_time_;
-
- // Our listener. Not owned.
- MenuButtonListener* listener_;
-
- // Whether or not we're showing a drop marker.
- bool show_menu_marker_;
-
- // The down arrow used to differentiate the menu button from normal buttons.
- const gfx::ImageSkia* menu_marker_;
-
- // The current number of "pressed" locks this button has.
- int pressed_lock_count_ = 0;
-
- // Used to let Activate() know if IncrementPressedLocked() was called.
- bool* increment_pressed_lock_called_ = nullptr;
-
- // True if the button was in a disabled state when a menu was run, and should
- // return to it once the press is complete. This can happen if, e.g., we
- // programmatically show a menu on a disabled button.
- bool should_disable_after_press_ = false;
-
- base::WeakPtrFactory<MenuButton> weak_factory_;
+ // All events get sent to this handler to be processed.
+ // TODO (cyan): This will be generalized into a ButtonEventHandler and moved
+ // into the Button class.
+ MenuButtonEventHandler menu_button_event_handler_;
DISALLOW_COPY_AND_ASSIGN(MenuButton);
};
diff --git a/chromium/ui/views/controls/button/menu_button_event_handler.cc b/chromium/ui/views/controls/button/menu_button_event_handler.cc
new file mode 100644
index 00000000000..2960da32944
--- /dev/null
+++ b/chromium/ui/views/controls/button/menu_button_event_handler.cc
@@ -0,0 +1,384 @@
+// 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/button/menu_button_event_handler.h"
+
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/events/event_constants.h"
+#include "ui/views/animation/ink_drop.h"
+#include "ui/views/controls/button/menu_button.h"
+#include "ui/views/controls/button/menu_button_listener.h"
+#include "ui/views/mouse_constants.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget.h"
+
+using base::TimeTicks;
+using base::TimeDelta;
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButtonEventHandler::PressedLock
+//
+////////////////////////////////////////////////////////////////////////////////
+
+MenuButtonEventHandler::PressedLock::PressedLock(
+ MenuButtonEventHandler* menu_button_event_handler)
+ : PressedLock(menu_button_event_handler, false, nullptr) {}
+
+MenuButtonEventHandler::PressedLock::PressedLock(
+ MenuButtonEventHandler* menu_button_event_handler,
+ bool is_sibling_menu_show,
+ const ui::LocatedEvent* event)
+ : menu_button_event_handler_(
+ menu_button_event_handler->weak_factory_.GetWeakPtr()) {
+ menu_button_event_handler_->IncrementPressedLocked(is_sibling_menu_show,
+ event);
+}
+
+std::unique_ptr<MenuButtonEventHandler::PressedLock>
+MenuButtonEventHandler::TakeLock() {
+ return TakeLock(false, nullptr);
+}
+
+std::unique_ptr<MenuButtonEventHandler::PressedLock>
+MenuButtonEventHandler::TakeLock(bool is_sibling_menu_show,
+ const ui::LocatedEvent* event) {
+ return std::make_unique<MenuButtonEventHandler::PressedLock>(
+ this, is_sibling_menu_show, event);
+}
+
+MenuButtonEventHandler::PressedLock::~PressedLock() {
+ if (menu_button_event_handler_)
+ menu_button_event_handler_->DecrementPressedLocked();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButtonEventHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+MenuButtonEventHandler::MenuButtonEventHandler(
+ MenuButton* menu_button_parent,
+ MenuButtonListener* menu_button_listener)
+ : menu_button_parent_(menu_button_parent), listener_(menu_button_listener) {
+ menu_button_parent_->AddPreTargetHandler(this);
+}
+
+MenuButtonEventHandler::~MenuButtonEventHandler() {
+ menu_button_parent_->RemovePreTargetHandler(this);
+}
+
+bool MenuButtonEventHandler::OnMousePressed(const ui::MouseEvent& event) {
+ if (menu_button_parent_->request_focus_on_press())
+ menu_button_parent_->RequestFocus();
+ if (menu_button_parent_->state() != Button::STATE_DISABLED &&
+ menu_button_parent_->HitTestPoint(event.location()) &&
+ menu_button_parent_->IsTriggerableEventType(event)) {
+ if (menu_button_parent_->IsTriggerableEvent(event))
+ return Activate(&event);
+ }
+ return true;
+}
+
+void MenuButtonEventHandler::OnMouseReleased(const ui::MouseEvent& event) {
+ if (menu_button_parent_->state() != Button::STATE_DISABLED &&
+ menu_button_parent_->IsTriggerableEvent(event) &&
+ menu_button_parent_->HitTestPoint(event.location()) &&
+ !menu_button_parent_->InDrag()) {
+ Activate(&event);
+ } else {
+ menu_button_parent_->AnimateInkDrop(InkDropState::HIDDEN, &event);
+ menu_button_parent_->LabelButton::OnMouseReleased(event);
+ }
+}
+
+void MenuButtonEventHandler::OnMouseEntered(const ui::MouseEvent& event) {
+ if (pressed_lock_count_ == 0) // Ignore mouse movement if state is locked.
+ menu_button_parent_->LabelButton::OnMouseEntered(event);
+}
+
+void MenuButtonEventHandler::OnMouseExited(const ui::MouseEvent& event) {
+ if (pressed_lock_count_ == 0) // Ignore mouse movement if state is locked.
+ menu_button_parent_->LabelButton::OnMouseExited(event);
+}
+
+void MenuButtonEventHandler::OnMouseMoved(const ui::MouseEvent& event) {
+ if (pressed_lock_count_ == 0) // Ignore mouse movement if state is locked.
+ menu_button_parent_->LabelButton::OnMouseMoved(event);
+}
+
+void MenuButtonEventHandler::OnGestureEvent(ui::GestureEvent* event) {
+ if (menu_button_parent_->state() != Button::STATE_DISABLED) {
+ auto ref = weak_factory_.GetWeakPtr();
+ if (menu_button_parent_->IsTriggerableEvent(*event) && !Activate(event)) {
+ if (!ref)
+ return;
+ // When |Activate()| returns |false|, it means the click was handled by
+ // a button listener and has handled the gesture event. So, there is no
+ // need to further process the gesture event here. However, if the
+ // listener didn't run menu code, we should make sure to reset our state.
+ if (menu_button_parent_->state() == Button::STATE_HOVERED)
+ menu_button_parent_->SetState(Button::STATE_NORMAL);
+ return;
+ }
+ if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
+ event->SetHandled();
+ if (pressed_lock_count_ == 0)
+ menu_button_parent_->SetState(Button::STATE_HOVERED);
+ } else if (menu_button_parent_->state() == Button::STATE_HOVERED &&
+ (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
+ event->type() == ui::ET_GESTURE_END) &&
+ pressed_lock_count_ == 0) {
+ menu_button_parent_->SetState(Button::STATE_NORMAL);
+ }
+ }
+ menu_button_parent_->LabelButton::OnGestureEvent(event);
+}
+
+bool MenuButtonEventHandler::OnKeyPressed(const ui::KeyEvent& event) {
+ switch (event.key_code()) {
+ case ui::VKEY_SPACE:
+ // Alt-space on windows should show the window menu.
+ if (event.IsAltDown())
+ break;
+ FALLTHROUGH;
+ case ui::VKEY_RETURN:
+ case ui::VKEY_UP:
+ case ui::VKEY_DOWN: {
+ // WARNING: we may have been deleted by the time Activate returns.
+ Activate(&event);
+ // This is to prevent the keyboard event from being dispatched twice. If
+ // the keyboard event is not handled, we pass it to the default handler
+ // which dispatches the event back to us causing the menu to get displayed
+ // again. Return true to prevent this.
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+bool MenuButtonEventHandler::OnKeyReleased(const ui::KeyEvent& event) {
+ // A MenuButton always activates the menu on key press.
+ return false;
+}
+
+void MenuButtonEventHandler::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+ menu_button_parent_->Button::GetAccessibleNodeData(node_data);
+ node_data->role = ax::mojom::Role::kPopUpButton;
+ node_data->SetHasPopup(ax::mojom::HasPopup::kMenu);
+ if (menu_button_parent_->enabled())
+ node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kOpen);
+}
+
+bool MenuButtonEventHandler::ShouldEnterPushedState(const ui::Event& event) {
+ return menu_button_parent_->IsTriggerableEventType(event);
+}
+
+void MenuButtonEventHandler::StateChanged(LabelButton::ButtonState old_state) {
+ if (pressed_lock_count_ != 0) {
+ // The button's state was changed while it was supposed to be locked in a
+ // pressed state. This shouldn't happen, but conceivably could if a caller
+ // tries to switch from enabled to disabled or vice versa while the button
+ // is pressed.
+ if (menu_button_parent_->state() == Button::STATE_NORMAL)
+ should_disable_after_press_ = false;
+ else if (menu_button_parent_->state() == Button::STATE_DISABLED)
+ should_disable_after_press_ = true;
+ } else {
+ menu_button_parent_->LabelButtonStateChanged(old_state);
+ }
+}
+
+void MenuButtonEventHandler::NotifyClick(const ui::Event& event) {
+ // We don't forward events to the normal button listener, instead using the
+ // MenuButtonListener.
+ Activate(&event);
+}
+
+void MenuButtonEventHandler::IncrementPressedLocked(
+ bool snap_ink_drop_to_activated,
+ const ui::LocatedEvent* event) {
+ ++pressed_lock_count_;
+ if (increment_pressed_lock_called_)
+ *(increment_pressed_lock_called_) = true;
+ should_disable_after_press_ =
+ menu_button_parent_->state() == Button::STATE_DISABLED;
+ if (menu_button_parent_->state() != Button::STATE_PRESSED) {
+ if (snap_ink_drop_to_activated) {
+ menu_button_parent_->GetInkDrop()->SnapToActivated();
+ } else
+ menu_button_parent_->AnimateInkDrop(InkDropState::ACTIVATED, event);
+ }
+ menu_button_parent_->SetState(Button::STATE_PRESSED);
+ menu_button_parent_->GetInkDrop()->SetHovered(false);
+}
+
+void MenuButtonEventHandler::DecrementPressedLocked() {
+ --pressed_lock_count_;
+ DCHECK_GE(pressed_lock_count_, 0);
+
+ // If this was the last lock, manually reset state to the desired state.
+ if (pressed_lock_count_ == 0) {
+ menu_closed_time_ = TimeTicks::Now();
+ LabelButton::ButtonState desired_state = Button::STATE_NORMAL;
+ if (should_disable_after_press_) {
+ desired_state = Button::STATE_DISABLED;
+ should_disable_after_press_ = false;
+ } else if (menu_button_parent_->GetWidget() &&
+ !menu_button_parent_->GetWidget()->dragged_view() &&
+ menu_button_parent_->ShouldEnterHoveredState()) {
+ desired_state = Button::STATE_HOVERED;
+ menu_button_parent_->GetInkDrop()->SetHovered(true);
+ }
+ menu_button_parent_->SetState(desired_state);
+ // The widget may be null during shutdown. If so, it doesn't make sense to
+ // try to add an ink drop effect.
+ if (menu_button_parent_->GetWidget() &&
+ menu_button_parent_->state() != Button::STATE_PRESSED)
+ menu_button_parent_->AnimateInkDrop(InkDropState::DEACTIVATED,
+ nullptr /* event */);
+ }
+}
+
+int MenuButtonEventHandler::GetMaximumScreenXCoordinate() {
+ if (!menu_button_parent_->GetWidget()) {
+ NOTREACHED();
+ return 0;
+ }
+
+ gfx::Rect monitor_bounds =
+ menu_button_parent_->GetWidget()->GetWorkAreaBoundsInScreen();
+ return monitor_bounds.right() - 1;
+}
+
+bool MenuButtonEventHandler::Activate(const ui::Event* event) {
+ if (listener_) {
+ gfx::Rect lb = menu_button_parent_->GetLocalBounds();
+
+ // Offset of the associated menu position.
+ constexpr gfx::Vector2d kMenuOffset{-2, -4};
+
+ // The position of the menu depends on whether or not the locale is
+ // right-to-left.
+ gfx::Point menu_position(lb.right(), lb.bottom());
+ if (base::i18n::IsRTL())
+ menu_position.set_x(lb.x());
+
+ View::ConvertPointToScreen(menu_button_parent_, &menu_position);
+ if (base::i18n::IsRTL())
+ menu_position.Offset(-kMenuOffset.x(), kMenuOffset.y());
+ else
+ menu_position += kMenuOffset;
+
+ int max_x_coordinate = GetMaximumScreenXCoordinate();
+ if (max_x_coordinate && max_x_coordinate <= menu_position.x())
+ menu_position.set_x(max_x_coordinate - 1);
+
+ // We're about to show the menu from a mouse press. By showing from the
+ // mouse press event we block RootView in mouse dispatching. This also
+ // appears to cause RootView to get a mouse pressed BEFORE the mouse
+ // release is seen, which means RootView sends us another mouse press no
+ // matter where the user pressed. To force RootView to recalculate the
+ // mouse target during the mouse press we explicitly set the mouse handler
+ // to NULL.
+ static_cast<internal::RootView*>(
+ menu_button_parent_->GetWidget()->GetRootView())
+ ->SetMouseHandler(nullptr);
+
+ DCHECK(increment_pressed_lock_called_ == nullptr);
+ // Observe if IncrementPressedLocked() was called so we can trigger the
+ // correct ink drop animations.
+ bool increment_pressed_lock_called = false;
+ increment_pressed_lock_called_ = &increment_pressed_lock_called;
+
+ // Allow for OnMenuButtonClicked() to delete this.
+ auto ref = weak_factory_.GetWeakPtr();
+
+ // We don't set our state here. It's handled in the MenuController code or
+ // by our click listener.
+ listener_->OnMenuButtonClicked(menu_button_parent_, menu_position, event);
+
+ if (!ref) {
+ // The menu was deleted while showing. Don't attempt any processing.
+ return false;
+ }
+
+ increment_pressed_lock_called_ = nullptr;
+
+ if (!increment_pressed_lock_called && pressed_lock_count_ == 0) {
+ menu_button_parent_->AnimateInkDrop(InkDropState::ACTION_TRIGGERED,
+ ui::LocatedEvent::FromIfValid(event));
+ }
+
+ // We must return false here so that the RootView does not get stuck
+ // sending all mouse pressed events to us instead of the appropriate
+ // target.
+ return false;
+ }
+
+ menu_button_parent_->AnimateInkDrop(InkDropState::HIDDEN,
+ ui::LocatedEvent::FromIfValid(event));
+ return true;
+}
+
+bool MenuButtonEventHandler::IsTriggerableEventType(const ui::Event& event) {
+ if (event.IsMouseEvent()) {
+ const ui::MouseEvent& mouseev = static_cast<const ui::MouseEvent&>(event);
+ // Active on left mouse button only, to prevent a menu from being activated
+ // when a right-click would also activate a context menu.
+ if (!mouseev.IsOnlyLeftMouseButton())
+ return false;
+ // If dragging is supported activate on release, otherwise activate on
+ // pressed.
+ ui::EventType active_on =
+ menu_button_parent_->GetDragOperations(mouseev.location()) ==
+ ui::DragDropTypes::DRAG_NONE
+ ? ui::ET_MOUSE_PRESSED
+ : ui::ET_MOUSE_RELEASED;
+ return event.type() == active_on;
+ }
+
+ return event.type() == ui::ET_GESTURE_TAP;
+}
+
+// TODO (cyan): Move all of the OnMouse.* methods here.
+// This gets more tricky because certain parts are still expected to be called
+// in the View::base class.
+void MenuButtonEventHandler::OnMouseEvent(ui::MouseEvent* event) {
+ switch (event->type()) {
+ case ui::ET_MOUSE_MOVED:
+ if ((event->flags() &
+ (ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON |
+ ui::EF_MIDDLE_MOUSE_BUTTON)) == 0) {
+ OnMouseMoved(*event);
+ return;
+ }
+ FALLTHROUGH;
+ case ui::ET_MOUSE_ENTERED:
+ if (event->flags() & ui::EF_TOUCH_ACCESSIBILITY)
+ menu_button_parent_->NotifyAccessibilityEvent(ax::mojom::Event::kHover,
+ true);
+ OnMouseEntered(*event);
+ break;
+ case ui::ET_MOUSE_EXITED:
+ OnMouseExited(*event);
+ break;
+ default:
+ return;
+ }
+}
+
+bool MenuButtonEventHandler::IsTriggerableEvent(const ui::Event& event) {
+ return menu_button_parent_->IsTriggerableEventType(event) &&
+ (TimeTicks::Now() - menu_closed_time_).InMilliseconds() >=
+ kMinimumMsBetweenButtonClicks;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/button/menu_button_event_handler.h b/chromium/ui/views/controls/button/menu_button_event_handler.h
new file mode 100644
index 00000000000..af44fa7b0a9
--- /dev/null
+++ b/chromium/ui/views/controls/button/menu_button_event_handler.h
@@ -0,0 +1,137 @@
+// 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_BUTTON_MENU_BUTTON_EVENT_HANDLER_H_
+#define UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_EVENT_HANDLER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "ui/events/event.h"
+#include "ui/views/controls/button/button.h"
+
+namespace ui {
+struct AXNodeData;
+}
+namespace views {
+class MenuButton;
+class MenuButtonListener;
+
+// An EventHandler that contains the event behavior of a MenuButton.
+// TODO (cyan): This will eventually be available to any Button derivative class
+// that wants MenuButton behavior.
+class VIEWS_EXPORT MenuButtonEventHandler : public ui::EventHandler {
+ public:
+ // A scoped lock for keeping the MenuButton in STATE_PRESSED e.g., while a
+ // menu is running. These are cumulative.
+ class VIEWS_EXPORT PressedLock {
+ public:
+ explicit PressedLock(MenuButtonEventHandler* menu_button_event_handler);
+
+ // |event| is the event that caused the button to be pressed. May be null.
+ PressedLock(MenuButtonEventHandler* menu_button_event_handler,
+ bool is_sibling_menu_show,
+ const ui::LocatedEvent* event);
+
+ ~PressedLock();
+
+ private:
+ base::WeakPtr<MenuButtonEventHandler> menu_button_event_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(PressedLock);
+ };
+
+ // TODO (cyan): MenuButtonEventHandler should take in a Button.
+ MenuButtonEventHandler(MenuButton* menu_button_parent,
+ MenuButtonListener* menu_button_listener);
+ ~MenuButtonEventHandler() override;
+
+ // TODO (cyan): Methods in this block should override EventHandler methods.
+ // These are currently called by the corresponding method from view::Views.
+ bool OnMousePressed(const ui::MouseEvent& event);
+ void OnMouseReleased(const ui::MouseEvent& event);
+ void OnMouseEntered(const ui::MouseEvent& event);
+ void OnMouseExited(const ui::MouseEvent& event);
+ void OnMouseMoved(const ui::MouseEvent& event);
+ bool OnKeyPressed(const ui::KeyEvent& event);
+ bool OnKeyReleased(const ui::KeyEvent& event);
+ void GetAccessibleNodeData(ui::AXNodeData* node_data);
+
+ // ui::EventHandler:
+ void OnGestureEvent(ui::GestureEvent* event) override;
+
+ // Calls TakeLock with is_sibling_menu_show as false and a nullptr to the
+ // event.
+ std::unique_ptr<PressedLock> TakeLock();
+
+ // Convenience method to increment the lock count on a button to keep the
+ // button in a PRESSED state when a menu is showing.
+ std::unique_ptr<PressedLock> TakeLock(bool is_sibling_menu_show,
+ const ui::LocatedEvent* event);
+
+ bool IsTriggerableEvent(const ui::Event& event);
+
+ bool ShouldEnterPushedState(const ui::Event& event);
+ void StateChanged(Button::ButtonState old_state);
+ void NotifyClick(const ui::Event& event);
+
+ // Activate the button (called when the button is pressed). |event| is the
+ // event triggering the activation, if any.
+ bool Activate(const ui::Event* event);
+
+ // Returns true if the event is of the proper type to potentially trigger an
+ // action. Since MenuButtons have properties other than event type (like
+ // last menu open time) to determine if an event is valid to activate the
+ // menu, this is distinct from IsTriggerableEvent().
+ bool IsTriggerableEventType(const ui::Event& event);
+
+ void OnMouseEvent(ui::MouseEvent* event) override;
+
+ private:
+ // Increment/decrement the number of "pressed" locks this button has, and
+ // set the state accordingly. The ink drop is snapped to the final ACTIVATED
+ // state if |snap_ink_drop_to_activated| is true, otherwise the ink drop
+ // will be animated to the ACTIVATED node_data. The ink drop is animated at
+ // the location of |event| if non-null, otherwise at the default location.
+ void IncrementPressedLocked(bool snap_ink_drop_to_activated,
+ const ui::LocatedEvent* event);
+
+ void DecrementPressedLocked();
+
+ // Compute the maximum X coordinate for the current screen. MenuButtons
+ // use this to make sure a menu is never shown off screen.
+ int GetMaximumScreenXCoordinate();
+
+ MenuButton* const menu_button_parent_;
+
+ // Our listener. Not owned.
+ MenuButtonListener* const listener_;
+
+ // We use a time object in order to keep track of when the menu was closed.
+ // The time is used for simulating menu behavior for the menu button; that
+ // is, if the menu is shown and the button is pressed, we need to close the
+ // menu. There is no clean way to get the second click event because the
+ // menu is displayed using a modal loop and, unlike regular menus in
+ // Windows, the button is not part of the displayed menu.
+ base::TimeTicks menu_closed_time_;
+
+ // The current number of "pressed" locks this button has.
+ int pressed_lock_count_ = 0;
+
+ // Used to let Activate() know if IncrementPressedLocked() was called.
+ bool* increment_pressed_lock_called_ = nullptr;
+
+ // True if the button was in a disabled state when a menu was run, and
+ // should return to it once the press is complete. This can happen if, e.g.,
+ // we programmatically show a menu on a disabled button.
+ bool should_disable_after_press_ = false;
+
+ base::WeakPtrFactory<MenuButtonEventHandler> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(MenuButtonEventHandler);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_CONTROLS_BUTTON_MENU_BUTTON_EVENT_HANDLER_H_ \ No newline at end of file
diff --git a/chromium/ui/views/controls/button/menu_button_unittest.cc b/chromium/ui/views/controls/button/menu_button_unittest.cc
index 969b67c86c5..823940021dc 100644
--- a/chromium/ui/views/controls/button/menu_button_unittest.cc
+++ b/chromium/ui/views/controls/button/menu_button_unittest.cc
@@ -15,9 +15,11 @@
#include "ui/events/test/event_generator.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/controls/button/menu_button_event_handler.h"
#include "ui/views/controls/button/menu_button_listener.h"
#include "ui/views/drag_controller.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget_utils.h"
#if defined(USE_AURA)
#include "ui/aura/client/drag_drop_client.h"
@@ -38,8 +40,7 @@ class TestMenuButton : public MenuButton {
public:
explicit TestMenuButton(MenuButtonListener* menu_button_listener)
: MenuButton(base::string16(ASCIIToUTF16("button")),
- menu_button_listener,
- false) {}
+ menu_button_listener) {}
~TestMenuButton() override {}
@@ -88,10 +89,11 @@ class MenuButtonTest : public ViewsTestBase {
void CreateMenuButton(MenuButtonListener* menu_button_listener) {
CreateWidget();
- generator_.reset(new ui::test::EventGenerator(widget_->GetNativeWindow()));
+ generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
// Set initial mouse location in a consistent way so that the menu button we
// are about to create initializes its hover state in a consistent manner.
- generator_->set_current_location(gfx::Point(10, 10));
+ generator_->set_current_screen_location(gfx::Point(10, 10));
button_ = new TestMenuButton(menu_button_listener);
button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
@@ -191,7 +193,7 @@ class PressStateMenuButtonListener : public MenuButtonListener {
void OnMenuButtonClicked(MenuButton* source,
const gfx::Point& point,
const ui::Event* event) override {
- pressed_lock_.reset(new MenuButton::PressedLock(menu_button_));
+ pressed_lock_ = menu_button_->menu_button_event_handler()->TakeLock();
if (release_lock_)
pressed_lock_.reset();
}
@@ -201,7 +203,7 @@ class PressStateMenuButtonListener : public MenuButtonListener {
private:
MenuButton* menu_button_;
- std::unique_ptr<MenuButton::PressedLock> pressed_lock_;
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock_;
// The |pressed_lock_| will be released when true.
bool release_lock_;
@@ -371,7 +373,8 @@ TEST_F(MenuButtonTest, InkDropCenterSetFromClickWithPressedLock) {
gfx::Point click_point(11, 7);
ui::MouseEvent click_event(ui::EventType::ET_MOUSE_PRESSED, click_point,
click_point, base::TimeTicks(), 0, 0);
- MenuButton::PressedLock pressed_lock(button(), false, &click_event);
+ MenuButtonEventHandler::PressedLock pressed_lock(
+ button()->menu_button_event_handler(), false, &click_event);
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
EXPECT_EQ(
@@ -394,8 +397,9 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
EXPECT_EQ(Button::STATE_HOVERED, button()->state());
// Introduce a PressedLock, which should make the button pressed.
- std::unique_ptr<MenuButton::PressedLock> pressed_lock1(
- new MenuButton::PressedLock(button()));
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock1(
+ new MenuButtonEventHandler::PressedLock(
+ button()->menu_button_event_handler()));
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
// Even if we move the mouse outside of the button, it should remain pressed.
@@ -403,8 +407,9 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
// Creating a new lock should obviously keep the button pressed.
- std::unique_ptr<MenuButton::PressedLock> pressed_lock2(
- new MenuButton::PressedLock(button()));
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock2(
+ new MenuButtonEventHandler::PressedLock(
+ button()->menu_button_event_handler()));
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
// The button should remain pressed while any locks are active.
@@ -421,7 +426,7 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
// Test that the button returns to the appropriate state after the press; if
// the mouse ends over the button, the button should be hovered.
- pressed_lock1.reset(new MenuButton::PressedLock(button()));
+ pressed_lock1 = button()->menu_button_event_handler()->TakeLock();
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
pressed_lock1.reset();
EXPECT_EQ(Button::STATE_HOVERED, button()->state());
@@ -429,7 +434,7 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
// If the button is disabled before the pressed lock, it should be disabled
// after the pressed lock.
button()->SetState(Button::STATE_DISABLED);
- pressed_lock1.reset(new MenuButton::PressedLock(button()));
+ pressed_lock1 = button()->menu_button_event_handler()->TakeLock();
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
pressed_lock1.reset();
EXPECT_EQ(Button::STATE_DISABLED, button()->state());
@@ -438,7 +443,7 @@ TEST_F(MenuButtonTest, ButtonStateForMenuButtonsWithPressedLocks) {
// Edge case: the button is disabled, a pressed lock is added, and then the
// button is re-enabled. It should be enabled after the lock is removed.
- pressed_lock1.reset(new MenuButton::PressedLock(button()));
+ pressed_lock1 = button()->menu_button_event_handler()->TakeLock();
EXPECT_EQ(Button::STATE_PRESSED, button()->state());
button()->SetState(Button::STATE_NORMAL);
pressed_lock1.reset();
@@ -516,13 +521,15 @@ TEST_F(MenuButtonTest,
TEST_F(MenuButtonTest, InkDropStateForMenuButtonsWithPressedLocks) {
CreateMenuButtonWithNoListener();
- std::unique_ptr<MenuButton::PressedLock> pressed_lock1(
- new MenuButton::PressedLock(button()));
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock1(
+ new MenuButtonEventHandler::PressedLock(
+ button()->menu_button_event_handler()));
EXPECT_EQ(InkDropState::ACTIVATED, ink_drop()->GetTargetInkDropState());
- std::unique_ptr<MenuButton::PressedLock> pressed_lock2(
- new MenuButton::PressedLock(button()));
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock2(
+ new MenuButtonEventHandler::PressedLock(
+ button()->menu_button_event_handler()));
EXPECT_EQ(InkDropState::ACTIVATED, ink_drop()->GetTargetInkDropState());
@@ -538,14 +545,16 @@ TEST_F(MenuButtonTest, InkDropStateForMenuButtonsWithPressedLocks) {
TEST_F(MenuButtonTest, OneInkDropAnimationForReentrantPressedLocks) {
CreateMenuButtonWithNoListener();
- std::unique_ptr<MenuButton::PressedLock> pressed_lock1(
- new MenuButton::PressedLock(button()));
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock1(
+ new MenuButtonEventHandler::PressedLock(
+ button()->menu_button_event_handler()));
EXPECT_EQ(InkDropState::ACTIVATED, ink_drop()->GetTargetInkDropState());
ink_drop()->AnimateToState(InkDropState::ACTION_PENDING);
- std::unique_ptr<MenuButton::PressedLock> pressed_lock2(
- new MenuButton::PressedLock(button()));
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock2(
+ new MenuButtonEventHandler::PressedLock(
+ button()->menu_button_event_handler()));
EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop()->GetTargetInkDropState());
}
@@ -556,7 +565,8 @@ TEST_F(MenuButtonTest,
InkDropStateForMenuButtonWithPressedLockBeforeActivation) {
TestMenuButtonListener menu_button_listener;
CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
- MenuButton::PressedLock lock(button());
+ MenuButtonEventHandler::PressedLock lock(
+ button()->menu_button_event_handler());
button()->Activate(nullptr);
@@ -585,6 +595,7 @@ TEST_F(MenuButtonTest, DraggableMenuButtonDoesNotActivateOnDrag) {
generator()->DragMouseBy(10, 0);
EXPECT_EQ(nullptr, menu_button_listener.last_source());
EXPECT_EQ(Button::STATE_NORMAL, menu_button_listener.last_source_state());
+ button()->RemovePreTargetHandler(&drag_client);
}
#endif // USE_AURA
@@ -692,7 +703,7 @@ TEST_F(MenuButtonTest,
class DestroyButtonInGestureListener : public MenuButtonListener {
public:
DestroyButtonInGestureListener() {
- menu_button_ = std::make_unique<MenuButton>(base::string16(), this, true);
+ menu_button_ = std::make_unique<MenuButton>(base::string16(), this);
}
~DestroyButtonInGestureListener() override = default;
diff --git a/chromium/ui/views/controls/button/toggle_button_unittest.cc b/chromium/ui/views/controls/button/toggle_button_unittest.cc
index 2315f7935b7..1b77d087c29 100644
--- a/chromium/ui/views/controls/button/toggle_button_unittest.cc
+++ b/chromium/ui/views/controls/button/toggle_button_unittest.cc
@@ -10,6 +10,7 @@
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget_utils.h"
namespace views {
@@ -108,7 +109,7 @@ TEST_F(ToggleButtonTest, ShutdownWithFocus) {
// Verify that ToggleButton::accepts_events_ works as expected.
TEST_F(ToggleButtonTest, AcceptEvents) {
EXPECT_FALSE(button()->is_on());
- ui::test::EventGenerator generator(widget()->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget()));
// Clicking toggles.
generator.ClickLeftButton();
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc
index f900b99d012..41a5ac2b1b3 100644
--- a/chromium/ui/views/controls/combobox/combobox.cc
+++ b/chromium/ui/views/controls/combobox/combobox.cc
@@ -4,93 +4,41 @@
#include "ui/views/controls/combobox/combobox.h"
-#include <stddef.h>
-
-#include <utility>
-
#include "base/logging.h"
-#include "base/macros.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_node_data.h"
-#include "ui/base/default_style.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/models/combobox_model.h"
#include "ui/base/models/combobox_model_observer.h"
-#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/models/menu_model.h"
#include "ui/events/event.h"
-#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/text_utils.h"
-#include "ui/native_theme/common_theme.h"
#include "ui/native_theme/native_theme.h"
-#include "ui/native_theme/native_theme_aura.h"
-#include "ui/resources/grit/ui_resources.h"
#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
-#include "ui/views/animation/ink_drop_highlight.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/background.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/focusable_border.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/prefix_selector.h"
-#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/mouse_constants.h"
-#include "ui/views/painter.h"
-#include "ui/views/resources/grit/views_resources.h"
#include "ui/views/style/platform_style.h"
+#include "ui/views/style/typography.h"
#include "ui/views/widget/widget.h"
namespace views {
namespace {
-// STYLE_ACTION arrow container padding widths.
-const int kActionLeftPadding = 12;
-const int kActionRightPadding = 11;
-
-// Menu border widths
-const int kMenuBorderWidthLeft = 1;
-const int kMenuBorderWidthTop = 1;
-const int kMenuBorderWidthRight = 1;
-
-// Limit how small a combobox can be.
-const int kMinComboboxWidth = 25;
-
-// Define the id of the first item in the menu (since it needs to be > 0)
-const int kFirstMenuItemId = 1000;
-
// Used to indicate that no item is currently selected by the user.
-const int kNoSelection = -1;
-
-const int kBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON);
-const int kHoveredBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
-const int kPressedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
-const int kFocusedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
-const int kFocusedHoveredBodyButtonImages[] =
- IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_H);
-const int kFocusedPressedBodyButtonImages[] =
- IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_P);
-
-#define MENU_IMAGE_GRID(x) { \
- x ## _MENU_TOP, x ## _MENU_CENTER, x ## _MENU_BOTTOM, }
-
-const int kMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON);
-const int kHoveredMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
-const int kPressedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
-const int kFocusedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
-const int kFocusedHoveredMenuButtonImages[] =
- MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_H);
-const int kFocusedPressedMenuButtonImages[] =
- MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_P);
-
-#undef MENU_IMAGE_GRID
+constexpr int kNoSelection = -1;
SkColor GetTextColorForEnableState(const Combobox& combobox, bool enabled) {
return style::GetColor(
@@ -98,30 +46,10 @@ SkColor GetTextColorForEnableState(const Combobox& combobox, bool enabled) {
enabled ? style::STYLE_PRIMARY : style::STYLE_DISABLED);
}
-gfx::Rect PositionArrowWithinContainer(const gfx::Rect& container_bounds,
- const gfx::Size& arrow_size,
- Combobox::Style style) {
- gfx::Rect bounds(container_bounds);
- if (style == Combobox::STYLE_ACTION) {
- // This positions the arrow horizontally. The later call to
- // ClampToCenteredSize will position it vertically without touching the
- // horizontal position.
- bounds.Inset(kActionLeftPadding, 0, kActionRightPadding, 0);
- DCHECK_EQ(bounds.width(), arrow_size.width());
- }
-
- bounds.ClampToCenteredSize(arrow_size);
- return bounds;
-}
-
// The transparent button which holds a button state but is not rendered.
class TransparentButton : public Button {
public:
- TransparentButton(ButtonListener* listener, bool animate_state_change)
- : Button(listener) {
- set_animate_on_state_change(animate_state_change);
- if (animate_state_change)
- SetAnimationDuration(LabelButton::kHoverAnimationDurationMs);
+ explicit TransparentButton(ButtonListener* listener) : Button(listener) {
SetFocusBehavior(FocusBehavior::NEVER);
set_notify_action(PlatformStyle::kMenuNotifyActivationAction);
@@ -180,103 +108,6 @@ int GetAdjacentIndex(ui::ComboboxModel* model, int increment, int index) {
}
#endif
-// Returns the image resource ids of an array for the body button.
-//
-// TODO(hajimehoshi): This function should return the images for the 'disabled'
-// status. (crbug/270052)
-const int* GetBodyButtonImageIds(bool focused,
- Button::ButtonState state,
- size_t* num) {
- DCHECK(num);
- *num = 9;
- switch (state) {
- case Button::STATE_DISABLED:
- return focused ? kFocusedBodyButtonImages : kBodyButtonImages;
- case Button::STATE_NORMAL:
- return focused ? kFocusedBodyButtonImages : kBodyButtonImages;
- case Button::STATE_HOVERED:
- return focused ?
- kFocusedHoveredBodyButtonImages : kHoveredBodyButtonImages;
- case Button::STATE_PRESSED:
- return focused ?
- kFocusedPressedBodyButtonImages : kPressedBodyButtonImages;
- default:
- NOTREACHED();
- }
- return NULL;
-}
-
-// Returns the image resource ids of an array for the menu button.
-const int* GetMenuButtonImageIds(bool focused,
- Button::ButtonState state,
- size_t* num) {
- DCHECK(num);
- *num = 3;
- switch (state) {
- case Button::STATE_DISABLED:
- return focused ? kFocusedMenuButtonImages : kMenuButtonImages;
- case Button::STATE_NORMAL:
- return focused ? kFocusedMenuButtonImages : kMenuButtonImages;
- case Button::STATE_HOVERED:
- return focused ?
- kFocusedHoveredMenuButtonImages : kHoveredMenuButtonImages;
- case Button::STATE_PRESSED:
- return focused ?
- kFocusedPressedMenuButtonImages : kPressedMenuButtonImages;
- default:
- NOTREACHED();
- }
- return NULL;
-}
-
-// Returns the images for the menu buttons.
-std::vector<const gfx::ImageSkia*> GetMenuButtonImages(
- bool focused,
- Button::ButtonState state) {
- const int* ids;
- size_t num_ids;
- ids = GetMenuButtonImageIds(focused, state, &num_ids);
- std::vector<const gfx::ImageSkia*> images;
- images.reserve(num_ids);
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- for (size_t i = 0; i < num_ids; i++)
- images.push_back(rb.GetImageSkiaNamed(ids[i]));
- return images;
-}
-
-// Paints three images in a column at the given location. The center image is
-// stretched so as to fit the given height.
-void PaintImagesVertically(gfx::Canvas* canvas,
- const gfx::ImageSkia& top_image,
- const gfx::ImageSkia& center_image,
- const gfx::ImageSkia& bottom_image,
- int x, int y, int width, int height) {
- canvas->DrawImageInt(top_image,
- 0, 0, top_image.width(), top_image.height(),
- x, y, width, top_image.height(), false);
- y += top_image.height();
- int center_height = height - top_image.height() - bottom_image.height();
- canvas->DrawImageInt(center_image,
- 0, 0, center_image.width(), center_image.height(),
- x, y, width, center_height, false);
- y += center_height;
- canvas->DrawImageInt(bottom_image,
- 0, 0, bottom_image.width(), bottom_image.height(),
- x, y, width, bottom_image.height(), false);
-}
-
-// Paints the arrow button.
-void PaintArrowButton(
- gfx::Canvas* canvas,
- const std::vector<const gfx::ImageSkia*>& arrow_button_images,
- int x, int height) {
- PaintImagesVertically(canvas,
- *arrow_button_images[0],
- *arrow_button_images[1],
- *arrow_button_images[2],
- x, 0, arrow_button_images[0]->width(), height);
-}
-
} // namespace
// static
@@ -295,8 +126,7 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
private:
bool UseCheckmarks() const {
- return owner_->style_ != STYLE_ACTION &&
- MenuConfig::instance().check_selected_combobox_item;
+ return MenuConfig::instance().check_selected_combobox_item;
}
// Overridden from MenuModel:
@@ -305,12 +135,8 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
int GetItemCount() const override { return model_->GetItemCount(); }
ItemType GetTypeAt(int index) const override {
- if (model_->IsItemSeparatorAt(index)) {
- // In action menus, disallow <item>, <separator>, ... since that would put
- // a separator at the top of the menu.
- DCHECK(index != 1 || owner_->style_ != STYLE_ACTION);
+ if (model_->IsItemSeparatorAt(index))
return TYPE_SEPARATOR;
- }
return UseCheckmarks() ? TYPE_CHECK : TYPE_COMMAND;
}
@@ -319,6 +145,8 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
}
int GetCommandIdAt(int index) const override {
+ // Define the id of the first item in the menu (since it needs to be > 0)
+ constexpr int kFirstMenuItemId = 1000;
return index + kFirstMenuItemId;
}
@@ -357,13 +185,6 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
return model_->IsItemEnabledAt(index);
}
- bool IsVisibleAt(int index) const override {
- // When STYLE_ACTION is used, the first item is not added to the menu. It is
- // assumed that the first item is always selected and rendered on the top of
- // the action button.
- return index > 0 || owner_->style_ != STYLE_ACTION;
- }
-
void HighlightChangedTo(int index) override {}
void ActivatedAt(int index) override {
@@ -396,22 +217,19 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel,
////////////////////////////////////////////////////////////////////////////////
// Combobox, public:
-Combobox::Combobox(std::unique_ptr<ui::ComboboxModel> model, Style style)
- : Combobox(model.get(), style) {
+Combobox::Combobox(std::unique_ptr<ui::ComboboxModel> model)
+ : Combobox(model.get()) {
owned_model_ = std::move(model);
}
-Combobox::Combobox(ui::ComboboxModel* model, Style style)
+Combobox::Combobox(ui::ComboboxModel* model)
: model_(model),
- style_(style),
listener_(nullptr),
- selected_index_(style == STYLE_ACTION ? 0 : model_->GetDefaultIndex()),
+ selected_index_(model_->GetDefaultIndex()),
invalid_(false),
menu_model_(new ComboboxMenuModel(this, model)),
- text_button_(new TransparentButton(this, style_ == STYLE_ACTION)),
- arrow_button_(new TransparentButton(this, style_ == STYLE_ACTION)),
- size_to_largest_label_(style_ == STYLE_NORMAL),
- weak_ptr_factory_(this) {
+ arrow_button_(new TransparentButton(this)),
+ size_to_largest_label_(true) {
ModelChanged();
#if defined(OS_MACOSX)
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
@@ -421,29 +239,7 @@ Combobox::Combobox(ui::ComboboxModel* model, Style style)
UpdateBorder();
- // Initialize the button images.
- Button::ButtonState button_states[] = {
- Button::STATE_DISABLED,
- Button::STATE_NORMAL,
- Button::STATE_HOVERED,
- Button::STATE_PRESSED,
- };
- for (int i = 0; i < 2; i++) {
- for (size_t state_index = 0; state_index < arraysize(button_states);
- state_index++) {
- Button::ButtonState state = button_states[state_index];
- size_t num;
- bool focused = !!i;
- const int* ids = GetBodyButtonImageIds(focused, state, &num);
- body_button_painters_[focused][state] =
- Painter::CreateImageGridPainter(ids);
- menu_button_images_[focused][state] = GetMenuButtonImages(focused, state);
- }
- }
-
- text_button_->SetVisible(true);
arrow_button_->SetVisible(true);
- AddChildView(text_button_);
AddChildView(arrow_button_);
// A layer is applied to make sure that canvas bounds are snapped to pixel
@@ -463,8 +259,7 @@ Combobox::~Combobox() {
// static
const gfx::FontList& Combobox::GetFontList() {
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
+ return style::GetFont(style::CONTEXT_BUTTON, style::STYLE_PRIMARY);
}
void Combobox::ModelChanged() {
@@ -482,9 +277,6 @@ void Combobox::ModelChanged() {
}
void Combobox::SetSelectedIndex(int index) {
- if (style_ == STYLE_ACTION)
- return;
-
selected_index_ = index;
if (size_to_largest_label_) {
SchedulePaint();
@@ -495,9 +287,6 @@ void Combobox::SetSelectedIndex(int index) {
}
bool Combobox::SelectValue(const base::string16& value) {
- if (style_ == STYLE_ACTION)
- return false;
-
for (int i = 0; i < model()->GetItemCount(); ++i) {
if (value == model()->GetItemAt(i)) {
SetSelectedIndex(i);
@@ -532,25 +321,7 @@ void Combobox::SetInvalid(bool invalid) {
void Combobox::Layout() {
View::Layout();
-
- int text_button_width = 0;
- int arrow_button_width = 0;
-
- switch (style_) {
- case STYLE_NORMAL: {
- arrow_button_width = width();
- break;
- }
- case STYLE_ACTION: {
- arrow_button_width = GetArrowContainerWidth();
- text_button_width = width() - arrow_button_width;
- break;
- }
- }
-
- int arrow_button_x = std::max(0, text_button_width);
- text_button_->SetBounds(0, 0, std::max(0, text_button_width), height());
- arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height());
+ arrow_button_->SetBounds(0, 0, width(), height());
}
void Combobox::OnNativeThemeChanged(const ui::NativeTheme* theme) {
@@ -585,6 +356,9 @@ base::string16 Combobox::GetTextForRow(int row) {
// Combobox, View overrides:
gfx::Size Combobox::CalculatePreferredSize() const {
+ // Limit how small a combobox can be.
+ constexpr int kMinComboboxWidth = 25;
+
// The preferred size will drive the local bounds which in turn is used to set
// the minimum width for the dropdown list.
gfx::Insets insets = GetInsets();
@@ -664,21 +438,9 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
new_index = GetAdjacentIndex(model(), -1, selected_index_);
break;
- case ui::VKEY_SPACE:
- if (style_ == STYLE_ACTION) {
- // When pressing space, the click event will be raised after the key is
- // released.
- text_button_->SetState(Button::STATE_PRESSED);
- } else {
- show_menu = true;
- }
- break;
-
case ui::VKEY_RETURN:
- if (style_ == STYLE_ACTION)
- OnPerformAction();
- else
- show_menu = true;
+ case ui::VKEY_SPACE:
+ show_menu = true;
break;
#endif // OS_MACOSX
default:
@@ -687,8 +449,7 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
if (show_menu) {
ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD);
- } else if (new_index != selected_index_ && new_index != kNoSelection &&
- style_ != STYLE_ACTION) {
+ } else if (new_index != selected_index_ && new_index != kNoSelection) {
DCHECK(!model()->IsItemSeparatorAt(new_index));
selected_index_ = new_index;
OnPerformAction();
@@ -697,31 +458,10 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
return true;
}
-bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
- if (style_ != STYLE_ACTION)
- return false; // crbug.com/127520
-
- if (e.key_code() == ui::VKEY_SPACE && style_ == STYLE_ACTION &&
- text_button_->state() == Button::STATE_PRESSED)
- OnPerformAction();
-
- return false;
-}
-
void Combobox::OnPaint(gfx::Canvas* canvas) {
- switch (style_) {
- case STYLE_NORMAL: {
- OnPaintBackground(canvas);
- PaintText(canvas);
- OnPaintBorder(canvas);
- break;
- }
- case STYLE_ACTION: {
- PaintButtons(canvas);
- PaintText(canvas);
- break;
- }
- }
+ OnPaintBackground(canvas);
+ PaintText(canvas);
+ OnPaintBorder(canvas);
}
void Combobox::OnFocus() {
@@ -779,29 +519,22 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
if (!enabled())
return;
- if (sender == text_button_) {
- OnPerformAction();
- } else {
- DCHECK_EQ(arrow_button_, sender);
- // TODO(hajimehoshi): Fix the problem that the arrow button blinks when
- // cliking this while the dropdown menu is opened.
- const base::TimeDelta delta = base::Time::Now() - closed_time_;
- if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks)
- return;
+ // TODO(hajimehoshi): Fix the problem that the arrow button blinks when
+ // cliking this while the dropdown menu is opened.
+ const base::TimeDelta delta = base::Time::Now() - closed_time_;
+ if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks)
+ return;
- ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
- if (event.IsKeyEvent())
- source_type = ui::MENU_SOURCE_KEYBOARD;
- else if (event.IsGestureEvent() || event.IsTouchEvent())
- source_type = ui::MENU_SOURCE_TOUCH;
- ShowDropDownMenu(source_type);
- }
+ ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
+ if (event.IsKeyEvent())
+ source_type = ui::MENU_SOURCE_KEYBOARD;
+ else if (event.IsGestureEvent() || event.IsTouchEvent())
+ source_type = ui::MENU_SOURCE_TOUCH;
+ ShowDropDownMenu(source_type);
}
void Combobox::UpdateBorder() {
std::unique_ptr<FocusableBorder> border(new FocusableBorder());
- if (style_ == STYLE_ACTION)
- border->SetInsets(5, 10, 5, 10);
if (invalid_)
border->SetColorId(ui::NativeTheme::kColorId_AlertSeverityHigh);
SetBorder(std::move(border));
@@ -842,8 +575,7 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
gfx::Rect arrow_bounds(disclosure_arrow_offset, 0, GetArrowContainerWidth(),
height());
- arrow_bounds =
- PositionArrowWithinContainer(arrow_bounds, ArrowSize(), style_);
+ arrow_bounds.ClampToCenteredSize(ArrowSize());
AdjustBoundsForRTLUI(&arrow_bounds);
{
@@ -874,82 +606,28 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
}
}
-void Combobox::PaintButtons(gfx::Canvas* canvas) {
- DCHECK(style_ == STYLE_ACTION);
-
- gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, width());
-
- bool focused = HasFocus();
- const std::vector<const gfx::ImageSkia*>& arrow_button_images =
- menu_button_images_[focused][
- arrow_button_->state() == Button::STATE_HOVERED ?
- Button::STATE_NORMAL : arrow_button_->state()];
-
- int text_button_hover_alpha =
- text_button_->state() == Button::STATE_PRESSED ? 0 :
- static_cast<int>(static_cast<TransparentButton*>(text_button_)->
- GetAnimationValue() * 255);
- if (text_button_hover_alpha < 255) {
- canvas->SaveLayerAlpha(255 - text_button_hover_alpha);
- Painter* text_button_painter =
- body_button_painters_[focused][
- text_button_->state() == Button::STATE_HOVERED ?
- Button::STATE_NORMAL : text_button_->state()].get();
- Painter::PaintPainterAt(canvas, text_button_painter,
- gfx::Rect(0, 0, text_button_->width(), height()));
- canvas->Restore();
- }
- if (0 < text_button_hover_alpha) {
- canvas->SaveLayerAlpha(text_button_hover_alpha);
- Painter* text_button_hovered_painter =
- body_button_painters_[focused][Button::STATE_HOVERED].get();
- Painter::PaintPainterAt(canvas, text_button_hovered_painter,
- gfx::Rect(0, 0, text_button_->width(), height()));
- canvas->Restore();
- }
-
- int arrow_button_hover_alpha =
- arrow_button_->state() == Button::STATE_PRESSED ? 0 :
- static_cast<int>(static_cast<TransparentButton*>(arrow_button_)->
- GetAnimationValue() * 255);
- if (arrow_button_hover_alpha < 255) {
- canvas->SaveLayerAlpha(255 - arrow_button_hover_alpha);
- PaintArrowButton(canvas, arrow_button_images, arrow_button_->x(), height());
- canvas->Restore();
- }
- if (0 < arrow_button_hover_alpha) {
- canvas->SaveLayerAlpha(arrow_button_hover_alpha);
- const std::vector<const gfx::ImageSkia*>& arrow_button_hovered_images =
- menu_button_images_[focused][Button::STATE_HOVERED];
- PaintArrowButton(canvas, arrow_button_hovered_images,
- arrow_button_->x(), height());
- canvas->Restore();
- }
-}
-
void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
+ // Menu border widths.
+ constexpr int kMenuBorderWidthLeft = 1;
+ constexpr int kMenuBorderWidthTop = 1;
+ constexpr int kMenuBorderWidthRight = 1;
+
gfx::Rect lb = GetLocalBounds();
gfx::Point menu_position(lb.origin());
- if (style_ == STYLE_NORMAL) {
- // Inset the menu's requested position so the border of the menu lines up
- // with the border of the combobox.
- menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
- menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
- }
+ // Inset the menu's requested position so the border of the menu lines up
+ // with the border of the combobox.
+ menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
+ menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
+
lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight));
View::ConvertPointToScreen(this, &menu_position);
gfx::Rect bounds(menu_position, lb.size());
- Button::ButtonState original_state = Button::STATE_NORMAL;
- if (arrow_button_) {
- original_state = arrow_button_->state();
- arrow_button_->SetState(Button::STATE_PRESSED);
- }
- MenuAnchorPosition anchor_position =
- style_ == STYLE_ACTION ? MENU_ANCHOR_TOPRIGHT : MENU_ANCHOR_TOPLEFT;
+ Button::ButtonState original_state = arrow_button_->state();
+ arrow_button_->SetState(Button::STATE_PRESSED);
// Allow |menu_runner_| to be set by the testing API, but if this method is
// ever invoked recursively, ensure the old menu is closed.
@@ -959,14 +637,13 @@ void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
base::Bind(&Combobox::OnMenuClosed,
base::Unretained(this), original_state)));
}
- menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, anchor_position,
+ menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, MENU_ANCHOR_TOPLEFT,
source_type);
}
void Combobox::OnMenuClosed(Button::ButtonState original_button_state) {
menu_runner_.reset();
- if (arrow_button_)
- arrow_button_->SetState(original_button_state);
+ arrow_button_->SetState(original_button_state);
closed_time_ = base::Time::Now();
}
@@ -974,13 +651,10 @@ void Combobox::OnPerformAction() {
NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
SchedulePaint();
- // This combobox may be deleted by the listener.
- base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr();
if (listener_)
listener_->OnPerformAction(this);
- if (weak_ptr && style_ == STYLE_ACTION)
- selected_index_ = 0;
+ // Note |this| may be deleted by |listener_|.
}
gfx::Size Combobox::ArrowSize() const {
@@ -1011,10 +685,7 @@ PrefixSelector* Combobox::GetPrefixSelector() {
int Combobox::GetArrowContainerWidth() const {
constexpr int kPaddingWidth = 8;
- int padding = style_ == STYLE_NORMAL
- ? kPaddingWidth * 2
- : kActionLeftPadding + kActionRightPadding;
- return ArrowSize().width() + padding;
+ return ArrowSize().width() + kPaddingWidth * 2;
}
} // namespace views
diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h
index d6132543edd..9f86b4619e5 100644
--- a/chromium/ui/views/controls/combobox/combobox.h
+++ b/chromium/ui/views/controls/combobox/combobox.h
@@ -6,12 +6,9 @@
#define UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_H_
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
-#include "ui/base/models/combobox_model.h"
#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/prefix_delegate.h"
namespace gfx {
@@ -19,6 +16,7 @@ class FontList;
}
namespace ui {
+class ComboboxModel;
class MenuModel;
}
@@ -28,40 +26,23 @@ class ComboboxTestApi;
}
class ComboboxListener;
-class Button;
+class FocusRing;
class MenuRunner;
-class Painter;
class PrefixSelector;
// A non-editable combobox (aka a drop-down list or selector).
-// Combobox has two distinct parts, the drop down arrow and the text. Combobox
-// offers two distinct behaviors:
-// * STYLE_NORMAL: typical combobox, clicking on the text and/or button shows
-// the drop down, arrow keys change selection or show the menu depending on
-// the platform, selected index can be changed by the user to something other
-// than the first item.
-// * STYLE_ACTION: clicking on the text notifies the listener. The menu can be
-// shown only by clicking on the arrow, except on Mac where it can be shown
-// through the keyboard. The selected index is always reverted to 0 after the
-// listener is notified.
+// Combobox has two distinct parts, the drop down arrow and the text.
class VIEWS_EXPORT Combobox : public View,
public PrefixDelegate,
public ButtonListener {
public:
- // The style of the combobox.
- enum Style {
- STYLE_NORMAL,
- STYLE_ACTION,
- };
-
// The combobox's class name.
static const char kViewClassName[];
// |model| is owned by the combobox when using this constructor.
- explicit Combobox(std::unique_ptr<ui::ComboboxModel> model,
- Style style = STYLE_NORMAL);
+ explicit Combobox(std::unique_ptr<ui::ComboboxModel> model);
// |model| is not owned by the combobox when using this constructor.
- explicit Combobox(ui::ComboboxModel* model, Style style = STYLE_NORMAL);
+ explicit Combobox(ui::ComboboxModel* model);
~Combobox() override;
static const gfx::FontList& GetFontList();
@@ -99,7 +80,6 @@ class VIEWS_EXPORT Combobox : public View,
const char* GetClassName() const override;
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) override;
bool OnKeyPressed(const ui::KeyEvent& e) override;
- bool OnKeyReleased(const ui::KeyEvent& e) override;
void OnPaint(gfx::Canvas* canvas) override;
void OnFocus() override;
void OnBlur() override;
@@ -136,9 +116,6 @@ class VIEWS_EXPORT Combobox : public View,
// Draws the selected value of the drop down list
void PaintText(gfx::Canvas* canvas);
- // Draws the button images.
- void PaintButtons(gfx::Canvas* canvas);
-
// Show the drop down list
void ShowDropDownMenu(ui::MenuSourceType source_type);
@@ -148,14 +125,10 @@ class VIEWS_EXPORT Combobox : public View,
// Called when the selection is changed by the user.
void OnPerformAction();
- int GetDisclosureArrowLeftPadding() const;
- int GetDisclosureArrowRightPadding() const;
-
// Returns the size of the disclosure arrow.
gfx::Size ArrowSize() const;
- // Finds the size of the largest menu label or, for STYLE_ACTION, the size of
- // the selected label.
+ // Finds the size of the largest menu label.
gfx::Size GetContentSize() const;
// Handles the clicking event.
@@ -176,9 +149,6 @@ class VIEWS_EXPORT Combobox : public View,
// Reference to our model, which may be owned or not.
ui::ComboboxModel* model_;
- // The visual style of this combobox.
- const Style style_;
-
// Our listener. Not owned. Notified when the selected index change.
ComboboxListener* listener_;
@@ -208,29 +178,15 @@ class VIEWS_EXPORT Combobox : public View,
// The maximum dimensions of the content in the dropdown.
gfx::Size content_size_;
- // The painters or images that are used when |style_| is STYLE_BUTTONS. The
- // first index means the state of unfocused or focused.
- // The images are owned by ResourceBundle.
- std::unique_ptr<Painter> body_button_painters_[2][Button::STATE_COUNT];
- std::vector<const gfx::ImageSkia*>
- menu_button_images_[2][Button::STATE_COUNT];
-
- // The transparent buttons to handle events and render buttons. These are
- // placed on top of this combobox as child views, accept event and manage the
- // button states. These are not rendered but when |style_| is
- // STYLE_NOTIFY_ON_CLICK, a Combobox renders the button images according to
- // these button states.
- // The base View takes the ownerships of these as child views.
- Button* text_button_;
+ // A transparent button that handles events and holds button state. Placed on
+ // top of the combobox as a child view. Doesn't paint itself, but serves as a
+ // host for inkdrops.
Button* arrow_button_;
// Set while the dropdown is showing. Ensures the menu is closed if |this| is
// destroyed.
std::unique_ptr<MenuRunner> menu_runner_;
- // The image to be drawn for this combobox's arrow.
- gfx::ImageSkia arrow_image_;
-
// When true, the size of contents is defined by the selected label.
// Otherwise, it's defined by the widest label in the menu. If this is set to
// true, the parent view must relayout in ChildPreferredSizeChanged().
@@ -239,9 +195,6 @@ class VIEWS_EXPORT Combobox : public View,
// The focus ring for this Combobox.
std::unique_ptr<FocusRing> focus_ring_;
- // Used for making calbacks.
- base::WeakPtrFactory<Combobox> weak_ptr_factory_;
-
DISALLOW_COPY_AND_ASSIGN(Combobox);
};
diff --git a/chromium/ui/views/controls/combobox/combobox_listener.h b/chromium/ui/views/controls/combobox/combobox_listener.h
index 2522e03c7d8..71442cd1c4e 100644
--- a/chromium/ui/views/controls/combobox/combobox_listener.h
+++ b/chromium/ui/views/controls/combobox/combobox_listener.h
@@ -16,12 +16,11 @@ class Combobox;
class VIEWS_EXPORT ComboboxListener {
public:
// Invoked when the user does the appropriate gesture that some action should
- // be performed. For both STYLE_NORMAL and STYLE_ACTION this is invoked if the
- // user clicks on the menu button and then clicks an item. For STYLE_NORMAL
- // this is also invoked when the menu is not showing and the does a gesture to
- // change the selection (for example, presses the home or end keys). This is
- // not invoked when the menu is shown and the user changes the selection
- // without closing the menu.
+ // be performed. This is invoked if the user clicks on the menu button and
+ // then clicks an item, and also when the menu is not showing and the does a
+ // gesture to change the selection (for example, presses the home or end
+ // keys). This is not invoked when the menu is shown and the user changes the
+ // selection without closing the menu.
virtual void OnPerformAction(Combobox* combobox) = 0;
protected:
diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc
index 5c32debbaf9..f1c486f26d1 100644
--- a/chromium/ui/views/controls/combobox/combobox_unittest.cc
+++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc
@@ -25,6 +25,7 @@
#include "ui/views/test/combobox_test_api.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
using base::ASCIIToUTF16;
@@ -38,8 +39,8 @@ namespace {
// OnKeyReleased() methods.
class TestCombobox : public Combobox {
public:
- TestCombobox(ui::ComboboxModel* model, Combobox::Style style)
- : Combobox(model, style), key_handled_(false), key_received_(false) {}
+ explicit TestCombobox(ui::ComboboxModel* model)
+ : Combobox(model), key_handled_(false), key_received_(false) {}
bool OnKeyPressed(const ui::KeyEvent& e) override {
key_received_ = true;
@@ -196,14 +197,14 @@ class ComboboxTest : public ViewsTestBase {
ViewsTestBase::TearDown();
}
- void InitCombobox(const std::set<int>* separators, Combobox::Style style) {
+ void InitCombobox(const std::set<int>* separators) {
model_.reset(new TestComboboxModel());
if (separators)
model_->SetSeparators(*separators);
ASSERT_FALSE(combobox_);
- combobox_ = new TestCombobox(model_.get(), style);
+ combobox_ = new TestCombobox(model_.get());
test_api_.reset(new ComboboxTestApi(combobox_));
test_api_->InstallTestMenuRunner(&menu_show_count_);
combobox_->set_id(1);
@@ -222,7 +223,7 @@ class ComboboxTest : public ViewsTestBase {
combobox_->SizeToPreferredSize();
event_generator_ =
- std::make_unique<ui::test::EventGenerator>(widget_->GetNativeWindow());
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW);
}
@@ -282,7 +283,7 @@ class ComboboxTest : public ViewsTestBase {
// Tests whether the various Mac specific keyboard shortcuts invoke the dropdown
// menu or not.
TEST_F(ComboboxTest, KeyTestMac) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
PressKey(ui::VKEY_END);
EXPECT_EQ(0, combobox_->selected_index());
EXPECT_EQ(1, menu_show_count_);
@@ -331,7 +332,7 @@ TEST_F(ComboboxTest, DisabilityTest) {
model_.reset(new TestComboboxModel());
ASSERT_FALSE(combobox_);
- combobox_ = new TestCombobox(model_.get(), Combobox::STYLE_NORMAL);
+ combobox_ = new TestCombobox(model_.get());
combobox_->SetEnabled(false);
widget_ = new Widget;
@@ -352,7 +353,7 @@ TEST_F(ComboboxTest, DisabilityTest) {
// Tests the behavior of various keyboard shortcuts on the currently selected
// index.
TEST_F(ComboboxTest, KeyTest) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
PressKey(ui::VKEY_END);
EXPECT_EQ(model_->GetItemCount(), combobox_->selected_index() + 1);
PressKey(ui::VKEY_HOME);
@@ -377,7 +378,7 @@ TEST_F(ComboboxTest, KeyTest) {
TEST_F(ComboboxTest, SkipSeparatorSimple) {
std::set<int> separators;
separators.insert(2);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
EXPECT_EQ(0, combobox_->selected_index());
PressKey(ui::VKEY_DOWN);
EXPECT_EQ(1, combobox_->selected_index());
@@ -398,7 +399,7 @@ TEST_F(ComboboxTest, SkipSeparatorSimple) {
TEST_F(ComboboxTest, SkipSeparatorBeginning) {
std::set<int> separators;
separators.insert(0);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
EXPECT_EQ(1, combobox_->selected_index());
PressKey(ui::VKEY_DOWN);
EXPECT_EQ(2, combobox_->selected_index());
@@ -419,7 +420,7 @@ TEST_F(ComboboxTest, SkipSeparatorBeginning) {
TEST_F(ComboboxTest, SkipSeparatorEnd) {
std::set<int> separators;
separators.insert(TestComboboxModel::kItemCount - 1);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
combobox_->SetSelectedIndex(8);
PressKey(ui::VKEY_DOWN);
EXPECT_EQ(8, combobox_->selected_index());
@@ -437,7 +438,7 @@ TEST_F(ComboboxTest, SkipMultipleSeparatorsAtBeginning) {
separators.insert(0);
separators.insert(1);
separators.insert(2);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
EXPECT_EQ(3, combobox_->selected_index());
PressKey(ui::VKEY_DOWN);
EXPECT_EQ(4, combobox_->selected_index());
@@ -461,7 +462,7 @@ TEST_F(ComboboxTest, SkipMultipleAdjacentSeparatorsAtMiddle) {
separators.insert(4);
separators.insert(5);
separators.insert(6);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
combobox_->SetSelectedIndex(3);
PressKey(ui::VKEY_DOWN);
EXPECT_EQ(7, combobox_->selected_index());
@@ -477,7 +478,7 @@ TEST_F(ComboboxTest, SkipMultipleSeparatorsAtEnd) {
separators.insert(7);
separators.insert(8);
separators.insert(9);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
combobox_->SetSelectedIndex(6);
PressKey(ui::VKEY_DOWN);
EXPECT_EQ(6, combobox_->selected_index());
@@ -499,7 +500,7 @@ TEST_F(ComboboxTest, GetTextForRowTest) {
separators.insert(0);
separators.insert(1);
separators.insert(9);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
for (int i = 0; i < combobox_->GetRowCount(); ++i) {
if (separators.count(i) != 0) {
EXPECT_TRUE(combobox_->GetTextForRow(i).empty()) << i;
@@ -512,7 +513,7 @@ TEST_F(ComboboxTest, GetTextForRowTest) {
// Verifies selecting the first matching value (and returning whether found).
TEST_F(ComboboxTest, SelectValue) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
ASSERT_EQ(model_->GetDefaultIndex(), combobox_->selected_index());
EXPECT_TRUE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
EXPECT_EQ(0, combobox_->selected_index());
@@ -522,50 +523,19 @@ TEST_F(ComboboxTest, SelectValue) {
EXPECT_EQ(1, combobox_->selected_index());
}
-TEST_F(ComboboxTest, SelectValueActionStyle) {
- // With the action style, the selected index is always 0.
- InitCombobox(nullptr, Combobox::STYLE_ACTION);
- EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("PEANUT BUTTER")));
- EXPECT_EQ(0, combobox_->selected_index());
- EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("JELLY")));
- EXPECT_EQ(0, combobox_->selected_index());
- EXPECT_FALSE(combobox_->SelectValue(ASCIIToUTF16("BANANAS")));
- EXPECT_EQ(0, combobox_->selected_index());
-}
-
-TEST_F(ComboboxTest, SelectIndexActionStyle) {
- InitCombobox(nullptr, Combobox::STYLE_ACTION);
-
- // With the action style, the selected index is always 0.
- combobox_->SetSelectedIndex(1);
- EXPECT_EQ(0, combobox_->selected_index());
- combobox_->SetSelectedIndex(2);
- EXPECT_EQ(0, combobox_->selected_index());
- combobox_->SetSelectedIndex(3);
- EXPECT_EQ(0, combobox_->selected_index());
-}
-
TEST_F(ComboboxTest, ListenerHandlesDelete) {
TestComboboxModel model;
// |combobox| will be deleted on change.
- TestCombobox* combobox = new TestCombobox(&model, Combobox::STYLE_NORMAL);
+ TestCombobox* combobox = new TestCombobox(&model);
std::unique_ptr<EvilListener> evil_listener(new EvilListener());
combobox->set_listener(evil_listener.get());
ASSERT_NO_FATAL_FAILURE(ComboboxTestApi(combobox).PerformActionAt(2));
EXPECT_TRUE(evil_listener->deleted());
-
- // With STYLE_ACTION
- // |combobox| will be deleted on change.
- combobox = new TestCombobox(&model, Combobox::STYLE_ACTION);
- evil_listener.reset(new EvilListener());
- combobox->set_listener(evil_listener.get());
- ASSERT_NO_FATAL_FAILURE(ComboboxTestApi(combobox).PerformActionAt(2));
- EXPECT_TRUE(evil_listener->deleted());
}
TEST_F(ComboboxTest, Click) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
TestComboboxListener listener;
combobox_->set_listener(&listener);
@@ -580,7 +550,7 @@ TEST_F(ComboboxTest, Click) {
}
TEST_F(ComboboxTest, ClickButDisabled) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
TestComboboxListener listener;
combobox_->set_listener(&listener);
@@ -596,44 +566,25 @@ TEST_F(ComboboxTest, ClickButDisabled) {
}
TEST_F(ComboboxTest, NotifyOnClickWithReturnKey) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
TestComboboxListener listener;
combobox_->set_listener(&listener);
- // With STYLE_NORMAL, the click event is ignored. Instead the menu is shown.
+ // The click event is ignored. Instead the menu is shown.
PressKey(ui::VKEY_RETURN);
EXPECT_EQ(PlatformStyle::kReturnClicksFocusedControl ? 1 : 0,
menu_show_count_);
EXPECT_FALSE(listener.on_perform_action_called());
}
-TEST_F(ComboboxTest, NotifyOnClickWithReturnKeyActionStyle) {
- InitCombobox(nullptr, Combobox::STYLE_ACTION);
-
- TestComboboxListener listener;
- combobox_->set_listener(&listener);
-
- // With STYLE_ACTION, the click event is notified and the menu is not shown.
- PressKey(ui::VKEY_RETURN);
- EXPECT_EQ(0, menu_show_count_);
-
- if (PlatformStyle::kReturnClicksFocusedControl) {
- EXPECT_TRUE(listener.on_perform_action_called());
- EXPECT_EQ(0, listener.perform_action_index());
- } else {
- EXPECT_FALSE(listener.on_perform_action_called());
- EXPECT_EQ(-1, listener.perform_action_index());
- }
-}
-
TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
TestComboboxListener listener;
combobox_->set_listener(&listener);
- // With STYLE_NORMAL, the click event is ignored. Instead the menu is shwon.
+ // The click event is ignored. Instead the menu is shwon.
PressKey(ui::VKEY_SPACE);
EXPECT_EQ(1, menu_show_count_);
EXPECT_FALSE(listener.on_perform_action_called());
@@ -645,7 +596,7 @@ TEST_F(ComboboxTest, NotifyOnClickWithSpaceKey) {
// Test that accessibility action events show the combobox dropdown.
TEST_F(ComboboxTest, ShowViaAccessibleAction) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
ui::AXActionData data;
data.action = ax::mojom::Action::kDoDefault;
@@ -673,37 +624,8 @@ TEST_F(ComboboxTest, ShowViaAccessibleAction) {
EXPECT_EQ(1, menu_show_count_); // No change.
}
-TEST_F(ComboboxTest, NotifyOnClickWithSpaceKeyActionStyle) {
- InitCombobox(nullptr, Combobox::STYLE_ACTION);
-
- TestComboboxListener listener;
- combobox_->set_listener(&listener);
-
- // With STYLE_ACTION, the click event is notified after releasing and the menu
- // is not shown. On Mac, the menu should be shown.
- PressKey(ui::VKEY_SPACE);
-#if defined(OS_MACOSX)
- EXPECT_EQ(1, menu_show_count_);
-#else
- EXPECT_EQ(0, menu_show_count_);
-#endif
- EXPECT_FALSE(listener.on_perform_action_called());
- EXPECT_EQ(-1, listener.perform_action_index());
-
- ReleaseKey(ui::VKEY_SPACE);
-#if defined(OS_MACOSX)
- EXPECT_EQ(1, menu_show_count_);
- EXPECT_FALSE(listener.on_perform_action_called());
- EXPECT_EQ(-1, listener.perform_action_index());
-#else
- EXPECT_EQ(0, menu_show_count_);
- EXPECT_TRUE(listener.on_perform_action_called());
- EXPECT_EQ(0, listener.perform_action_index());
-#endif
-}
-
TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
- InitCombobox(nullptr, Combobox::STYLE_ACTION);
+ InitCombobox(nullptr);
TestComboboxListener listener;
combobox_->set_listener(&listener);
@@ -735,12 +657,13 @@ TEST_F(ComboboxTest, NotifyOnClickWithMouse) {
PerformMousePress(left_point);
PerformMouseRelease(left_point);
- EXPECT_EQ(1, menu_show_count_); // Unchanged.
- EXPECT_EQ(0, listener.perform_action_index());
+ // Both the text and the arrow may toggle the menu.
+ EXPECT_EQ(2, menu_show_count_);
+ EXPECT_EQ(-1, listener.perform_action_index()); // Nothing selected.
}
TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
EXPECT_TRUE(combobox_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, ui::EF_NONE)));
@@ -756,33 +679,11 @@ TEST_F(ComboboxTest, ConsumingPressKeyEvents) {
}
}
-TEST_F(ComboboxTest, ConsumingKeyPressEventsActionStyle) {
- // When the combobox's style is STYLE_ACTION, pressing events of a space key
- // or an enter key will be consumed and the menu is not shown. However, on
- // Mac, space will show the menu.
- InitCombobox(nullptr, Combobox::STYLE_ACTION);
-
- EXPECT_EQ(PlatformStyle::kReturnClicksFocusedControl,
- combobox_->OnKeyPressed(ui::KeyEvent(
- ui::ET_KEY_PRESSED, ui::VKEY_RETURN, ui::EF_NONE)));
- EXPECT_EQ(0, menu_show_count_);
-
- EXPECT_TRUE(combobox_->OnKeyPressed(
- ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, ui::EF_NONE)));
-#if defined(OS_MACOSX)
- EXPECT_EQ(1, menu_show_count_);
-#else
- EXPECT_EQ(0, menu_show_count_);
-#endif
-}
-
TEST_F(ComboboxTest, ContentWidth) {
std::vector<std::string> values;
VectorComboboxModel model(&values);
- TestCombobox combobox(&model, Combobox::STYLE_NORMAL);
- TestCombobox action_combobox(&model, Combobox::STYLE_ACTION);
+ TestCombobox combobox(&model);
ComboboxTestApi test_api(&combobox);
- ComboboxTestApi action_test_api(&action_combobox);
std::string long_item = "this is the long item";
std::string short_item = "s";
@@ -790,13 +691,11 @@ TEST_F(ComboboxTest, ContentWidth) {
values.resize(1);
values[0] = long_item;
combobox.ModelChanged();
- action_combobox.ModelChanged();
const int long_item_width = test_api.content_size().width();
values[0] = short_item;
combobox.ModelChanged();
- action_combobox.ModelChanged();
const int short_item_width = test_api.content_size().width();
@@ -804,20 +703,16 @@ TEST_F(ComboboxTest, ContentWidth) {
values[0] = short_item;
values[1] = long_item;
combobox.ModelChanged();
- action_combobox.ModelChanged();
- // When the style is STYLE_NORMAL, the width will fit with the longest item.
+ // The width will fit with the longest item.
EXPECT_EQ(long_item_width, test_api.content_size().width());
-
- // When the style is STYLE_ACTION, the width will fit with the selected item's
- // width.
- EXPECT_EQ(short_item_width, action_test_api.content_size().width());
+ EXPECT_LT(short_item_width, test_api.content_size().width());
}
// Test that model updates preserve the selected index, so long as it is in
// range.
TEST_F(ComboboxTest, ModelChanged) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
EXPECT_EQ(0, combobox_->GetSelectedRow());
EXPECT_EQ(10, combobox_->GetRowCount());
@@ -859,7 +754,7 @@ TEST_F(ComboboxTest, ModelChanged) {
}
TEST_F(ComboboxTest, TypingPrefixNotifiesListener) {
- InitCombobox(nullptr, Combobox::STYLE_NORMAL);
+ InitCombobox(nullptr);
TestComboboxListener listener;
combobox_->set_listener(&listener);
@@ -902,7 +797,7 @@ TEST_F(ComboboxTest, MenuModel) {
const int kSeparatorIndex = 3;
std::set<int> separators;
separators.insert(kSeparatorIndex);
- InitCombobox(&separators, Combobox::STYLE_NORMAL);
+ InitCombobox(&separators);
ui::MenuModel* menu_model = test_api_->menu_model();
@@ -931,26 +826,4 @@ TEST_F(ComboboxTest, MenuModel) {
EXPECT_TRUE(menu_model->IsVisibleAt(0));
}
-// Check that with STYLE_ACTION, the first item (only) is not shown.
-TEST_F(ComboboxTest, MenuModelActionStyleMac) {
- const int kSeparatorIndex = 3;
- std::set<int> separators;
- separators.insert(kSeparatorIndex);
- InitCombobox(&separators, Combobox::STYLE_ACTION);
-
- ui::MenuModel* menu_model = test_api_->menu_model();
-
- EXPECT_EQ(TestComboboxModel::kItemCount, menu_model->GetItemCount());
- EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR,
- menu_model->GetTypeAt(kSeparatorIndex));
-
- EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu_model->GetTypeAt(0));
- EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu_model->GetTypeAt(1));
-
- EXPECT_EQ(ASCIIToUTF16("PEANUT BUTTER"), menu_model->GetLabelAt(0));
- EXPECT_EQ(ASCIIToUTF16("JELLY"), menu_model->GetLabelAt(1));
- EXPECT_FALSE(menu_model->IsVisibleAt(0));
- EXPECT_TRUE(menu_model->IsVisibleAt(1));
-}
-
} // namespace views
diff --git a/chromium/ui/views/controls/focus_ring.cc b/chromium/ui/views/controls/focus_ring.cc
index bc9597596ce..f5fbb33ec88 100644
--- a/chromium/ui/views/controls/focus_ring.cc
+++ b/chromium/ui/views/controls/focus_ring.cc
@@ -81,7 +81,7 @@ void FocusRing::OnPaint(gfx::Canvas* canvas) {
SkPath path = path_;
if (path.isEmpty()) {
- gfx::Path* highlight_path = parent()->GetProperty(kHighlightPathKey);
+ SkPath* highlight_path = parent()->GetProperty(kHighlightPathKey);
if (highlight_path)
path = *highlight_path;
}
diff --git a/chromium/ui/views/controls/image_view_base.cc b/chromium/ui/views/controls/image_view_base.cc
index d898798239f..9c15144910c 100644
--- a/chromium/ui/views/controls/image_view_base.cc
+++ b/chromium/ui/views/controls/image_view_base.cc
@@ -32,7 +32,7 @@ void ImageViewBase::ResetImageSize() {
void ImageViewBase::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kImage;
- node_data->SetName(accessible_name_);
+ node_data->SetName(GetAccessibleName());
}
void ImageViewBase::SetHorizontalAlignment(Alignment alignment) {
@@ -63,19 +63,8 @@ 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_;
+const base::string16& ImageViewBase::GetAccessibleName() const {
+ return accessible_name_.empty() ? tooltip_text_ : accessible_name_;
}
bool ImageViewBase::GetTooltipText(const gfx::Point& p,
@@ -83,7 +72,7 @@ bool ImageViewBase::GetTooltipText(const gfx::Point& p,
if (tooltip_text_.empty())
return false;
- *tooltip = GetTooltipText();
+ *tooltip = tooltip_text();
return true;
}
diff --git a/chromium/ui/views/controls/image_view_base.h b/chromium/ui/views/controls/image_view_base.h
index 4764f2f4c47..8046584de4a 100644
--- a/chromium/ui/views/controls/image_view_base.h
+++ b/chromium/ui/views/controls/image_view_base.h
@@ -40,12 +40,14 @@ class VIEWS_EXPORT ImageViewBase : public View {
Alignment GetVerticalAlignment() const;
// Set / Get the tooltip text.
- void SetTooltipText(const base::string16& tooltip);
- base::string16 GetTooltipText() const;
+ void set_tooltip_text(const base::string16& tooltip) {
+ tooltip_text_ = tooltip;
+ }
+ const base::string16& tooltip_text() const { return tooltip_text_; }
// Set / Get the accessible name text.
void SetAccessibleName(const base::string16& name);
- base::string16 GetAccessibleName() const;
+ const base::string16& GetAccessibleName() const;
// Overridden from View:
void OnPaint(gfx::Canvas* canvas) override = 0;
diff --git a/chromium/ui/views/controls/label_unittest.cc b/chromium/ui/views/controls/label_unittest.cc
index 1ee2b444c42..aec4a0a0d3d 100644
--- a/chromium/ui/views/controls/label_unittest.cc
+++ b/chromium/ui/views/controls/label_unittest.cc
@@ -27,6 +27,7 @@
#include "ui/views/test/focus_manager_test.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
using base::ASCIIToUTF16;
using base::WideToUTF16;
@@ -164,7 +165,7 @@ class LabelSelectionTest : public LabelTest {
void SetUp() override {
LabelTest::SetUp();
event_generator_ =
- std::make_unique<ui::test::EventGenerator>(widget()->GetNativeWindow());
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget()));
}
protected:
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 32127db42d9..fabb1a34680 100644
--- a/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_closure_animation_mac.mm
@@ -86,7 +86,7 @@ void MenuClosureAnimationMac::DisableAnimationsForTesting() {
void MenuClosureAnimationMac::AnimationProgressed(
const gfx::Animation* animation) {
- NSWindow* window = menu_->GetWidget()->GetNativeWindow();
+ NSWindow* window = menu_->GetWidget()->GetNativeWindow().GetNativeNSWindow();
[window setAlphaValue:animation->CurrentValueBetween(1.0, 0.0)];
}
diff --git a/chromium/ui/views/controls/menu/menu_controller.cc b/chromium/ui/views/controls/menu/menu_controller.cc
index 9e56ca54813..237a19181f2 100644
--- a/chromium/ui/views/controls/menu/menu_controller.cc
+++ b/chromium/ui/views/controls/menu/menu_controller.cc
@@ -480,8 +480,8 @@ void MenuController::Run(Widget* parent,
SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
if (button) {
- pressed_lock_ = std::make_unique<MenuButton::PressedLock>(
- button, false, ui::LocatedEvent::FromIfValid(event));
+ pressed_lock_ = button->menu_button_event_handler()->TakeLock(
+ false, ui::LocatedEvent::FromIfValid(event));
}
if (for_drop_) {
@@ -1118,7 +1118,23 @@ ui::PostDispatchAction MenuController::OnWillDispatchKeyEvent(
if (event->type() == ui::ET_KEY_PRESSED) {
base::WeakPtr<MenuController> this_ref = AsWeakPtr();
+#if defined(OS_MACOSX)
+ // Special handling for Option-Up and Option-Down, which should behave like
+ // Home and End respectively in menus.
+ if ((event->flags() & ui::EF_ALT_DOWN)) {
+ if (event->key_code() == ui::VKEY_UP) {
+ OnKeyDown(ui::VKEY_HOME);
+ } else if (event->key_code() == ui::VKEY_DOWN) {
+ OnKeyDown(ui::VKEY_END);
+ } else {
+ OnKeyDown(event->key_code());
+ }
+ } else {
+ OnKeyDown(event->key_code());
+ }
+#else
OnKeyDown(event->key_code());
+#endif
// Key events can lead to this being deleted.
if (!this_ref)
return ui::POST_DISPATCH_NONE;
@@ -1348,6 +1364,14 @@ void MenuController::OnKeyDown(ui::KeyboardCode key_code) {
return;
switch (key_code) {
+ case ui::VKEY_HOME:
+ MoveSelectionToFirstOrLastItem(INCREMENT_SELECTION_DOWN);
+ break;
+
+ case ui::VKEY_END:
+ MoveSelectionToFirstOrLastItem(INCREMENT_SELECTION_UP);
+ break;
+
case ui::VKEY_UP:
IncrementSelection(INCREMENT_SELECTION_UP);
break;
@@ -1601,7 +1625,7 @@ bool MenuController::ShowSiblingMenu(SubmenuView* source,
// There is a sibling menu, update the button state, hide the current menu
// and show the new one.
- pressed_lock_.reset(new MenuButton::PressedLock(button, true, nullptr));
+ pressed_lock_ = button->menu_button_event_handler()->TakeLock(true, nullptr);
// Need to reset capture when we show the menu again, otherwise we aren't
// going to get any events.
@@ -2155,7 +2179,7 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
// Menu fits above anchor bounds.
menu_bounds.set_y(above_anchor);
item->set_actual_menu_position(MenuItemView::POSITION_ABOVE_BOUNDS);
- } else {
+ } else if (item->GetDelegate()->ShouldTryPositioningBesideAnchor()) {
const int left_of_anchor = anchor_bounds.x() - menu_bounds.width();
const int right_of_anchor = anchor_bounds.right();
@@ -2173,6 +2197,11 @@ gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
if (menu_bounds.x() < monitor_bounds.x())
menu_bounds.set_x(right_of_anchor);
}
+ } else {
+ // The delegate doesn't want the menu repositioned to the side, and it
+ // doesn't fit on the screen in any orientation - just clip the menu to
+ // the screen and let the scrolling arrows appear.
+ menu_bounds.Intersect(monitor_bounds);
}
}
@@ -2412,6 +2441,27 @@ void MenuController::IncrementSelection(
}
}
+void MenuController::MoveSelectionToFirstOrLastItem(
+ SelectionIncrementDirectionType direction) {
+ MenuItemView* item = pending_state_.item;
+ DCHECK(item);
+ MenuItemView* submenu = nullptr;
+
+ if (pending_state_.submenu_open && item->SubmenuIsShowing()) {
+ if (!item->GetSubmenu()->GetMenuItemCount())
+ return;
+
+ // A menu is selected and open, but none of its children are selected,
+ // select the first or last menu item that is visible and enabled.
+ submenu = item;
+ } else {
+ submenu = item->GetParentMenuItem();
+ }
+
+ MenuItemView* to_select = FindInitialSelectableMenuItem(submenu, direction);
+ SetInitialHotTrackedView(to_select, direction);
+}
+
MenuItemView* MenuController::FindInitialSelectableMenuItem(
MenuItemView* parent,
SelectionIncrementDirectionType direction) {
@@ -2788,7 +2838,7 @@ MenuItemView* MenuController::ExitTopMostMenu() {
}
#endif
- std::unique_ptr<MenuButton::PressedLock> nested_pressed_lock;
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> nested_pressed_lock;
bool nested_menu = !menu_stack_.empty();
if (nested_menu) {
DCHECK(!menu_stack_.empty());
diff --git a/chromium/ui/views/controls/menu/menu_controller.h b/chromium/ui/views/controls/menu/menu_controller.h
index 588612b1edc..94538e47b29 100644
--- a/chromium/ui/views/controls/menu/menu_controller.h
+++ b/chromium/ui/views/controls/menu/menu_controller.h
@@ -22,6 +22,7 @@
#include "ui/events/event_constants.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/views/controls/button/menu_button.h"
+#include "ui/views/controls/button/menu_button_event_handler.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
#include "ui/views/widget/widget_observer.h"
@@ -486,6 +487,10 @@ class VIEWS_EXPORT MenuController
// Selects the next or previous (depending on |direction|) menu item.
void IncrementSelection(SelectionIncrementDirectionType direction);
+ // Selects the first or last (depending on |direction|) menu item.
+ void MoveSelectionToFirstOrLastItem(
+ SelectionIncrementDirectionType direction);
+
// Returns the first (|direction| == NAVIGATE_SELECTION_DOWN) or the last
// (|direction| == INCREMENT_SELECTION_UP) selectable child menu item of
// |parent|. If there are no selectable items returns NULL.
@@ -623,7 +628,7 @@ class VIEWS_EXPORT MenuController
// Run, the current state (state_) is pushed onto menu_stack_. This allows
// MenuController to restore the state when the nested run returns.
using NestedState =
- std::pair<State, std::unique_ptr<MenuButton::PressedLock>>;
+ std::pair<State, std::unique_ptr<MenuButtonEventHandler::PressedLock>>;
std::list<NestedState> menu_stack_;
// When Run is invoked during an active Run, it may be called from a separate
@@ -677,7 +682,7 @@ class VIEWS_EXPORT MenuController
std::unique_ptr<MenuScrollTask> scroll_task_;
// The lock to keep the menu button pressed while a menu is visible.
- std::unique_ptr<MenuButton::PressedLock> pressed_lock_;
+ std::unique_ptr<MenuButtonEventHandler::PressedLock> pressed_lock_;
// ViewTracker used to store the View mouse drag events are forwarded to. See
// UpdateActiveMouseView() for details.
diff --git a/chromium/ui/views/controls/menu/menu_controller_unittest.cc b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
index ad8f6732a80..8cce8de8e18 100644
--- a/chromium/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_controller_unittest.cc
@@ -30,6 +30,7 @@
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget_utils.h"
#if defined(USE_AURA)
#include "ui/aura/client/drag_drop_client.h"
@@ -45,6 +46,10 @@
#include "ui/gfx/x/x11.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "ui/base/ui_base_features.h"
+#endif
+
namespace views {
namespace test {
@@ -324,7 +329,7 @@ class MenuControllerTest : public ViewsTestBase {
set_views_delegate(std::move(views_delegate));
ViewsTestBase::SetUp();
Init();
- ASSERT_TRUE(base::MessageLoopForUI::IsCurrent());
+ ASSERT_TRUE(base::MessageLoopCurrentForUI::IsSet());
}
void TearDown() override {
@@ -604,8 +609,8 @@ class MenuControllerTest : public ViewsTestBase {
Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
owner_->Init(params);
- event_generator_.reset(
- new ui::test::EventGenerator(owner_->GetNativeWindow()));
+ event_generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(owner()));
owner_->Show();
SetupMenuItem();
@@ -654,8 +659,7 @@ TEST_F(MenuControllerTest, EventTargeter) {
// With the aura::NullWindowTargeter instantiated and assigned we expect
// the menu to not handle the key event.
aura::ScopedWindowTargeter scoped_targeter(
- owner()->GetNativeWindow()->GetRootWindow(),
- std::make_unique<aura::NullWindowTargeter>());
+ GetRootWindow(owner()), std::make_unique<aura::NullWindowTargeter>());
PressKey(ui::VKEY_ESCAPE);
EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type());
}
@@ -672,8 +676,7 @@ TEST_F(MenuControllerTest, EventTargeter) {
// details. When the ids aren't managed correctly, we get stuck down touches.
TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
TestEventHandler test_event_handler;
- owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
- &test_event_handler);
+ GetRootWindow(owner())->AddPreTargetHandler(&test_event_handler);
std::vector<int> devices;
devices.push_back(1);
@@ -692,8 +695,7 @@ TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
EXPECT_EQ(MenuController::EXIT_ALL, menu_exit_type());
EXPECT_EQ(0, test_event_handler.outstanding_touches());
- owner()->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
- &test_event_handler);
+ GetRootWindow(owner())->RemovePreTargetHandler(&test_event_handler);
}
#endif // defined(USE_X11)
@@ -777,6 +779,66 @@ TEST_F(MenuControllerTest, InitialSelectedItem) {
ResetSelection();
}
+// Tests that opening the menu and pressing 'Home' selects the first menu item.
+TEST_F(MenuControllerTest, FirstSelectedItem) {
+ SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
+ EXPECT_EQ(1, pending_state_item()->GetCommand());
+
+ // Select the first menu item.
+ DispatchKey(ui::VKEY_HOME);
+ EXPECT_EQ(1, pending_state_item()->GetCommand());
+
+ // Fake initial root item selection and submenu showing.
+ SetPendingStateItem(menu_item());
+ EXPECT_EQ(0, pending_state_item()->GetCommand());
+
+ // Select the first menu item.
+ DispatchKey(ui::VKEY_HOME);
+ EXPECT_EQ(1, pending_state_item()->GetCommand());
+
+ // Select the last item.
+ SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(3));
+ EXPECT_EQ(4, pending_state_item()->GetCommand());
+
+ // Select the first menu item.
+ DispatchKey(ui::VKEY_HOME);
+ EXPECT_EQ(1, pending_state_item()->GetCommand());
+
+ // Clear references in menu controller to the menu item that is going away.
+ ResetSelection();
+}
+
+// Tests that opening the menu and pressing 'End' selects the last enabled menu
+// item.
+TEST_F(MenuControllerTest, LastSelectedItem) {
+ // Fake initial root item selection and submenu showing.
+ SetPendingStateItem(menu_item());
+ EXPECT_EQ(0, pending_state_item()->GetCommand());
+
+ // Select the last menu item.
+ DispatchKey(ui::VKEY_END);
+ EXPECT_EQ(4, pending_state_item()->GetCommand());
+
+ // Select the last item.
+ SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(3));
+ EXPECT_EQ(4, pending_state_item()->GetCommand());
+
+ // Select the last menu item.
+ DispatchKey(ui::VKEY_END);
+ EXPECT_EQ(4, pending_state_item()->GetCommand());
+
+ // Select the first item.
+ SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0));
+ EXPECT_EQ(1, pending_state_item()->GetCommand());
+
+ // Select the last menu item.
+ DispatchKey(ui::VKEY_END);
+ EXPECT_EQ(4, pending_state_item()->GetCommand());
+
+ // Clear references in menu controller to the menu item that is going away.
+ ResetSelection();
+}
+
// Tests that opening menu and pressing 'Down' and 'Up' iterates over enabled
// items.
TEST_F(MenuControllerTest, NextSelectedItem) {
@@ -1669,7 +1731,7 @@ TEST_F(MenuControllerTest, MouseAtMenuItemOnShow) {
// and show the menu.
gfx::Size item_size = first_item->CalculatePreferredSize();
gfx::Point location(item_size.width() / 2, item_size.height() / 2);
- owner()->GetNativeWindow()->GetRootWindow()->MoveCursorTo(location);
+ GetRootWindow(owner())->MoveCursorTo(location);
menu_controller()->Run(owner(), nullptr, menu_item.get(), gfx::Rect(),
MENU_ANCHOR_TOPLEFT, false, false);
@@ -1704,9 +1766,15 @@ TEST_F(MenuControllerTest, AsynchronousCancelEvent) {
EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type());
}
-// Tests that if a menu is ran without a widget, that MenuPreTargetHandler does
-// not cause a crash.
+// Tests that menus without parent widgets do not crash in MenuPreTargetHandler.
+// This is generally true, except on Chrome OS running with the window service.
+// In that case, a DCHECK fires to ensure menus can consume parents' key events.
TEST_F(MenuControllerTest, RunWithoutWidgetDoesntCrash) {
+#if defined(OS_CHROMEOS)
+ if (features::IsUsingWindowService())
+ return;
+#endif // OS_CHROMEOS
+
ExitMenuRun();
MenuController* controller = menu_controller();
controller->Run(nullptr, nullptr, menu_item(), gfx::Rect(),
@@ -1723,12 +1791,8 @@ TEST_F(MenuControllerTest, MenuControllerReplacedDuringDrag) {
TestDragDropClient drag_drop_client(
base::Bind(&MenuControllerTest::TestMenuControllerReplacementDuringDrag,
base::Unretained(this)));
- aura::client::SetDragDropClient(menu_item()
- ->GetSubmenu()
- ->GetWidget()
- ->GetNativeWindow()
- ->GetRootWindow(),
- &drag_drop_client);
+ aura::client::SetDragDropClient(
+ GetRootWindow(menu_item()->GetSubmenu()->GetWidget()), &drag_drop_client);
StartDrag();
}
@@ -1741,12 +1805,8 @@ TEST_F(MenuControllerTest, CancelAllDuringDrag) {
AddButtonMenuItems();
TestDragDropClient drag_drop_client(base::Bind(
&MenuControllerTest::TestCancelAllDuringDrag, base::Unretained(this)));
- aura::client::SetDragDropClient(menu_item()
- ->GetSubmenu()
- ->GetWidget()
- ->GetNativeWindow()
- ->GetRootWindow(),
- &drag_drop_client);
+ aura::client::SetDragDropClient(
+ GetRootWindow(menu_item()->GetSubmenu()->GetWidget()), &drag_drop_client);
StartDrag();
}
diff --git a/chromium/ui/views/controls/menu/menu_delegate.cc b/chromium/ui/views/controls/menu/menu_delegate.cc
index 56c3c51ca94..f8a91bcd5c7 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.cc
+++ b/chromium/ui/views/controls/menu/menu_delegate.cc
@@ -152,4 +152,8 @@ bool MenuDelegate::ShouldReserveSpaceForSubmenuIndicator() const {
return true;
}
+bool MenuDelegate::ShouldTryPositioningBesideAnchor() const {
+ return true;
+}
+
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_delegate.h b/chromium/ui/views/controls/menu/menu_delegate.h
index 706605182f9..69a8ed510b6 100644
--- a/chromium/ui/views/controls/menu/menu_delegate.h
+++ b/chromium/ui/views/controls/menu/menu_delegate.h
@@ -233,6 +233,11 @@ class VIEWS_EXPORT MenuDelegate {
// Returns true if the labels should reserve additional spacing for e.g.
// submenu indicators at the end of the line.
virtual bool ShouldReserveSpaceForSubmenuIndicator() const;
+
+ // Returns true if menus should fall back to positioning beside the anchor,
+ // rather than directly above or below it, when the menu is too tall to fit
+ // within the screen.
+ virtual bool ShouldTryPositioningBesideAnchor() const;
};
} // namespace views
diff --git a/chromium/ui/views/controls/menu/menu_host.cc b/chromium/ui/views/controls/menu/menu_host.cc
index 780a0f9c27b..91889d70bf7 100644
--- a/chromium/ui/views/controls/menu/menu_host.cc
+++ b/chromium/ui/views/controls/menu/menu_host.cc
@@ -124,7 +124,7 @@ void MenuHost::InitMenuHost(Widget* parent,
params.opacity = (bubble_border || rounded_border) ?
Widget::InitParams::TRANSLUCENT_WINDOW :
Widget::InitParams::OPAQUE_WINDOW;
- params.parent = parent ? parent->GetNativeView() : NULL;
+ params.parent = parent ? parent->GetNativeView() : gfx::kNullNativeView;
params.bounds = bounds;
// If MenuHost has no parent widget, it needs to be marked
// Activatable, so that calling Show in ShowMenuHost will
diff --git a/chromium/ui/views/controls/menu/menu_image_util.cc b/chromium/ui/views/controls/menu/menu_image_util.cc
index f5aa8df39aa..d1cc32bc757 100644
--- a/chromium/ui/views/controls/menu/menu_image_util.cc
+++ b/chromium/ui/views/controls/menu/menu_image_util.cc
@@ -4,7 +4,6 @@
#include "ui/views/controls/menu/menu_image_util.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
diff --git a/chromium/ui/views/controls/menu/menu_item_view.cc b/chromium/ui/views/controls/menu/menu_item_view.cc
index 7b17d2662ec..c26f578b8c6 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.cc
+++ b/chromium/ui/views/controls/menu/menu_item_view.cc
@@ -196,6 +196,7 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
case NORMAL:
case SEPARATOR:
case EMPTY:
+ case HIGHLIGHTED:
// No additional accessibility states currently for these menu states.
break;
}
@@ -692,6 +693,12 @@ void MenuItemView::SetForcedVisualSelection(bool selected) {
SchedulePaint();
}
+void MenuItemView::SetCornerRadius(int radius) {
+ DCHECK_EQ(GetType(), HIGHLIGHTED);
+ corner_radius_ = radius;
+ invalidate_dimensions(); // Triggers preferred size recalculation.
+}
+
MenuItemView::MenuItemView(MenuItemView* parent,
int command,
MenuItemView::Type type)
@@ -781,6 +788,7 @@ void MenuItemView::Init(MenuItemView* parent,
submenu_arrow_image_view_ = nullptr;
vertical_separator_ = nullptr;
show_mnemonics_ = false;
+ corner_radius_ = 0;
// Assign our ID, this allows SubmenuItemView to find MenuItemViews.
set_id(kMenuItemViewID);
has_icons_ = false;
@@ -925,26 +933,7 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
// Render the background. As MenuScrollViewContainer draws the background, we
// only need the background when we want it to look different, as when we're
// selected.
- ui::NativeTheme* native_theme = GetNativeTheme();
- if (render_selection) {
- gfx::Rect item_bounds(0, 0, width(), height());
- if (type_ == ACTIONABLE_SUBMENU) {
- if (submenu_area_of_actionable_submenu_selected_) {
- item_bounds = GetSubmenuAreaOfActionableSubmenu();
- } else {
- item_bounds = gfx::Rect(gfx::Size(
- width() - MenuConfig::instance().actionable_submenu_width - 1,
- height()));
- }
- }
- AdjustBoundsForRTLUI(&item_bounds);
-
- native_theme->Paint(canvas->sk_canvas(),
- ui::NativeTheme::kMenuItemBackground,
- ui::NativeTheme::kHovered,
- item_bounds,
- ui::NativeTheme::ExtraParams());
- }
+ PaintBackground(canvas, mode, render_selection);
const int top_margin = GetTopMargin();
const int bottom_margin = GetBottomMargin();
@@ -999,6 +988,48 @@ void MenuItemView::PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) {
submenu_arrow_image_view_->SetImage(GetSubmenuArrowImage(icon_color));
}
+void MenuItemView::PaintBackground(gfx::Canvas* canvas,
+ PaintButtonMode mode,
+ bool render_selection) {
+ if (GetType() == HIGHLIGHTED) {
+ // Highligted items always have a different-colored background, and ignore
+ // system theme.
+ ui::NativeTheme::ColorId color_id =
+ render_selection
+ ? ui::NativeTheme::
+ kColorId_FocusedHighlightedMenuItemBackgroundColor
+ : ui::NativeTheme::kColorId_HighlightedMenuItemBackgroundColor;
+ cc::PaintFlags flags;
+ flags.setAntiAlias(true);
+ flags.setStyle(cc::PaintFlags::kFill_Style);
+ flags.setColor(GetNativeTheme()->GetSystemColor(color_id));
+ // Draw a rounded rect that spills outside of the clipping area, so that the
+ // rounded corners only show in the bottom 2 corners. Note that
+ // |corner_radius_| should only be set when the highlighted item is at the
+ // end of the menu.
+ gfx::RectF spilling_rect(GetLocalBounds());
+ spilling_rect.set_y(spilling_rect.y() - corner_radius_);
+ spilling_rect.set_height(spilling_rect.height() + corner_radius_);
+ canvas->DrawRoundRect(spilling_rect, corner_radius_, flags);
+ } else if (render_selection) {
+ gfx::Rect item_bounds = GetLocalBounds();
+ if (type_ == ACTIONABLE_SUBMENU) {
+ if (submenu_area_of_actionable_submenu_selected_) {
+ item_bounds = GetSubmenuAreaOfActionableSubmenu();
+ } else {
+ item_bounds.set_width(item_bounds.width() -
+ MenuConfig::instance().actionable_submenu_width -
+ 1);
+ }
+ }
+ AdjustBoundsForRTLUI(&item_bounds);
+
+ GetNativeTheme()->Paint(
+ canvas->sk_canvas(), ui::NativeTheme::kMenuItemBackground,
+ ui::NativeTheme::kHovered, item_bounds, ui::NativeTheme::ExtraParams());
+ }
+}
+
void MenuItemView::PaintMinorIconAndText(
gfx::Canvas* canvas,
const MenuDelegate::LabelStyle& style) {
@@ -1059,6 +1090,9 @@ SkColor MenuItemView::GetTextColor(bool minor, bool render_selection) const {
if (GetMenuController() && GetMenuController()->use_touchable_layout())
color_id = ui::NativeTheme::kColorId_TouchableMenuItemLabelColor;
+ if (GetType() == HIGHLIGHTED)
+ color_id = ui::NativeTheme::kColorId_HighlightedMenuItemForegroundColor;
+
return GetNativeTheme()->GetSystemColor(color_id);
}
@@ -1074,23 +1108,28 @@ void MenuItemView::DestroyAllMenuHosts() {
}
int MenuItemView::GetTopMargin() const {
- if (top_margin_ >= 0)
- return top_margin_;
-
- const MenuItemView* root = GetRootMenuItem();
- return root && root->has_icons_
- ? MenuConfig::instance().item_top_margin
- : MenuConfig::instance().item_no_icon_top_margin;
+ int margin = top_margin_;
+ if (margin < 0) {
+ const MenuItemView* root = GetRootMenuItem();
+ margin = root && root->has_icons_
+ ? MenuConfig::instance().item_top_margin
+ : MenuConfig::instance().item_no_icon_top_margin;
+ }
+ return margin + corner_radius_ / 2;
}
int MenuItemView::GetBottomMargin() const {
- if (bottom_margin_ >= 0)
- return bottom_margin_;
-
- const MenuItemView* root = GetRootMenuItem();
- return root && root->has_icons_
- ? MenuConfig::instance().item_bottom_margin
- : MenuConfig::instance().item_no_icon_bottom_margin;
+ int margin = bottom_margin_;
+ if (margin < 0) {
+ const MenuItemView* root = GetRootMenuItem();
+ margin = root && root->has_icons_
+ ? MenuConfig::instance().item_bottom_margin
+ : MenuConfig::instance().item_no_icon_bottom_margin;
+ }
+ // Add half of |corner_radius_| in both GetTopMargin() and GetBottomMargin(),
+ // so that they add up to exactly |corner_radius_|. When |corner_radius_| is
+ // odd, we need to add 1 here to avoid the height being off by 1.
+ return margin + corner_radius_ / 2 + (corner_radius_ % 2);
}
gfx::Size MenuItemView::GetChildPreferredSize() const {
diff --git a/chromium/ui/views/controls/menu/menu_item_view.h b/chromium/ui/views/controls/menu/menu_item_view.h
index 160a0069256..f0e80ee12e6 100644
--- a/chromium/ui/views/controls/menu/menu_item_view.h
+++ b/chromium/ui/views/controls/menu/menu_item_view.h
@@ -91,6 +91,9 @@ class VIEWS_EXPORT MenuItemView : public View {
CHECKBOX, // Can be selected/checked to toggle a boolean state.
RADIO, // Can be selected/checked among a group of choices.
SEPARATOR, // Shows a horizontal line separator.
+ HIGHLIGHTED, // Performs an action when selected, and has a
+ // different colored background that merges with the
+ // menu's rounded corners when placed at the bottom.
EMPTY, // EMPTY is a special type for empty menus that is only used
// internally.
};
@@ -359,6 +362,11 @@ class VIEWS_EXPORT MenuItemView : public View {
// there's no way to unset it for this MenuItemView!
void SetForcedVisualSelection(bool selected);
+ // For items of type HIGHLIGHTED only: sets the radius of the item's
+ // background. This makes the menu item's background fit its container's
+ // border radius, if they are both the same value.
+ void SetCornerRadius(int radius);
+
protected:
// Creates a MenuItemView. This is used by the various AddXXX methods.
MenuItemView(MenuItemView* parent, int command, Type type);
@@ -424,6 +432,12 @@ class VIEWS_EXPORT MenuItemView : public View {
// are not rendered.
void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
+ // Helper function for PaintButton(), draws the background for the button if
+ // appropriate.
+ void PaintBackground(gfx::Canvas* canvas,
+ PaintButtonMode mode,
+ bool render_selection);
+
// Paints the right-side icon and text.
void PaintMinorIconAndText(gfx::Canvas* canvas,
const MenuDelegate::LabelStyle& style);
@@ -568,6 +582,9 @@ class VIEWS_EXPORT MenuItemView : public View {
int top_margin_;
int bottom_margin_;
+ // Corner radius in pixels, for HIGHLIGHTED items placed at the end of a menu.
+ int corner_radius_;
+
// Horizontal icon margins in pixels, which can differ between MenuItems.
// These values will be set in the layout process.
mutable int left_icon_margin_;
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter.cc b/chromium/ui/views/controls/menu/menu_model_adapter.cc
index cbccee16e4c..08132c522c1 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter.cc
@@ -83,6 +83,9 @@ MenuItemView* MenuModelAdapter::AddMenuItemFromModelAt(ui::MenuModel* model,
case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
type = MenuItemView::ACTIONABLE_SUBMENU;
break;
+ case ui::MenuModel::TYPE_HIGHLIGHTED:
+ type = MenuItemView::HIGHLIGHTED;
+ break;
}
if (*type == MenuItemView::SEPARATOR) {
diff --git a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
index 00da8e3ebcc..392f6c3ed34 100644
--- a/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_model_adapter_unittest.cc
@@ -241,6 +241,9 @@ void CheckSubmenu(const RootModel& model,
case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
EXPECT_EQ(views::MenuItemView::ACTIONABLE_SUBMENU, item->GetType());
break;
+ case ui::MenuModel::TYPE_HIGHLIGHTED:
+ EXPECT_EQ(views::MenuItemView::HIGHLIGHTED, item->GetType());
+ break;
}
// Check enabled state.
@@ -312,6 +315,9 @@ TEST_F(MenuModelAdapterTest, BasicTest) {
case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
EXPECT_EQ(views::MenuItemView::ACTIONABLE_SUBMENU, item->GetType());
break;
+ case ui::MenuModel::TYPE_HIGHLIGHTED:
+ EXPECT_EQ(views::MenuItemView::HIGHLIGHTED, item->GetType());
+ break;
}
// Check enabled state.
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 b38b0d49d53..459347bf9ee 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
@@ -25,26 +25,23 @@ MenuPreTargetHandlerAura::MenuPreTargetHandlerAura(MenuController* controller,
Widget* owner)
: controller_(controller), root_(GetOwnerRootWindow(owner)) {
if (root_) {
- root_->env()->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
+ aura_env_ = root_->env();
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);
+ // This should only happen in cases like when context menus are shown for
+ // Windows OS system tray items and there is no parent window. This should
+ // not be hit on Chrome OS, where Window Service clients need to install a
+ // pre-target handler on the aura::Env associated with their app window.
+ DCHECK(!features::IsUsingWindowService())
+ << "MenuPreTargetHandlerAura may not work correctly without an owner.";
+ aura_env_ = aura::Env::GetInstance();
}
+ aura_env_->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
}
MenuPreTargetHandlerAura::~MenuPreTargetHandlerAura() {
- if (root_)
- root_->env()->RemovePreTargetHandler(this);
- else
- aura::Env::GetInstance()->RemovePreTargetHandler(this);
+ aura_env_->RemovePreTargetHandler(this);
Cleanup();
}
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h
index 13fc79cbde2..f1e494e494f 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_aura.h
@@ -12,6 +12,7 @@
#include "ui/wm/public/activation_change_observer.h"
namespace aura {
+class Env;
class Window;
} // namespace aura
@@ -48,6 +49,7 @@ class VIEWS_EXPORT MenuPreTargetHandlerAura
private:
void Cleanup();
+ aura::Env* aura_env_ = nullptr;
MenuController* controller_;
aura::Window* root_;
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h
index d2250979d3d..76a78f7c308 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.h
@@ -5,24 +5,23 @@
#ifndef UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_MAC_H_
#define UI_VIEWS_CONTROLS_MENU_MENU_PRE_TARGET_HANDLER_MAC_H_
-#include "ui/events/event_handler.h"
#include "ui/views/controls/menu/menu_pre_target_handler.h"
-#include "ui/views/event_monitor_mac.h"
+
+#include "ui/base/cocoa/weak_ptr_nsobject.h"
namespace views {
-class MenuPreTargetHandlerMac : public MenuPreTargetHandler,
- public ui::EventHandler {
+// Stops dispatch of key events when they are handled by MenuController.
+// While similar to EventMonitorMac, that class does not allow dispatch changes.
+class MenuPreTargetHandlerMac : public MenuPreTargetHandler {
public:
MenuPreTargetHandlerMac(MenuController* controller, Widget* widget);
~MenuPreTargetHandlerMac() override;
- // ui::EventHandler:
- void OnKeyEvent(ui::KeyEvent* event) override;
-
private:
MenuController* controller_; // Weak. Owns |this|.
- std::unique_ptr<EventMonitorMac> event_monitor_;
+ id monitor_;
+ ui::WeakPtrNSObjectFactory<MenuPreTargetHandlerMac> factory_;
DISALLOW_COPY_AND_ASSIGN(MenuPreTargetHandlerMac);
};
diff --git a/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm
index 81ce0dafa79..4308b8cdf3a 100644
--- a/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm
+++ b/chromium/ui/views/controls/menu/menu_pre_target_handler_mac.mm
@@ -4,6 +4,10 @@
#include "ui/views/controls/menu/menu_pre_target_handler_mac.h"
+#import <Cocoa/Cocoa.h>
+
+#include "ui/events/event.h"
+#include "ui/events/event_utils.h"
#include "ui/views/controls/menu/menu_controller.h"
#include "ui/views/widget/widget.h"
@@ -11,17 +15,35 @@ namespace views {
MenuPreTargetHandlerMac::MenuPreTargetHandlerMac(MenuController* controller,
Widget* widget)
- : controller_(controller),
- event_monitor_(
- std::make_unique<EventMonitorMac>(this, widget->GetNativeWindow())) {}
-
-MenuPreTargetHandlerMac::~MenuPreTargetHandlerMac() {}
+ : controller_(controller), factory_(this) {
+ gfx::NativeWindow target_window = widget->GetNativeWindow();
+
+ // Capture a WeakPtr via NSObject. This allows the block to detect another
+ // event monitor for the same event deleting |this|.
+ WeakPtrNSObject* handle = factory_.handle();
+
+ auto block = ^NSEvent*(NSEvent* event) {
+ if (!ui::WeakPtrNSObjectFactory<MenuPreTargetHandlerMac>::Get(handle))
+ return event;
+
+ if (!target_window || [event window] == target_window.GetNativeNSWindow()) {
+ std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event);
+ if (ui_event && ui_event->IsKeyEvent() &&
+ controller_->OnWillDispatchKeyEvent(ui_event->AsKeyEvent()) !=
+ ui::POST_DISPATCH_PERFORM_DEFAULT) {
+ // Return nil so the event will not proceed through normal dispatch.
+ return nil;
+ }
+ }
+ return event;
+ };
+
+ monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask
+ handler:block];
+}
-void MenuPreTargetHandlerMac::OnKeyEvent(ui::KeyEvent* event) {
- if (controller_->OnWillDispatchKeyEvent(event) !=
- ui::POST_DISPATCH_PERFORM_DEFAULT) {
- event->SetHandled();
- }
+MenuPreTargetHandlerMac::~MenuPreTargetHandlerMac() {
+ [NSEvent removeMonitor:monitor_];
}
// static
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 7acfc99f907..557e7e372ce 100644
--- a/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -106,7 +106,8 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
gfx::Rect(kWindowOffset, kWindowOffset, kWindowWidth, kWindowHeight));
parent_->Show();
- native_view_subview_count_ = [[parent_->GetNativeView() subviews] count];
+ native_view_subview_count_ =
+ [[parent_->GetNativeView().GetNativeNSView() subviews] count];
base::Closure on_close = base::Bind(&MenuRunnerCocoaTest::MenuCloseCallback,
base::Unretained(this));
@@ -119,7 +120,7 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
void TearDown() override {
EXPECT_EQ(native_view_subview_count_,
- [[parent_->GetNativeView() subviews] count]);
+ [[parent_->GetNativeView().GetNativeNSView() subviews] count]);
if (runner_) {
runner_->Release();
@@ -252,12 +253,11 @@ class MenuRunnerCocoaTest : public ViewsTestBase,
}
void ComboboxRunMenuAtCallback() {
- NSArray* subviews = [parent_->GetNativeView() subviews];
+ NSArray* subviews = [parent_->GetNativeView().GetNativeNSView() subviews];
// An anchor view should only be added for Native menus.
if (GetParam() == MenuType::NATIVE) {
ASSERT_EQ(native_view_subview_count_ + 1, [subviews count]);
- last_anchor_frame_ =
- [[subviews objectAtIndex:native_view_subview_count_] frame];
+ last_anchor_frame_ = [subviews[native_view_subview_count_] frame];
} else {
EXPECT_EQ(native_view_subview_count_, [subviews count]);
}
diff --git a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index f0ea47108de..f67cdcbd9f9 100644
--- a/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/chromium/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -176,11 +176,12 @@ void MenuRunnerImplCocoa::RunMenuAt(Widget* parent,
// Ensure the UI can update while the menu is fading out.
base::ScopedPumpMessagesInPrivateModes pump_private;
- NSWindow* window = parent->GetNativeWindow();
+ NSWindow* window = parent->GetNativeWindow().GetNativeNSWindow();
+ NSView* view = parent->GetNativeView().GetNativeNSView();
if (run_types & MenuRunner::CONTEXT_MENU) {
[NSMenu popUpContextMenu:[menu_controller_ menu]
withEvent:EventForPositioningContextMenu(bounds, window)
- forView:parent->GetNativeView()];
+ forView:view];
} else if (run_types & MenuRunner::COMBOBOX) {
NSMenuItem* checked_item = FirstCheckedItem(menu_controller_);
NSMenu* menu = [menu_controller_ menu];
diff --git a/chromium/ui/views/controls/menu/menu_runner_unittest.cc b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
index bb3961c9af0..577c4cceb03 100644
--- a/chromium/ui/views/controls/menu/menu_runner_unittest.cc
+++ b/chromium/ui/views/controls/menu/menu_runner_unittest.cc
@@ -27,6 +27,7 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
namespace {
@@ -369,7 +370,7 @@ class MenuRunnerWidgetTest : public MenuRunnerTest {
std::unique_ptr<ui::test::EventGenerator> EventGeneratorForWidget(
Widget* widget) {
return std::make_unique<ui::test::EventGenerator>(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget) : GetContext(),
widget->GetNativeWindow());
}
@@ -413,8 +414,9 @@ class MenuRunnerWidgetTest : public MenuRunnerTest {
TEST_F(MenuRunnerWidgetTest, WidgetDoesntTakeCapture) {
AddMenuLauncherEventHandler(owner());
- EXPECT_EQ(nullptr, internal::NativeWidgetPrivate::GetGlobalCapture(
- widget()->GetNativeView()));
+ EXPECT_EQ(gfx::kNullNativeView,
+ internal::NativeWidgetPrivate::GetGlobalCapture(
+ widget()->GetNativeView()));
auto generator(EventGeneratorForWidget(widget()));
// Implicit capture should not be held by |widget|.
generator->PressLeftButton();
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
index ecbd5d773b9..0ad986a75c3 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -172,9 +172,7 @@ class MenuScrollViewContainer::MenuScrollView : public View {
// MenuScrollViewContainer ----------------------------------------------------
MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
- : content_view_(content_view),
- arrow_(BubbleBorder::NONE),
- bubble_border_(NULL) {
+ : content_view_(content_view) {
scroll_up_button_ = new MenuScrollButton(content_view, true);
scroll_down_button_ = new MenuScrollButton(content_view, false);
AddChildView(scroll_up_button_);
@@ -186,10 +184,7 @@ MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
arrow_ = BubbleBorderTypeFromAnchor(
content_view_->GetMenuItem()->GetMenuController()->GetAnchorPosition());
- if (arrow_ != BubbleBorder::NONE)
- CreateBubbleBorder();
- else
- CreateDefaultBorder();
+ CreateBorder();
}
bool MenuScrollViewContainer::HasBubbleBorder() {
@@ -201,10 +196,19 @@ void MenuScrollViewContainer::SetBubbleArrowOffset(int offset) {
bubble_border_->set_arrow_offset(offset);
}
+MenuItemView* MenuScrollViewContainer::GetFootnote() const {
+ MenuItemView* footnote = content_view_->GetLastItem();
+ if (!footnote || footnote->GetType() != MenuItemView::HIGHLIGHTED)
+ return nullptr;
+ return footnote;
+}
+
gfx::Size MenuScrollViewContainer::CalculatePreferredSize() const {
gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
gfx::Insets insets = GetInsets();
prefsize.Enlarge(insets.width(), insets.height());
+ if (GetFootnote() && bubble_border_)
+ prefsize.Enlarge(0, bubble_border_->GetBorderCornerRadius());
return prefsize;
}
@@ -214,12 +218,19 @@ void MenuScrollViewContainer::Layout() {
int y = insets.top();
int width = View::width() - insets.width();
int content_height = height() - insets.height();
+ MenuItemView* footnote = GetFootnote();
if (!scroll_up_button_->visible()) {
+ if (footnote && bubble_border_)
+ footnote->SetCornerRadius(bubble_border_->GetBorderCornerRadius());
scroll_view_->SetBounds(x, y, width, content_height);
scroll_view_->Layout();
return;
}
+ // Don't round the footnote when the scroll button is visible.
+ if (footnote)
+ footnote->SetCornerRadius(0);
+
gfx::Size pref = scroll_up_button_->GetPreferredSize();
scroll_up_button_->SetBounds(x, y, width, pref.height());
content_height -= pref.height();
@@ -237,7 +248,7 @@ void MenuScrollViewContainer::Layout() {
void MenuScrollViewContainer::OnNativeThemeChanged(
const ui::NativeTheme* theme) {
- if (arrow_ == BubbleBorder::NONE)
+ if (!HasBubbleBorder())
CreateDefaultBorder();
}
@@ -270,6 +281,13 @@ void MenuScrollViewContainer::OnBoundsChanged(
Layout();
}
+void MenuScrollViewContainer::CreateBorder() {
+ if (HasBubbleBorder())
+ CreateBubbleBorder();
+ else
+ CreateDefaultBorder();
+}
+
void MenuScrollViewContainer::CreateDefaultBorder() {
DCHECK_EQ(arrow_, BubbleBorder::NONE);
bubble_border_ = nullptr;
@@ -292,6 +310,8 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
const int horizontal_inset =
menu_config.menu_horizontal_border_size + padding;
+ int bottom_inset = GetFootnote() ? 0 : vertical_inset;
+
if (use_outer_border) {
SkColor color = GetNativeTheme()
? GetNativeTheme()->GetSystemColor(
@@ -299,10 +319,11 @@ void MenuScrollViewContainer::CreateDefaultBorder() {
: gfx::kPlaceholderColor;
SetBorder(views::CreateBorderPainter(
std::make_unique<views::RoundRectPainter>(color, corner_radius),
- gfx::Insets(vertical_inset, horizontal_inset)));
+ gfx::Insets(vertical_inset, horizontal_inset, bottom_inset,
+ horizontal_inset)));
} else {
- SetBorder(CreateEmptyBorder(vertical_inset, horizontal_inset,
- vertical_inset, horizontal_inset));
+ SetBorder(CreateEmptyBorder(vertical_inset, horizontal_inset, bottom_inset,
+ horizontal_inset));
}
}
@@ -316,8 +337,10 @@ void MenuScrollViewContainer::CreateBubbleBorder() {
bubble_border_->SetCornerRadius(menu_config.touchable_corner_radius);
bubble_border_->set_md_shadow_elevation(
menu_config.touchable_menu_shadow_elevation);
- scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(
- gfx::Insets(menu_config.vertical_touchable_menu_item_padding, 0)));
+ gfx::Insets insets(menu_config.vertical_touchable_menu_item_padding, 0);
+ if (GetFootnote())
+ insets.Set(menu_config.vertical_touchable_menu_item_padding, 0, 0, 0);
+ scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(insets));
}
SetBorder(std::unique_ptr<Border>(bubble_border_));
diff --git a/chromium/ui/views/controls/menu/menu_scroll_view_container.h b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
index f08341929cb..290fe81bb33 100644
--- a/chromium/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/chromium/ui/views/controls/menu/menu_scroll_view_container.h
@@ -12,6 +12,7 @@
namespace views {
+class MenuItemView;
class SubmenuView;
// MenuScrollViewContainer contains the SubmenuView (through a MenuScrollView)
@@ -31,6 +32,8 @@ class MenuScrollViewContainer : public View {
// Offsets the Arrow from the default location.
void SetBubbleArrowOffset(int offset);
+ void SetFootnoteView(View* view);
+
// View overrides.
gfx::Size CalculatePreferredSize() const override;
void Layout() override;
@@ -43,6 +46,9 @@ class MenuScrollViewContainer : public View {
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
private:
+ // Create a default border or bubble border, as appropriate.
+ void CreateBorder();
+
// Create the default border.
void CreateDefaultBorder();
@@ -51,6 +57,9 @@ class MenuScrollViewContainer : public View {
BubbleBorder::Arrow BubbleBorderTypeFromAnchor(MenuAnchorPosition anchor);
+ // Returns the last item in the menu if it is of type HIGHLIGHTED.
+ MenuItemView* GetFootnote() const;
+
class MenuScrollView;
// The scroll buttons.
@@ -64,10 +73,10 @@ class MenuScrollViewContainer : public View {
SubmenuView* content_view_;
// If set the currently set border is a bubble border.
- BubbleBorder::Arrow arrow_;
+ BubbleBorder::Arrow arrow_ = BubbleBorder::NONE;
// Weak reference to the currently set border.
- BubbleBorder* bubble_border_;
+ BubbleBorder* bubble_border_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(MenuScrollViewContainer);
};
diff --git a/chromium/ui/views/controls/menu/submenu_view.cc b/chromium/ui/views/controls/menu/submenu_view.cc
index 36865a59316..04c38f5c364 100644
--- a/chromium/ui/views/controls/menu/submenu_view.cc
+++ b/chromium/ui/views/controls/menu/submenu_view.cc
@@ -475,6 +475,14 @@ MenuScrollViewContainer* SubmenuView::GetScrollViewContainer() {
return scroll_view_container_;
}
+MenuItemView* SubmenuView::GetLastItem() {
+ for (int i = child_count() - 1; i >= 0; i--) {
+ if (child_at(i)->id() == MenuItemView::kMenuItemViewID)
+ return static_cast<MenuItemView*>(child_at(i));
+ }
+ return nullptr;
+}
+
void SubmenuView::MenuHostDestroyed() {
host_ = NULL;
MenuController* controller = GetMenuItem()->GetMenuController();
diff --git a/chromium/ui/views/controls/menu/submenu_view.h b/chromium/ui/views/controls/menu/submenu_view.h
index 4374790035e..37056577fe9 100644
--- a/chromium/ui/views/controls/menu/submenu_view.h
+++ b/chromium/ui/views/controls/menu/submenu_view.h
@@ -147,6 +147,9 @@ class VIEWS_EXPORT SubmenuView : public View,
// Returns the container for the SubmenuView.
MenuScrollViewContainer* GetScrollViewContainer();
+ // Returns the last MenuItemView in this submenu.
+ MenuItemView* GetLastItem();
+
// Invoked if the menu is prematurely destroyed. This can happen if the window
// closes while the menu is shown. If invoked the SubmenuView must drop all
// references to the MenuHost as the MenuHost is about to be deleted.
diff --git a/chromium/ui/views/controls/menu/submenu_view_unittest.cc b/chromium/ui/views/controls/menu/submenu_view_unittest.cc
new file mode 100644
index 00000000000..9b2458799c9
--- /dev/null
+++ b/chromium/ui/views/controls/menu/submenu_view_unittest.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/controls/menu/submenu_view.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/controls/menu/submenu_view.h"
+
+namespace views {
+
+TEST(SubmenuViewTest, GetLastItem) {
+ MenuItemView* parent = new MenuItemView(nullptr);
+ MenuRunner menu_runner(parent, 0);
+
+ SubmenuView* submenu = parent->CreateSubmenu();
+ EXPECT_EQ(nullptr, submenu->GetLastItem());
+
+ submenu->AddChildView(new View());
+ EXPECT_EQ(nullptr, submenu->GetLastItem());
+
+ MenuItemView* first = new MenuItemView(nullptr);
+ submenu->AddChildView(first);
+ EXPECT_EQ(first, submenu->GetLastItem());
+
+ submenu->AddChildView(new View());
+ EXPECT_EQ(first, submenu->GetLastItem());
+
+ MenuItemView* second = new MenuItemView(nullptr);
+ submenu->AddChildView(second);
+ EXPECT_EQ(second, submenu->GetLastItem());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/controls/native/native_view_host.cc b/chromium/ui/views/controls/native/native_view_host.cc
index 5240d2bf72d..270f22b0ece 100644
--- a/chromium/ui/views/controls/native/native_view_host.cc
+++ b/chromium/ui/views/controls/native/native_view_host.cc
@@ -176,7 +176,7 @@ void NativeViewHost::ViewHierarchyChanged(
if (!native_wrapper_.get())
native_wrapper_.reset(NativeViewHostWrapper::CreateWrapper(this));
native_wrapper_->AddedToWidget();
- } else if (!details.is_add) {
+ } else if (!details.is_add && native_wrapper_) {
native_wrapper_->RemovedFromWidget();
}
}
@@ -206,6 +206,11 @@ gfx::NativeCursor NativeViewHost::GetCursor(const ui::MouseEvent& event) {
return native_wrapper_->GetCursor(event.x(), event.y());
}
+void NativeViewHost::SetVisible(bool visible) {
+ native_wrapper_->SetVisible(visible);
+ View::SetVisible(visible);
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeViewHost, private:
diff --git a/chromium/ui/views/controls/native/native_view_host.h b/chromium/ui/views/controls/native/native_view_host.h
index ec0b8e9f18a..5c47f29d258 100644
--- a/chromium/ui/views/controls/native/native_view_host.h
+++ b/chromium/ui/views/controls/native/native_view_host.h
@@ -98,6 +98,7 @@ class VIEWS_EXPORT NativeViewHost : public View {
void OnFocus() override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
+ void SetVisible(bool visible) override;
protected:
bool GetNeedsNotificationWhenVisibleBoundsChange() const override;
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 3be7f536eb1..dabae673dd7 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.cc
+++ b/chromium/ui/views/controls/native/native_view_host_aura.cc
@@ -134,8 +134,12 @@ void NativeViewHostAura::AddedToWidget() {
void NativeViewHostAura::RemovedFromWidget() {
if (host_->native_view()) {
- host_->native_view()->Hide();
+ // Clear kHostWindowKey before Hide() because it could be accessed during
+ // the call. In MUS aura, the hosting window could be destroyed at this
+ // point.
host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
+
+ host_->native_view()->Hide();
if (host_->native_view()->parent())
host_->native_view()->parent()->RemoveChild(host_->native_view());
RemoveClippingWindow();
@@ -229,6 +233,13 @@ gfx::NativeCursor NativeViewHostAura::GetCursor(int x, int y) {
return gfx::kNullCursor;
}
+void NativeViewHostAura::SetVisible(bool visible) {
+ if (!visible)
+ host_->native_view()->Hide();
+ else
+ host_->native_view()->Show();
+}
+
void NativeViewHostAura::OnWindowBoundsChanged(
aura::Window* window,
const gfx::Rect& old_bounds,
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 0adf8fb3aec..1e24714575b 100644
--- a/chromium/ui/views/controls/native/native_view_host_aura.h
+++ b/chromium/ui/views/controls/native/native_view_host_aura.h
@@ -44,6 +44,7 @@ class NativeViewHostAura : public NativeViewHostWrapper,
gfx::NativeView GetNativeViewContainer() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(int x, int y) override;
+ void SetVisible(bool visible) override;
private:
friend class NativeViewHostAuraTest;
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 f46e575e442..08a0ce36806 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.h
+++ b/chromium/ui/views/controls/native/native_view_host_mac.h
@@ -51,6 +51,7 @@ class NativeViewHostMac : public NativeViewHostWrapper,
gfx::NativeView GetNativeViewContainer() const override;
gfx::NativeViewAccessible GetNativeViewAccessible() override;
gfx::NativeCursor GetCursor(int x, int y) override;
+ void SetVisible(bool visible) override;
private:
// Return the BridgedNativeWidgetHostImpl for this hosted view.
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 d98e6e1456c..7ce36315bfa 100644
--- a/chromium/ui/views/controls/native/native_view_host_mac.mm
+++ b/chromium/ui/views/controls/native/native_view_host_mac.mm
@@ -68,7 +68,10 @@ 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;
+ // This matches content::NSViewBridgeFactoryHost::kLocalDirectHostId,
+ // indicating that this is a local window.
+ constexpr uint64_t kLocalDirectHostId = -1;
+ return kLocalDirectHostId;
}
uint64_t NativeViewHostMac::GetNSViewId() const {
@@ -111,12 +114,14 @@ void NativeViewHostMac::OnHostableViewDestroying() {
void NativeViewHostMac::AttachNativeView() {
DCHECK(host_->native_view());
DCHECK(!native_view_);
- native_view_.reset([host_->native_view() retain]);
+ native_view_.reset([host_->native_view().GetNativeNSView() retain]);
EnsureNativeViewHasNoChildWidgets(native_view_);
auto* bridge_host = GetBridgedNativeWidgetHost();
DCHECK(bridge_host);
- [bridge_host->native_widget_mac()->GetNativeView() addSubview:native_view_];
+ NSView* superview =
+ bridge_host->native_widget_mac()->GetNativeView().GetNativeNSView();
+ [superview addSubview:native_view_];
bridge_host->SetAssociationForView(host_, native_view_);
if ([native_view_ conformsToProtocol:@protocol(ViewsHostable)]) {
@@ -134,21 +139,22 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
// |native_view_| can be nil here if RemovedFromWidget() is called before
// NativeViewHost::Detach().
+ NSView* host_native_view = host_->native_view().GetNativeNSView();
if (!native_view_) {
- DCHECK(![host_->native_view() superview]);
+ DCHECK(![host_native_view superview]);
return;
}
- DCHECK(native_view_ == host_->native_view());
- [host_->native_view() setHidden:YES];
- [host_->native_view() removeFromSuperview];
+ DCHECK(native_view_ == host_native_view);
+ [native_view_ setHidden:YES];
+ [native_view_ removeFromSuperview];
if (native_view_hostable_) {
native_view_hostable_->OnViewsHostableDetached();
native_view_hostable_ = nullptr;
}
- EnsureNativeViewHasNoChildWidgets(host_->native_view());
+ EnsureNativeViewHasNoChildWidgets(native_view_);
auto* bridge_host = GetBridgedNativeWidgetHost();
// BridgedNativeWidgetImpl can be null when Widget is closing.
if (bridge_host)
@@ -195,8 +201,7 @@ void NativeViewHostMac::ShowWidget(int x,
int h,
int native_w,
int native_h) {
- if (host_->fast_resize())
- NOTIMPLEMENTED();
+ // TODO(https://crbug.com/415024): Implement host_->fast_resize().
// Coordinates will be from the top left of the parent Widget. The NativeView
// is already in the same NSWindow, so just flip to get Cooca coordinates and
@@ -210,24 +215,24 @@ void NativeViewHostMac::ShowWidget(int x,
// Convert window coordinates to the hosted view's superview, since that's how
// coordinates of the hosted view's frame is based.
NSRect container_rect =
- [[host_->native_view() superview] convertRect:window_rect fromView:nil];
- [host_->native_view() setFrame:container_rect];
- [host_->native_view() setHidden:NO];
+ [[native_view_ superview] convertRect:window_rect fromView:nil];
+ [native_view_ setFrame:container_rect];
+ [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];
+ [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_ acceptsFirstResponder])
+ [[native_view_ window] makeFirstResponder:native_view_];
if (native_view_hostable_)
native_view_hostable_->OnViewsHostableMakeFirstResponder();
@@ -256,6 +261,10 @@ gfx::NativeCursor NativeViewHostMac::GetCursor(int x, int y) {
return gfx::kNullCursor;
}
+void NativeViewHostMac::SetVisible(bool visible) {
+ [native_view_ setHidden:!visible];
+}
+
// static
NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
NativeViewHost* host) {
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 85373e5b977..3de36c65a96 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
@@ -76,7 +76,7 @@ class NativeViewHostMacTest : public test::NativeViewHostTestBase {
toplevel()->GetRootView()->AddChildView(host());
EXPECT_TRUE(native_host());
- host()->Attach(native_view_);
+ host()->Attach(native_view_.get());
}
protected:
@@ -118,7 +118,7 @@ TEST_F(NativeViewHostMacTest, Attach) {
EXPECT_FALSE([native_view_ window]);
EXPECT_NSEQ(NSZeroRect, [native_view_ frame]);
- host()->Attach(native_view_);
+ host()->Attach(native_view_.get());
EXPECT_TRUE([native_view_ superview]);
EXPECT_TRUE([native_view_ window]);
@@ -141,7 +141,7 @@ TEST_F(NativeViewHostMacTest, AccessibilityParent) {
TestViewsHostable views_hostable;
[view setViewsHostableView:&views_hostable];
- host()->Attach(view);
+ host()->Attach(view.get());
EXPECT_NSEQ(views_hostable.parent_accessibility_element(),
toplevel()->GetRootView()->GetNativeViewAccessible());
@@ -186,14 +186,14 @@ TEST_F(NativeViewHostMacTest, NativeViewHidden) {
host()->SetVisible(false);
EXPECT_FALSE([native_view_ isHidden]); // Stays visible.
- host()->Attach(native_view_);
+ host()->Attach(native_view_.get());
EXPECT_TRUE([native_view_ isHidden]); // Hidden when attached.
host()->Detach();
[native_view_ setHidden:YES];
host()->SetVisible(true);
EXPECT_TRUE([native_view_ isHidden]); // Stays hidden.
- host()->Attach(native_view_);
+ host()->Attach(native_view_.get());
EXPECT_FALSE([native_view_ isHidden]); // Made visible when attached.
EXPECT_TRUE([native_view_ superview]);
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 07cf9f1fea0..acd9b2fbd5d 100644
--- a/chromium/ui/views/controls/native/native_view_host_wrapper.h
+++ b/chromium/ui/views/controls/native/native_view_host_wrapper.h
@@ -90,6 +90,11 @@ class NativeViewHostWrapper {
// in the native view.
virtual gfx::NativeCursor GetCursor(int x, int y) = 0;
+ // Sets the visibility of the gfx::NativeView. This differs from
+ // {Show,Hide}Widget because it doesn't affect the placement, size,
+ // or clipping of the view.
+ virtual void SetVisible(bool visible) = 0;
+
// Creates a platform-specific instance of an object implementing this
// interface.
static NativeViewHostWrapper* CreateWrapper(NativeViewHost* host);
diff --git a/chromium/ui/views/controls/resize_area_unittest.cc b/chromium/ui/views/controls/resize_area_unittest.cc
index 8d11df5e8ea..f5e0db232c5 100644
--- a/chromium/ui/views/controls/resize_area_unittest.cc
+++ b/chromium/ui/views/controls/resize_area_unittest.cc
@@ -13,6 +13,7 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
namespace {
// Constants used by the ResizeAreaTest.SuccessfulGestureDrag test to simulate
@@ -130,8 +131,8 @@ void ResizeAreaTest::SetUp() {
widget_->SetContentsView(resize_area_);
widget_->Show();
- event_generator_.reset(
- new ui::test::EventGenerator(widget_->GetNativeWindow()));
+ event_generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
}
void ResizeAreaTest::TearDown() {
diff --git a/chromium/ui/views/controls/scroll_view_unittest.cc b/chromium/ui/views/controls/scroll_view_unittest.cc
index 4166c97c0bc..cb3a4c981e8 100644
--- a/chromium/ui/views/controls/scroll_view_unittest.cc
+++ b/chromium/ui/views/controls/scroll_view_unittest.cc
@@ -1025,8 +1025,9 @@ TEST_F(WidgetScrollViewTest, ScrollersOnRest) {
const float y_offset = 3;
const int kSteps = 1;
const int kNnumFingers = 2;
- generator.ScrollSequence(generator.current_location(), base::TimeDelta(), 0,
- y_offset, kSteps, kNnumFingers);
+ generator.ScrollSequence(generator.current_screen_location(),
+ base::TimeDelta(), 0, y_offset, kSteps,
+ kNnumFingers);
// Horizontal scroller should start fading out immediately.
EXPECT_EQ(kMaxOpacity, bar[HORIZONTAL]->layer()->opacity());
@@ -1044,8 +1045,9 @@ TEST_F(WidgetScrollViewTest, ScrollersOnRest) {
// Then, scrolling horizontally should show the horizontal scroller. The
// vertical scroller should still be visible, running its hide timer.
const float x_offset = 5;
- generator.ScrollSequence(generator.current_location(), base::TimeDelta(),
- x_offset, 0, kSteps, kNnumFingers);
+ generator.ScrollSequence(generator.current_screen_location(),
+ base::TimeDelta(), x_offset, 0, kSteps,
+ kNnumFingers);
for (ScrollBarOrientation orientation : {HORIZONTAL, VERTICAL}) {
EXPECT_EQ(kMaxOpacity, bar[orientation]->layer()->opacity());
EXPECT_EQ(kMaxOpacity, bar[orientation]->layer()->GetTargetOpacity());
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
index 0801c66123a..26ddd900913 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -84,8 +84,8 @@ void BaseScrollBar::ScrollByAmount(ScrollAmount amount) {
void BaseScrollBar::ScrollToThumbPosition(int thumb_position,
bool scroll_to_middle) {
- contents_scroll_offset_ =
- CalculateContentsOffset(thumb_position, scroll_to_middle);
+ contents_scroll_offset_ = CalculateContentsOffset(
+ static_cast<float>(thumb_position), scroll_to_middle);
if (contents_scroll_offset_ < GetMinPosition()) {
contents_scroll_offset_ = GetMinPosition();
} else if (contents_scroll_offset_ > GetMaxPosition()) {
@@ -460,16 +460,17 @@ int BaseScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
(contents_size_ - viewport_size_);
}
-int BaseScrollBar::CalculateContentsOffset(int thumb_position,
+int BaseScrollBar::CalculateContentsOffset(float thumb_position,
bool scroll_to_middle) const {
- int thumb_size = thumb_->GetSize();
+ float thumb_size = static_cast<float>(thumb_->GetSize());
int track_size = GetTrackSize();
if (track_size == thumb_size)
return 0;
if (scroll_to_middle)
thumb_position = thumb_position - (thumb_size / 2);
- return (thumb_position * (contents_size_ - viewport_size_)) /
- (track_size - thumb_size);
+ float result = (thumb_position * (contents_size_ - viewport_size_)) /
+ (track_size - thumb_size);
+ return static_cast<int>(result);
}
} // namespace views
diff --git a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
index 9b447add2ee..f2c0a7d5c48 100644
--- a/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
+++ b/chromium/ui/views/controls/scrollbar/base_scroll_bar.h
@@ -135,7 +135,7 @@ class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
// Calculates the current value of the contents offset (contents coordinates)
// based on the current thumb position (thumb track coordinates). See
// |ScrollToThumbPosition| for an explanation of |scroll_to_middle|.
- int CalculateContentsOffset(int thumb_position,
+ int CalculateContentsOffset(float thumb_position,
bool scroll_to_middle) const;
// Called when the state of the thumb track changes (e.g. by the user
diff --git a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
index 75196bdef82..913a1e5669b 100644
--- a/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
+++ b/chromium/ui/views/controls/scrollbar/scrollbar_unittest.cc
@@ -87,17 +87,7 @@ class ScrollBarViewsTest : public ViewsTestBase {
std::unique_ptr<TestScrollBarController> controller_;
};
-// TODO(dnicoara) Can't run the test on Windows since the scrollbar |Part|
-// isn't handled in NativeTheme.
-#if defined(OS_WIN)
-#define MAYBE_Scrolling DISABLED_Scrolling
-#define MAYBE_ScrollBarFitsToBottom DISABLED_ScrollBarFitsToBottom
-#else
-#define MAYBE_Scrolling Scrolling
-#define MAYBE_ScrollBarFitsToBottom ScrollBarFitsToBottom
-#endif
-
-TEST_F(ScrollBarViewsTest, MAYBE_Scrolling) {
+TEST_F(ScrollBarViewsTest, Scrolling) {
EXPECT_EQ(0, scrollbar_->GetPosition());
EXPECT_EQ(900, scrollbar_->GetMaxPosition());
EXPECT_EQ(0, scrollbar_->GetMinPosition());
@@ -135,7 +125,7 @@ TEST_F(ScrollBarViewsTest, MAYBE_Scrolling) {
EXPECT_EQ(0, controller_->last_position);
}
-TEST_F(ScrollBarViewsTest, MAYBE_ScrollBarFitsToBottom) {
+TEST_F(ScrollBarViewsTest, ScrollBarFitsToBottom) {
scrollbar_->Update(100, 1999, 0);
EXPECT_EQ(0, scrollbar_->GetPosition());
EXPECT_EQ(1899, scrollbar_->GetMaxPosition());
diff --git a/chromium/ui/views/controls/slider_unittest.cc b/chromium/ui/views/controls/slider_unittest.cc
index 5ce176bd113..96900ebc17d 100644
--- a/chromium/ui/views/controls/slider_unittest.cc
+++ b/chromium/ui/views/controls/slider_unittest.cc
@@ -18,12 +18,14 @@
#include "ui/events/gesture_event_details.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
+#include "ui/views/accessibility/ax_event_manager.h"
+#include "ui/views/accessibility/ax_event_observer.h"
#include "ui/views/test/slider_test_api.h"
-#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_utils.h"
namespace {
@@ -117,6 +119,28 @@ void TestSliderListener::SliderDragEnded(views::Slider* sender) {
last_drag_ended_epoch_ = ++last_event_epoch_;
}
+class TestAXEventObserver : public views::AXEventObserver {
+ public:
+ TestAXEventObserver() { views::AXEventManager::Get()->AddObserver(this); }
+
+ ~TestAXEventObserver() override {
+ views::AXEventManager::Get()->RemoveObserver(this);
+ }
+
+ bool value_changed() const { return value_changed_; }
+
+ // views::AXEventObserver:
+ void OnViewEvent(views::View* view, ax::mojom::Event event_type) override {
+ if (event_type == ax::mojom::Event::kValueChanged)
+ value_changed_ = true;
+ }
+
+ private:
+ bool value_changed_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TestAXEventObserver);
+};
+
} // namespace
namespace views {
@@ -124,22 +148,8 @@ namespace views {
// Base test fixture for Slider tests.
class SliderTest : public views::ViewsTestBase {
public:
- class SliderTestViewsDelegate : public views::TestViewsDelegate {
- public:
- bool has_value_changed() { return has_value_changed_; }
-
- private:
- void NotifyAccessibilityEvent(View* view,
- ax::mojom::Event event_type) override {
- if (event_type == ax::mojom::Event::kValueChanged)
- has_value_changed_ = true;
- }
-
- bool has_value_changed_ = false;
- };
-
- SliderTest();
- ~SliderTest() override;
+ SliderTest() = default;
+ ~SliderTest() override = default;
protected:
Slider* slider() {
@@ -168,43 +178,26 @@ class SliderTest : public views::ViewsTestBase {
return event_generator_.get();
}
- SliderTestViewsDelegate* delegate() { return delegate_; }
-
private:
// The Slider to be tested.
- Slider* slider_;
+ Slider* slider_ = nullptr;
// A simple SliderListener test double.
TestSliderListener slider_listener_;
// Stores the default locale at test setup so it can be restored
// during test teardown.
std::string default_locale_;
// The maximum x value within the bounds of the slider.
- int max_x_;
+ int max_x_ = 0;
// The maximum y value within the bounds of the slider.
- int max_y_;
+ int max_y_ = 0;
// The widget container for the slider being tested.
- views::Widget* widget_;
+ views::Widget* widget_ = nullptr;
// An event generator.
std::unique_ptr<ui::test::EventGenerator> event_generator_;
- // A TestViewsDelegate that intercepts accessibility notifications. Weak.
- SliderTestViewsDelegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(SliderTest);
};
-SliderTest::SliderTest()
- : slider_(NULL),
- default_locale_(),
- max_x_(0),
- max_y_(0),
- delegate_(new SliderTestViewsDelegate()) {
- std::unique_ptr<views::TestViewsDelegate> delegate(delegate_);
- set_views_delegate(std::move(delegate));
-}
-
-SliderTest::~SliderTest() {
-}
-
void SliderTest::SetUp() {
views::ViewsTestBase::SetUp();
@@ -225,8 +218,8 @@ void SliderTest::SetUp() {
widget_->SetContentsView(slider_);
widget_->Show();
- event_generator_.reset(
- new ui::test::EventGenerator(widget_->GetNativeWindow()));
+ event_generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
}
void SliderTest::TearDown() {
@@ -400,7 +393,8 @@ TEST_F(SliderTest, SliderListenerEventsForMultiFingerScrollGesture) {
// Verifies the correct SliderListener events are raised for an accessible
// slider.
TEST_F(SliderTest, SliderRaisesA11yEvents) {
- EXPECT_FALSE(delegate()->has_value_changed());
+ TestAXEventObserver observer;
+ EXPECT_FALSE(observer.value_changed());
// First, detach/reattach the slider without setting value.
// Temporarily detach the slider.
@@ -409,18 +403,18 @@ TEST_F(SliderTest, SliderRaisesA11yEvents) {
// Re-attachment should cause nothing to get fired.
root_view->AddChildView(slider());
- EXPECT_FALSE(delegate()->has_value_changed());
+ EXPECT_FALSE(observer.value_changed());
// Now, set value before reattaching.
root_view->RemoveChildView(slider());
// Value changes won't trigger accessibility events before re-attachment.
slider()->SetValue(22);
- EXPECT_FALSE(delegate()->has_value_changed());
+ EXPECT_FALSE(observer.value_changed());
// Re-attachment should trigger the value change.
root_view->AddChildView(slider());
- EXPECT_TRUE(delegate()->has_value_changed());
+ EXPECT_TRUE(observer.value_changed());
}
#endif // !defined(OS_MACOSX) || defined(USE_AURA)
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 96309bc1709..881e4df535d 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -157,7 +157,7 @@ Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents)
// Use leaf so that name is spoken by screen reader without exposing the
// children.
- GetViewAccessibility().OverrideIsLeaf();
+ GetViewAccessibility().OverrideIsLeaf(true);
}
Tab::~Tab() {}
diff --git a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm
index d0ae166c1cf..8f08e724af2 100644
--- a/chromium/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm
+++ b/chromium/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm
@@ -56,7 +56,8 @@ class TabbedPaneAccessibilityMacTest : public WidgetTest {
id A11yElementAtPoint(const gfx::Point& point) {
// Accessibility hit tests come in Cocoa screen coordinates.
NSPoint ns_point = gfx::ScreenPointToNSPoint(point);
- return [widget_->GetNativeWindow() accessibilityHitTest:ns_point];
+ return [widget_->GetNativeWindow().GetNativeNSWindow()
+ accessibilityHitTest:ns_point];
}
gfx::Point TabCenterPoint(int index) {
diff --git a/chromium/ui/views/controls/table/table_view_unittest.cc b/chromium/ui/views/controls/table/table_view_unittest.cc
index 88df9b24fd8..df04dc1a96e 100644
--- a/chromium/ui/views/controls/table/table_view_unittest.cc
+++ b/chromium/ui/views/controls/table/table_view_unittest.cc
@@ -20,6 +20,7 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_utils.h"
// Put the tests in the views namespace to make it easier to declare them as
// friend classes.
@@ -271,15 +272,15 @@ class TableViewTest : public ViewsTestBase {
}
void ClickOnRow(int row, int flags) {
- ui::test::EventGenerator generator(widget_->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget_.get()));
generator.set_assume_window_at_origin(false);
generator.set_flags(flags);
- generator.set_current_location(GetPointForRow(row));
+ generator.set_current_screen_location(GetPointForRow(row));
generator.PressLeftButton();
}
void TapOnRow(int row) {
- ui::test::EventGenerator generator(widget_->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget_.get()));
generator.GestureTapAt(GetPointForRow(row));
}
@@ -301,7 +302,7 @@ class TableViewTest : public ViewsTestBase {
}
void PressKey(ui::KeyboardCode code) {
- ui::test::EventGenerator generator(widget_->GetNativeWindow());
+ ui::test::EventGenerator generator(GetRootWindow(widget_.get()));
generator.PressKey(code, ui::EF_NONE);
}
diff --git a/chromium/ui/views/controls/textfield/textfield.h b/chromium/ui/views/controls/textfield/textfield.h
index 4d20d983432..f5d0914d43e 100644
--- a/chromium/ui/views/controls/textfield/textfield.h
+++ b/chromium/ui/views/controls/textfield/textfield.h
@@ -21,7 +21,7 @@
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/base/models/simple_menu_model.h"
-#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/base/pointer/touch_editing_controller.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/range/range.h"
diff --git a/chromium/ui/views/controls/textfield/textfield_model.cc b/chromium/ui/views/controls/textfield/textfield_model.cc
index 1bfea07108c..6c63283e596 100644
--- a/chromium/ui/views/controls/textfield/textfield_model.cc
+++ b/chromium/ui/views/controls/textfield/textfield_model.cc
@@ -270,7 +270,7 @@ gfx::Range GetFirstEmphasizedRange(const ui::CompositionText& composition) {
// the default kill ring size of 1 (i.e. a single buffer) is assumed.
base::string16* GetKillBuffer() {
static base::NoDestructor<base::string16> kill_buffer;
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
return kill_buffer.get();
}
diff --git a/chromium/ui/views/controls/textfield/textfield_unittest.cc b/chromium/ui/views/controls/textfield/textfield_unittest.cc
index be57d658a24..879ebf11a83 100644
--- a/chromium/ui/views/controls/textfield/textfield_unittest.cc
+++ b/chromium/ui/views/controls/textfield/textfield_unittest.cc
@@ -56,6 +56,7 @@
#include "ui/views/test/views_test_base.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
#include "url/gurl.h"
#if defined(OS_WIN)
@@ -492,8 +493,8 @@ class TextfieldTest : public ViewsTestBase, public TextfieldController {
widget_->Show();
textfield_->RequestFocus();
- event_generator_.reset(
- new ui::test::EventGenerator(widget_->GetNativeWindow()));
+ event_generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW);
}
ui::MenuModel* GetContextMenuModel() {
@@ -3074,7 +3075,7 @@ TEST_F(TextfieldTest, CursorBlinkRestartsOnInsertOrReplace) {
TEST_F(TextfieldTest, VirtualKeyboardFocusEnsureCaretNotInRect) {
InitTextfield();
- aura::Window* root_window = widget_->GetNativeView()->GetRootWindow();
+ aura::Window* root_window = GetRootWindow(widget_);
int keyboard_height = 200;
gfx::Rect root_bounds = root_window->bounds();
gfx::Rect orig_widget_bounds = gfx::Rect(0, 300, 400, 200);
diff --git a/chromium/ui/views/controls/tree/tree_view.cc b/chromium/ui/views/controls/tree/tree_view.cc
index b8b07ce5377..b57f0535ac0 100644
--- a/chromium/ui/views/controls/tree/tree_view.cc
+++ b/chromium/ui/views/controls/tree/tree_view.cc
@@ -11,7 +11,6 @@
#include "components/vector_icons/vector_icons.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/ime/input_method.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
diff --git a/chromium/ui/views/controls/views_text_services_context_menu_mac.mm b/chromium/ui/views/controls/views_text_services_context_menu_mac.mm
index c7731fb7547..0ae218c0f28 100644
--- a/chromium/ui/views/controls/views_text_services_context_menu_mac.mm
+++ b/chromium/ui/views/controls/views_text_services_context_menu_mac.mm
@@ -114,7 +114,7 @@ class ViewsTextServicesContextMenuMac
gfx::DecoratedText text;
if (client()->GetWordLookupDataFromSelection(&text, &baseline_point)) {
Widget* widget = client()->GetWidget();
- gfx::NativeView view = widget->GetNativeView();
+ NSView* view = widget->GetNativeView().GetNativeNSView();
views::View::ConvertPointToTarget(client(), widget->GetRootView(),
&baseline_point);
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
index d7bd93654d1..80ce19eb64d 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.cc
@@ -16,12 +16,12 @@ UnhandledKeyboardEventHandler::UnhandledKeyboardEventHandler()
UnhandledKeyboardEventHandler::~UnhandledKeyboardEventHandler() {
}
-void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
+bool UnhandledKeyboardEventHandler::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event,
FocusManager* focus_manager) {
if (!focus_manager) {
NOTREACHED();
- return;
+ return false;
}
// Previous calls to TranslateMessage can generate Char events as well as
// RawKeyDown events, even if the latter triggered an accelerator. In these
@@ -29,7 +29,7 @@ void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
if (event.GetType() == blink::WebInputEvent::kChar &&
ignore_next_char_event_) {
ignore_next_char_event_ = false;
- return;
+ return false;
}
// It's necessary to reset this flag, because a RawKeyDown event may not
// always generate a Char event.
@@ -45,9 +45,8 @@ void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
// set the flag and fix it if no event was handled.
ignore_next_char_event_ = true;
- if (focus_manager->ProcessAccelerator(accelerator)) {
- return;
- }
+ if (focus_manager->ProcessAccelerator(accelerator))
+ return true;
// ProcessAccelerator didn't handle the accelerator, so we know both
// that |this| is still valid, and that we didn't want to set the flag.
@@ -55,7 +54,9 @@ void UnhandledKeyboardEventHandler::HandleKeyboardEvent(
}
if (event.os_event && !event.skip_in_browser)
- HandleNativeKeyboardEvent(event.os_event, focus_manager);
+ return HandleNativeKeyboardEvent(event.os_event, focus_manager);
+
+ return false;
}
} // namespace views
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.h b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.h
index 8f06105703c..67cb6563e72 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.h
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler.h
@@ -23,12 +23,12 @@ class WEBVIEW_EXPORT UnhandledKeyboardEventHandler {
UnhandledKeyboardEventHandler();
~UnhandledKeyboardEventHandler();
- void HandleKeyboardEvent(const content::NativeWebKeyboardEvent& event,
+ bool HandleKeyboardEvent(const content::NativeWebKeyboardEvent& event,
FocusManager* focus_manager);
private:
// Platform specific handling for unhandled keyboard events.
- static void HandleNativeKeyboardEvent(gfx::NativeEvent event,
+ static bool HandleNativeKeyboardEvent(gfx::NativeEvent event,
FocusManager* focus_manager);
// Whether to ignore the next Char keyboard event.
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_default.cc b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_default.cc
index 8d30e36ad8a..f6cb4a38d17 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_default.cc
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_default.cc
@@ -10,10 +10,10 @@
namespace views {
// static
-void UnhandledKeyboardEventHandler::HandleNativeKeyboardEvent(
+bool UnhandledKeyboardEventHandler::HandleNativeKeyboardEvent(
gfx::NativeEvent event,
FocusManager* focus_manager) {
- focus_manager->OnKeyEvent(*static_cast<ui::KeyEvent*>(event));
+ return !focus_manager->OnKeyEvent(*(event->AsKeyEvent()));
}
} // namespace views
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 e87f913ff61..5e004e4190e 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
@@ -10,11 +10,12 @@
namespace views {
// static
-void UnhandledKeyboardEventHandler::HandleNativeKeyboardEvent(
+bool UnhandledKeyboardEventHandler::HandleNativeKeyboardEvent(
gfx::NativeEvent event,
FocusManager* focus_manager) {
[[base::mac::ObjCCastStrict<NativeWidgetMacNSWindow>([event window])
commandDispatcher] redispatchKeyEvent:event];
+ return true;
}
} // namespace views
diff --git a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
index e31aabbf901..04f7604c970 100644
--- a/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
+++ b/chromium/ui/views/controls/webview/unhandled_keyboard_event_handler_win.cc
@@ -9,13 +9,14 @@
namespace views {
// static
-void UnhandledKeyboardEventHandler::HandleNativeKeyboardEvent(
+bool UnhandledKeyboardEventHandler::HandleNativeKeyboardEvent(
gfx::NativeEvent event,
FocusManager* focus_manager) {
// Any unhandled keyboard/character messages should be defproced.
// This allows stuff like F10, etc to work correctly.
const MSG& message(event->native_event());
DefWindowProc(message.hwnd, message.message, message.wParam, message.lParam);
+ return true;
}
} // 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 56fc98b2840..e2023e4030f 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.cc
+++ b/chromium/ui/views/controls/webview/web_dialog_view.cc
@@ -287,12 +287,13 @@ void WebDialogView::SetContentsBounds(WebContents* source,
// A simplified version of BrowserView::HandleKeyboardEvent().
// We don't handle global keyboard shortcuts here, but that's fine since
// they're all browser-specific. (This may change in the future.)
-void WebDialogView::HandleKeyboardEvent(content::WebContents* source,
+bool WebDialogView::HandleKeyboardEvent(content::WebContents* source,
const NativeWebKeyboardEvent& event) {
if (!event.os_event)
- return;
+ return false;
GetWidget()->native_widget_private()->RepostNativeEvent(event.os_event);
+ return true;
}
void WebDialogView::CloseContents(WebContents* source) {
diff --git a/chromium/ui/views/controls/webview/web_dialog_view.h b/chromium/ui/views/controls/webview/web_dialog_view.h
index 29d18cb2e1f..6467993163f 100644
--- a/chromium/ui/views/controls/webview/web_dialog_view.h
+++ b/chromium/ui/views/controls/webview/web_dialog_view.h
@@ -97,7 +97,7 @@ class WEBVIEW_EXPORT WebDialogView : public views::ClientView,
// Overridden from content::WebContentsDelegate:
void SetContentsBounds(content::WebContents* source,
const gfx::Rect& bounds) override;
- void HandleKeyboardEvent(
+ bool HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
void CloseContents(content::WebContents* source) override;
diff --git a/chromium/ui/views/controls/webview/webview.cc b/chromium/ui/views/controls/webview/webview.cc
index 2a4cc7e8938..15e497fcf41 100644
--- a/chromium/ui/views/controls/webview/webview.cc
+++ b/chromium/ui/views/controls/webview/webview.cc
@@ -129,6 +129,10 @@ void WebView::SetCrashedOverlayView(View* crashed_overlay_view) {
if (crashed_overlay_view_) {
RemoveChildView(crashed_overlay_view_);
+ // Show the hosted web contents view iff the crashed
+ // overlay is NOT showing, to ensure hit testing is
+ // correct on Mac. See https://crbug.com/896508
+ holder_->SetVisible(true);
if (!crashed_overlay_view_->owned_by_client())
delete crashed_overlay_view_;
}
@@ -136,6 +140,7 @@ void WebView::SetCrashedOverlayView(View* crashed_overlay_view) {
crashed_overlay_view_ = crashed_overlay_view;
if (crashed_overlay_view_) {
AddChildView(crashed_overlay_view_);
+ holder_->SetVisible(false);
crashed_overlay_view_->SetBoundsRect(gfx::Rect(size()));
}
diff --git a/chromium/ui/views/controls/webview/webview_unittest.cc b/chromium/ui/views/controls/webview/webview_unittest.cc
index f1d0ce7758d..27be01b37a9 100644
--- a/chromium/ui/views/controls/webview/webview_unittest.cc
+++ b/chromium/ui/views/controls/webview/webview_unittest.cc
@@ -17,6 +17,7 @@
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "content/test/test_content_browser_client.h"
#include "ui/events/event.h"
@@ -187,6 +188,7 @@ class WebViewUnitTest : public views::test::WidgetTest {
private:
content::TestBrowserThreadBundle test_browser_thread_bundle_;
+ content::RenderViewHostTestEnabler rvh_enabler_;
std::unique_ptr<content::TestBrowserContext> browser_context_;
content::TestContentBrowserClient test_browser_client_;
std::unique_ptr<views::WebView::ScopedWebContentsCreatorForTesting>
diff --git a/chromium/ui/views/corewm/tooltip_controller_unittest.cc b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
index 83519930cee..77372afa1b6 100644
--- a/chromium/ui/views/corewm/tooltip_controller_unittest.cc
+++ b/chromium/ui/views/corewm/tooltip_controller_unittest.cc
@@ -183,7 +183,7 @@ TEST_F(TooltipControllerTest, ViewTooltip) {
generator_->MoveMouseToCenterOf(GetWindow());
EXPECT_EQ(GetWindow(), GetRootWindow()->GetEventHandlerForPoint(
- generator_->current_location()));
+ generator_->current_screen_location()));
base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
EXPECT_EQ(expected_tooltip, wm::GetTooltipText(GetWindow()));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
@@ -273,7 +273,7 @@ TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
generator_->MoveMouseBy(1, 0);
EXPECT_TRUE(helper_->IsTooltipVisible());
EXPECT_EQ(window, root_window->GetEventHandlerForPoint(
- generator_->current_location()));
+ generator_->current_screen_location()));
base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
EXPECT_EQ(expected_tooltip, wm::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
@@ -283,7 +283,7 @@ TEST_F(TooltipControllerTest, TooltipsInMultipleViews) {
generator_->MoveMouseBy(1, 0);
EXPECT_FALSE(helper_->IsTooltipVisible());
EXPECT_EQ(window, root_window->GetEventHandlerForPoint(
- generator_->current_location()));
+ generator_->current_screen_location()));
base::string16 expected_tooltip; // = ""
EXPECT_EQ(expected_tooltip, wm::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
@@ -346,9 +346,8 @@ TEST_F(TooltipControllerTest, TooltipHidesOnKeyPressAndStaysHiddenUntilChange) {
generator_->MoveMouseBy(1, 0);
EXPECT_FALSE(helper_->IsTooltipVisible());
EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
- EXPECT_EQ(window,
- GetRootWindow()->GetEventHandlerForPoint(
- generator_->current_location()));
+ EXPECT_EQ(window, GetRootWindow()->GetEventHandlerForPoint(
+ generator_->current_screen_location()));
base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1");
EXPECT_EQ(expected_tooltip, wm::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
@@ -392,7 +391,7 @@ TEST_F(TooltipControllerTest, TooltipHidesOnTimeoutAndStaysHiddenUntilChange) {
EXPECT_FALSE(helper_->IsTooltipVisible());
EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
EXPECT_EQ(window, GetRootWindow()->GetEventHandlerForPoint(
- generator_->current_location()));
+ generator_->current_screen_location()));
base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text for view 1");
EXPECT_EQ(expected_tooltip, wm::GetTooltipText(window));
EXPECT_EQ(expected_tooltip, helper_->GetTooltipText());
@@ -712,8 +711,10 @@ class TooltipControllerTest3 : public ViewsTestBase {
auto tooltip = std::make_unique<TestTooltip>();
test_tooltip_ = tooltip.get();
controller_ = std::make_unique<TooltipController>(std::move(tooltip));
- GetRootWindow()->RemovePreTargetHandler(static_cast<TooltipController*>(
- wm::GetTooltipClient(widget_->GetNativeWindow()->GetRootWindow())));
+ auto* tooltip_controller = static_cast<TooltipController*>(
+ wm::GetTooltipClient(widget_->GetNativeWindow()->GetRootWindow()));
+ if (tooltip_controller)
+ GetRootWindow()->RemovePreTargetHandler(tooltip_controller);
GetRootWindow()->AddPreTargetHandler(controller_.get());
helper_.reset(new TooltipControllerTestHelper(controller_.get()));
SetTooltipClient(GetRootWindow(), controller_.get());
diff --git a/chromium/ui/views/corewm/tooltip_win.cc b/chromium/ui/views/corewm/tooltip_win.cc
index 153d4c47484..918be16ed81 100644
--- a/chromium/ui/views/corewm/tooltip_win.cc
+++ b/chromium/ui/views/corewm/tooltip_win.cc
@@ -7,6 +7,7 @@
#include "base/debug/stack_trace.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/win/windowsx_shim.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
@@ -18,22 +19,6 @@
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),
diff --git a/chromium/ui/views/event_monitor.h b/chromium/ui/views/event_monitor.h
index d866e432a83..11137eae33c 100644
--- a/chromium/ui/views/event_monitor.h
+++ b/chromium/ui/views/event_monitor.h
@@ -6,41 +6,40 @@
#define UI_VIEWS_EVENT_MONITOR_H_
#include <memory>
+#include <set>
+#include "ui/events/event_constants.h"
+#include "ui/events/event_observer.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
-namespace ui {
-class EventHandler;
-}
-
namespace views {
-// RAII-style class that forwards events to |event_handler| before they are
-// dispatched.
+// RAII-style class that forwards events matching the specified |types| to
+// |event_observer| before they are dispatched to the intended target.
+// EventObservers cannot modify events nor alter dispatch.
class VIEWS_EXPORT EventMonitor {
public:
virtual ~EventMonitor() {}
- // Create an instance for monitoring application events.
- // Events will be forwarded to |event_handler| before they are dispatched to
- // the application. |context| is used to determine where to observer events
- // from. |context| may be destroyed before the EventMonitor.
+ // Create an instance for monitoring application events. This includes all
+ // events on ChromeOS, but only events targeting Chrome on desktop platforms.
+ // |context| is used to determine where to observe events from.
+ // |context| may be destroyed before the EventMonitor.
static std::unique_ptr<EventMonitor> CreateApplicationMonitor(
- ui::EventHandler* event_handler,
- gfx::NativeWindow context);
+ ui::EventObserver* event_observer,
+ gfx::NativeWindow context,
+ const std::set<ui::EventType>& types);
// Create an instance for monitoring events on a specific window.
- // Events will be forwarded to |event_handler| before they are dispatched to
- // |target_window|.
// The EventMonitor instance must be destroyed before |target_window|.
static std::unique_ptr<EventMonitor> CreateWindowMonitor(
- ui::EventHandler* event_handler,
- gfx::NativeWindow target_window);
+ ui::EventObserver* event_observer,
+ gfx::NativeWindow target_window,
+ const std::set<ui::EventType>& types);
- // Returns the last mouse location seen in a mouse event in screen
- // coordinates.
+ // Returns the last recorded mouse event location in screen coordinates.
virtual gfx::Point GetLastMouseLocation() = 0;
};
diff --git a/chromium/ui/views/event_monitor_aura.cc b/chromium/ui/views/event_monitor_aura.cc
index 5afde17f3dc..d560a66bd72 100644
--- a/chromium/ui/views/event_monitor_aura.cc
+++ b/chromium/ui/views/event_monitor_aura.cc
@@ -5,41 +5,44 @@
#include "ui/views/event_monitor_aura.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
+#include "ui/events/event_observer.h"
#include "ui/events/event_target.h"
namespace views {
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor(
- ui::EventHandler* event_handler,
- gfx::NativeWindow context) {
+ ui::EventObserver* event_observer,
+ gfx::NativeWindow context,
+ const std::set<ui::EventType>& types) {
aura::Env* env = context->env();
- return std::make_unique<EventMonitorAura>(env, event_handler, env);
+ return std::make_unique<EventMonitorAura>(env, event_observer, env, types);
}
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateWindowMonitor(
- ui::EventHandler* event_handler,
- gfx::NativeWindow target_window) {
- return std::make_unique<EventMonitorAura>(target_window->env(), event_handler,
- target_window);
+ ui::EventObserver* event_observer,
+ gfx::NativeWindow target_window,
+ const std::set<ui::EventType>& types) {
+ return std::make_unique<EventMonitorAura>(
+ target_window->env(), event_observer, target_window, types);
}
EventMonitorAura::EventMonitorAura(aura::Env* env,
- ui::EventHandler* event_handler,
- ui::EventTarget* event_target)
- : env_(env), event_handler_(event_handler), event_target_(event_target) {
+ ui::EventObserver* event_observer,
+ ui::EventTarget* event_target,
+ const std::set<ui::EventType>& types)
+ : env_(env), event_observer_(event_observer), event_target_(event_target) {
DCHECK(env_);
- DCHECK(event_handler_);
+ DCHECK(event_observer_);
DCHECK(event_target_);
- event_target_->AddPreTargetHandler(event_handler_);
+ env_->AddEventObserver(event_observer_, event_target, types);
}
EventMonitorAura::~EventMonitorAura() {
- event_target_->RemovePreTargetHandler(event_handler_);
+ env_->RemoveEventObserver(event_observer_);
}
gfx::Point EventMonitorAura::GetLastMouseLocation() {
diff --git a/chromium/ui/views/event_monitor_aura.h b/chromium/ui/views/event_monitor_aura.h
index 68c633b655a..222b8a15bc9 100644
--- a/chromium/ui/views/event_monitor_aura.h
+++ b/chromium/ui/views/event_monitor_aura.h
@@ -21,17 +21,18 @@ namespace views {
class EventMonitorAura : public EventMonitor {
public:
EventMonitorAura(aura::Env* env,
- ui::EventHandler* event_handler,
- ui::EventTarget* event_target);
+ ui::EventObserver* event_observer,
+ ui::EventTarget* event_target,
+ const std::set<ui::EventType>& types);
~EventMonitorAura() override;
// EventMonitor:
gfx::Point GetLastMouseLocation() override;
private:
- aura::Env* env_; // Weak.
- ui::EventHandler* event_handler_; // Weak. Owned by our owner.
- ui::EventTarget* event_target_; // Weak.
+ aura::Env* env_; // Weak.
+ ui::EventObserver* event_observer_; // Weak. Owned by our owner.
+ ui::EventTarget* event_target_; // Weak.
DISALLOW_COPY_AND_ASSIGN(EventMonitorAura);
};
diff --git a/chromium/ui/views/event_monitor_mac.h b/chromium/ui/views/event_monitor_mac.h
index 5cc56a5fef1..d3d46b6b54e 100644
--- a/chromium/ui/views/event_monitor_mac.h
+++ b/chromium/ui/views/event_monitor_mac.h
@@ -14,8 +14,9 @@ namespace views {
class EventMonitorMac : public EventMonitor {
public:
- EventMonitorMac(ui::EventHandler* event_handler,
- gfx::NativeWindow target_window);
+ EventMonitorMac(ui::EventObserver* event_observer,
+ gfx::NativeWindow target_window,
+ const std::set<ui::EventType>& types);
~EventMonitorMac() override;
// EventMonitor:
@@ -24,6 +25,7 @@ class EventMonitorMac : public EventMonitor {
private:
id monitor_;
ui::WeakPtrNSObjectFactory<EventMonitorMac> factory_;
+ const std::set<ui::EventType> types_;
DISALLOW_COPY_AND_ASSIGN(EventMonitorMac);
};
diff --git a/chromium/ui/views/event_monitor_mac.mm b/chromium/ui/views/event_monitor_mac.mm
index 46562a63972..cfa72698b19 100644
--- a/chromium/ui/views/event_monitor_mac.mm
+++ b/chromium/ui/views/event_monitor_mac.mm
@@ -10,30 +10,35 @@
#include "base/memory/ptr_util.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
-#include "ui/events/event_handler.h"
+#include "ui/events/event_observer.h"
#include "ui/events/event_utils.h"
namespace views {
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateApplicationMonitor(
- ui::EventHandler* event_handler,
- gfx::NativeWindow context) {
+ ui::EventObserver* event_observer,
+ gfx::NativeWindow context,
+ const std::set<ui::EventType>& types) {
// |context| is not needed on Mac.
- return base::WrapUnique(new EventMonitorMac(event_handler, nullptr));
+ return std::make_unique<EventMonitorMac>(event_observer, nullptr, types);
}
// static
std::unique_ptr<EventMonitor> EventMonitor::CreateWindowMonitor(
- ui::EventHandler* event_handler,
- gfx::NativeWindow target_window) {
- return base::WrapUnique(new EventMonitorMac(event_handler, target_window));
+ ui::EventObserver* event_observer,
+ gfx::NativeWindow target_window,
+ const std::set<ui::EventType>& types) {
+ return std::make_unique<EventMonitorMac>(event_observer, target_window,
+ types);
}
-EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler,
- gfx::NativeWindow target_window)
- : factory_(this) {
- DCHECK(event_handler);
+EventMonitorMac::EventMonitorMac(ui::EventObserver* event_observer,
+ gfx::NativeWindow target_native_window,
+ const std::set<ui::EventType>& types)
+ : factory_(this), types_(types) {
+ DCHECK(event_observer);
+ NSWindow* target_window = target_native_window.GetNativeNSWindow();
// Capture a WeakPtr via NSObject. This allows the block to detect another
// event monitor for the same event deleting |this|.
@@ -45,13 +50,8 @@ EventMonitorMac::EventMonitorMac(ui::EventHandler* event_handler,
if (!target_window || [event window] == target_window) {
std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event);
- if (ui_event) {
- event_handler->OnEvent(ui_event.get());
- // If an event is handled, swallow it by returning nil so the event
- // never proceeds to the normal event handling machinery.
- if (ui_event->handled())
- return nil;
- }
+ if (ui_event && types_.find(ui_event->type()) != types_.end())
+ event_observer->OnEvent(*ui_event);
}
return event;
};
diff --git a/chromium/ui/views/event_monitor_unittest.cc b/chromium/ui/views/event_monitor_unittest.cc
index 178ef70b56b..6db69c176c5 100644
--- a/chromium/ui/views/event_monitor_unittest.cc
+++ b/chromium/ui/views/event_monitor_unittest.cc
@@ -5,13 +5,35 @@
#include "ui/views/event_monitor.h"
#include "base/macros.h"
+#include "ui/events/event_observer.h"
#include "ui/events/test/event_generator.h"
-#include "ui/events/test/test_event_handler.h"
#include "ui/views/test/widget_test.h"
+#include "ui/views/widget/widget_utils.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#endif
namespace views {
namespace test {
+// A simple event observer that records the number of events.
+class TestEventObserver : public ui::EventObserver {
+ public:
+ TestEventObserver() = default;
+ ~TestEventObserver() override = default;
+
+ // ui::EventObserver:
+ void OnEvent(const ui::Event& event) override { ++observed_event_count_; }
+
+ size_t observed_event_count() const { return observed_event_count_; }
+
+ private:
+ size_t observed_event_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TestEventObserver);
+};
+
class EventMonitorTest : public WidgetTest {
public:
EventMonitorTest() : widget_(nullptr) {}
@@ -23,11 +45,16 @@ class EventMonitorTest : public WidgetTest {
widget_->SetSize(gfx::Size(100, 100));
widget_->Show();
if (IsMus()) {
- generator_.reset(
- new ui::test::EventGenerator(widget_->GetNativeWindow()));
+ generator_ =
+ std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
+// This #if will always be true on this path, but the code inside won't compile
+// for non-Aura.
+#if defined(USE_AURA)
+ generator_->MoveMouseRelativeTo(widget_->GetNativeWindow(), gfx::Point());
+#endif
} else {
- generator_.reset(new ui::test::EventGenerator(
- GetContext(), widget_->GetNativeWindow()));
+ generator_ = std::make_unique<ui::test::EventGenerator>(
+ GetContext(), widget_->GetNativeWindow());
}
generator_->set_target(ui::test::EventGenerator::Target::APPLICATION);
}
@@ -39,7 +66,7 @@ class EventMonitorTest : public WidgetTest {
protected:
Widget* widget_;
std::unique_ptr<ui::test::EventGenerator> generator_;
- ui::test::TestEventHandler handler_;
+ TestEventObserver observer_;
private:
DISALLOW_COPY_AND_ASSIGN(EventMonitorTest);
@@ -47,84 +74,97 @@ class EventMonitorTest : public WidgetTest {
TEST_F(EventMonitorTest, ShouldReceiveAppEventsWhileInstalled) {
std::unique_ptr<EventMonitor> monitor(EventMonitor::CreateApplicationMonitor(
- &handler_, widget_->GetNativeWindow()));
+ &observer_, widget_->GetNativeWindow(),
+ {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_RELEASED}));
generator_->ClickLeftButton();
- EXPECT_EQ(2, handler_.num_mouse_events());
+ EXPECT_EQ(2u, observer_.observed_event_count());
monitor.reset();
generator_->ClickLeftButton();
- EXPECT_EQ(2, handler_.num_mouse_events());
+ EXPECT_EQ(2u, observer_.observed_event_count());
}
TEST_F(EventMonitorTest, ShouldReceiveWindowEventsWhileInstalled) {
- std::unique_ptr<EventMonitor> monitor(
- EventMonitor::CreateWindowMonitor(&handler_, widget_->GetNativeWindow()));
+ std::unique_ptr<EventMonitor> monitor(EventMonitor::CreateWindowMonitor(
+ &observer_, widget_->GetNativeWindow(),
+ {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_RELEASED}));
generator_->ClickLeftButton();
- EXPECT_EQ(2, handler_.num_mouse_events());
+ EXPECT_EQ(2u, observer_.observed_event_count());
monitor.reset();
generator_->ClickLeftButton();
- EXPECT_EQ(2, handler_.num_mouse_events());
+ EXPECT_EQ(2u, observer_.observed_event_count());
}
TEST_F(EventMonitorTest, ShouldNotReceiveEventsFromOtherWindow) {
Widget* widget2 = CreateTopLevelNativeWidget();
- std::unique_ptr<EventMonitor> monitor(
- EventMonitor::CreateWindowMonitor(&handler_, widget2->GetNativeWindow()));
+ std::unique_ptr<EventMonitor> monitor(EventMonitor::CreateWindowMonitor(
+ &observer_, widget2->GetNativeWindow(),
+ {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_RELEASED}));
generator_->ClickLeftButton();
- EXPECT_EQ(0, handler_.num_mouse_events());
+ EXPECT_EQ(0u, observer_.observed_event_count());
monitor.reset();
widget2->CloseNow();
}
+TEST_F(EventMonitorTest, ShouldOnlyReceiveRequestedEventTypes) {
+ // This event monitor only listens to mouse press, not release.
+ std::unique_ptr<EventMonitor> monitor(EventMonitor::CreateWindowMonitor(
+ &observer_, widget_->GetNativeWindow(), {ui::ET_MOUSE_PRESSED}));
+
+ generator_->ClickLeftButton();
+ EXPECT_EQ(1u, observer_.observed_event_count());
+
+ monitor.reset();
+}
+
namespace {
-class DeleteOtherOnEventHandler : public ui::EventHandler {
+class DeleteOtherOnEventObserver : public ui::EventObserver {
public:
- explicit DeleteOtherOnEventHandler(gfx::NativeWindow context) {
- monitor_ = EventMonitor::CreateApplicationMonitor(this, context);
+ explicit DeleteOtherOnEventObserver(gfx::NativeWindow context) {
+ monitor_ = EventMonitor::CreateApplicationMonitor(
+ this, context, {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_RELEASED});
}
- bool DidDelete() const { return !handler_to_delete_; }
+ bool DidDelete() const { return !observer_to_delete_; }
void set_monitor_to_delete(
- std::unique_ptr<DeleteOtherOnEventHandler> handler_to_delete) {
- handler_to_delete_ = std::move(handler_to_delete);
+ std::unique_ptr<DeleteOtherOnEventObserver> observer_to_delete) {
+ observer_to_delete_ = std::move(observer_to_delete);
}
- // EventHandler::
- void OnMouseEvent(ui::MouseEvent* event) override {
- handler_to_delete_ = nullptr;
+ // ui::EventObserver:
+ void OnEvent(const ui::Event& event) override {
+ observer_to_delete_ = nullptr;
}
private:
std::unique_ptr<EventMonitor> monitor_;
- std::unique_ptr<DeleteOtherOnEventHandler> handler_to_delete_;
+ std::unique_ptr<DeleteOtherOnEventObserver> observer_to_delete_;
- DISALLOW_COPY_AND_ASSIGN(DeleteOtherOnEventHandler);
+ DISALLOW_COPY_AND_ASSIGN(DeleteOtherOnEventObserver);
};
} // namespace
// Ensure correct behavior when an event monitor is removed while iterating
// over the OS-controlled observer list.
TEST_F(EventMonitorTest, TwoMonitors) {
- auto deleter =
- std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow());
- deleter->set_monitor_to_delete(
- std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow()));
+ gfx::NativeWindow window = widget_->GetNativeWindow();
+ auto deleter = std::make_unique<DeleteOtherOnEventObserver>(window);
+ auto deletee = std::make_unique<DeleteOtherOnEventObserver>(window);
+ deleter->set_monitor_to_delete(std::move(deletee));
EXPECT_FALSE(deleter->DidDelete());
generator_->PressLeftButton();
EXPECT_TRUE(deleter->DidDelete());
// Now try setting up observers in the alternate order.
- auto deletee =
- std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow());
- deleter =
- std::make_unique<DeleteOtherOnEventHandler>(widget_->GetNativeWindow());
+ deletee = std::make_unique<DeleteOtherOnEventObserver>(window);
+ deleter = std::make_unique<DeleteOtherOnEventObserver>(window);
deleter->set_monitor_to_delete(std::move(deletee));
EXPECT_FALSE(deleter->DidDelete());
diff --git a/chromium/ui/views/event_utils.cc b/chromium/ui/views/event_utils.cc
index ecec6e0220c..83ca464f1b6 100644
--- a/chromium/ui/views/event_utils.cc
+++ b/chromium/ui/views/event_utils.cc
@@ -12,8 +12,7 @@ namespace views {
bool IsPossiblyUnintendedInteraction(const base::TimeTicks& initial_timestamp,
const ui::Event& event) {
- return (event.IsMouseEvent() || event.IsPointerEvent() ||
- event.IsTouchEvent()) &&
+ return (event.IsMouseEvent() || event.IsTouchEvent()) &&
event.time_stamp() <
initial_timestamp +
base::TimeDelta::FromMilliseconds(GetDoubleClickInterval());
diff --git a/chromium/ui/views/examples/BUILD.gn b/chromium/ui/views/examples/BUILD.gn
index 0069d8c9c8d..eab97ae3045 100644
--- a/chromium/ui/views/examples/BUILD.gn
+++ b/chromium/ui/views/examples/BUILD.gn
@@ -33,6 +33,8 @@ jumbo_component("views_examples_lib") {
"examples_window.h",
"label_example.cc",
"label_example.h",
+ "layout_example_base.cc",
+ "layout_example_base.h",
"link_example.cc",
"link_example.h",
"menu_example.cc",
diff --git a/chromium/ui/views/examples/animated_image_view_example.cc b/chromium/ui/views/examples/animated_image_view_example.cc
index 4e52a95aeab..095403a112f 100644
--- a/chromium/ui/views/examples/animated_image_view_example.cc
+++ b/chromium/ui/views/examples/animated_image_view_example.cc
@@ -14,8 +14,8 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
+#include "cc/paint/skottie_wrapper.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"
@@ -99,7 +99,7 @@ class AnimationGallery : public View,
#endif // defined(OS_POSIX)
base::ReadFileToString(path, &json);
- auto skottie = base::MakeRefCounted<gfx::SkottieWrapper>(
+ auto skottie = base::MakeRefCounted<cc::SkottieWrapper>(
base::RefCountedString::TakeString(&json));
animated_image_view_->SetAnimatedImage(
std::make_unique<gfx::SkiaVectorAnimation>(skottie));
diff --git a/chromium/ui/views/examples/box_layout_example.cc b/chromium/ui/views/examples/box_layout_example.cc
index a17fd295dee..f731b6a77a4 100644
--- a/chromium/ui/views/examples/box_layout_example.cc
+++ b/chromium/ui/views/examples/box_layout_example.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "box_layout_example.h"
+#include "ui/views/examples/box_layout_example.h"
-#include <vector>
+#include <memory>
+#include <utility>
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
@@ -23,337 +24,46 @@
#include "ui/views/examples/example_combobox_model.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/view.h"
-#include "ui/views/view_properties.h"
namespace views {
namespace examples {
-namespace {
-
-// This View holds two other views which consists of a view on the left onto
-// which the BoxLayout is attached for demonstrating its features. The view
-// on the right contains all the various controls which allow the user to
-// interactively control the various features/properties of BoxLayout. Layout()
-// will ensure the left view takes 75% and the right view fills the remaining
-// 25%.
-class FullPanel : public View {
- public:
- FullPanel() {}
- ~FullPanel() override {}
-
- // View
- void Layout() override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FullPanel);
-};
-
-// This view is created and added to the left-side view in the FullPanel each
-// time the "Add" button is pressed. It also will display Textfield controls
-// when the mouse is pressed over the view. These Textfields allow the user to
-// interactively set each margin and the "flex" for the given view.
-class ChildPanel : public View, public TextfieldController {
- public:
- explicit ChildPanel(BoxLayoutExample* example, gfx::Size preferred_size);
- ~ChildPanel() override {}
-
- // View
- gfx::Size CalculatePreferredSize() const override;
- bool OnMousePressed(const ui::MouseEvent& event) override;
- void Layout() override;
-
- void SetSelected(bool value);
- bool selected() const { return selected_; };
-
- int GetFlex();
-
- private:
- // TextfieldController
- void ContentsChanged(Textfield* sender,
- const base::string16& new_contents) override;
-
- Textfield* CreateTextfield();
-
- BoxLayoutExample* example_;
- bool selected_ = false;
- Textfield* flex_;
- Textfield* margin_[4];
- gfx::Size preferred_size_;
-
- DISALLOW_COPY_AND_ASSIGN(ChildPanel);
-};
-
-void FullPanel::Layout() {
- DCHECK_EQ(child_count(), 2);
- View* left_panel = child_at(0);
- View* right_panel = child_at(1);
- gfx::Rect bounds = GetContentsBounds();
- left_panel->SetBounds(bounds.x(), bounds.y(), (bounds.width() * 75) / 100,
- bounds.height());
- right_panel->SetBounds(left_panel->width(), bounds.y(),
- bounds.width() - left_panel->width(), bounds.height());
-}
-
-ChildPanel::ChildPanel(BoxLayoutExample* example, gfx::Size preferred_size)
- : View(), example_(example), preferred_size_(preferred_size) {
- SetBorder(CreateSolidBorder(1, SK_ColorGRAY));
- for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i)
- margin_[i] = CreateTextfield();
- flex_ = CreateTextfield();
- flex_->SetText(base::ASCIIToUTF16(""));
-}
-
-gfx::Size ChildPanel::CalculatePreferredSize() const {
- return preferred_size_;
-}
-
-bool ChildPanel::OnMousePressed(const ui::MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton())
- SetSelected(true);
- return true;
-}
-
-void ChildPanel::Layout() {
- const int kSpacing = 2;
- if (selected_) {
- gfx::Rect client = GetContentsBounds();
- for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
- gfx::Point pos;
- Textfield* textfield = margin_[i];
- switch (i) {
- case 0:
- pos = gfx::Point((client.width() - textfield->width()) / 2, kSpacing);
- break;
- case 1:
- pos =
- gfx::Point(kSpacing, (client.height() - textfield->height()) / 2);
- break;
- case 2:
- pos = gfx::Point((client.width() - textfield->width()) / 2,
- client.height() - textfield->height() - kSpacing);
- break;
- case 3:
- pos = gfx::Point(client.width() - textfield->width() - kSpacing,
- (client.height() - textfield->height()) / 2);
- break;
- default:
- NOTREACHED();
- }
- textfield->SetPosition(pos);
- }
- flex_->SetPosition(gfx::Point((client.width() - flex_->width()) / 2,
- (client.height() - flex_->height()) / 2));
- }
-}
-
-void ChildPanel::SetSelected(bool value) {
- if (value != selected_) {
- selected_ = value;
- SetBorder(CreateSolidBorder(1, selected_ ? SK_ColorBLACK : SK_ColorGRAY));
- if (selected_ && parent()) {
- for (int i = 0; i < parent()->child_count(); ++i) {
- View* child = parent()->child_at(i);
- if (child != this && child->GetGroup() == GetGroup()) {
- ChildPanel* child_panel = static_cast<ChildPanel*>(child);
- child_panel->SetSelected(false);
- }
- }
- }
- for (Textfield* textfield : margin_)
- textfield->SetVisible(selected_);
- flex_->SetVisible(selected_);
- InvalidateLayout();
- example_->RefreshLayoutPanel();
- }
-}
-
-int ChildPanel::GetFlex() {
- int flex;
- if (base::StringToInt(flex_->text(), &flex))
- return flex;
- return -1;
-}
-
-void ChildPanel::ContentsChanged(Textfield* sender,
- const base::string16& new_contents) {
- int edges[4];
- for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
- base::StringToInt(margin_[i]->text(), &edges[i]);
- }
- gfx::Insets margins = gfx::Insets(edges[0], edges[1], edges[2], edges[3]);
- if (!margins.IsEmpty())
- this->SetProperty(kMarginsKey, new gfx::Insets(margins));
- else
- this->ClearProperty(kMarginsKey);
- if (sender == flex_)
- example_->UpdateLayoutManager();
- example_->RefreshLayoutPanel();
-}
-
-Textfield* ChildPanel::CreateTextfield() {
- Textfield* textfield = new Textfield();
- textfield->SetDefaultWidthInChars(3);
- textfield->SizeToPreferredSize();
- textfield->SetText(base::ASCIIToUTF16("0"));
- textfield->set_controller(this);
- textfield->SetVisible(false);
- AddChildView(textfield);
- return textfield;
-}
-
-const int kSpacing = 3;
-const int kPadding = 8;
-const int kMaxPanels = 5;
-const int kChildPanelGroup = 100;
-const int kChildPanelWidth = 180;
-const int kChildPanelHeight = 90;
-const char* orientation_values[2] = {"Horizontal", "Vertical"};
-const char* main_axis_values[3] = {"Start", "Center", "End"};
-const char* cross_axis_values[4] = {"Stretch", "Start", "Center", "End"};
-}
-
-BoxLayoutExample::BoxLayoutExample() : ExampleBase("Box Layout") {}
+BoxLayoutExample::BoxLayoutExample() : LayoutExampleBase("Box Layout") {}
BoxLayoutExample::~BoxLayoutExample() {}
-Combobox* BoxLayoutExample::CreateCombobox(const base::string16& label_text,
- const char** items,
- int count,
- int& vertical_pos) {
- Label* label = new Label(label_text);
- label->SetPosition(gfx::Point(kPadding, vertical_pos));
- label->SizeToPreferredSize();
- Combobox* combo_box =
- new Combobox(std::make_unique<ExampleComboboxModel>(items, count));
- combo_box->SetPosition(
- gfx::Point(label->x() + label->width() + kSpacing, vertical_pos));
- combo_box->SizeToPreferredSize();
- combo_box->set_listener(this);
- label->SetSize(gfx::Size(label->width(), combo_box->height()));
- control_panel_->AddChildView(label);
- control_panel_->AddChildView(combo_box);
- vertical_pos += combo_box->height() + kSpacing;
- return combo_box;
-}
-
-Textfield* BoxLayoutExample::CreateRawTextfield(int& horizontal_pos,
- int vertical_pos,
- bool add) {
- Textfield* text_field = new Textfield();
- text_field->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
- text_field->SetDefaultWidthInChars(3);
- text_field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
- text_field->SizeToPreferredSize();
- text_field->SetText(base::ASCIIToUTF16("0"));
- text_field->set_controller(this);
- horizontal_pos += text_field->width() + kSpacing;
- if (add)
- control_panel_->AddChildView(text_field);
- return text_field;
-}
-
-Textfield* BoxLayoutExample::CreateTextfield(const base::string16& label_text,
- int& vertical_pos) {
- Label* label = new Label(label_text);
- label->SetPosition(gfx::Point(kPadding, vertical_pos));
- label->SizeToPreferredSize();
- int horizontal_pos = label->x() + label->width() + kSpacing;
- Textfield* text_field =
- CreateRawTextfield(horizontal_pos, vertical_pos, false);
- label->SetSize(gfx::Size(label->width(), text_field->height()));
- control_panel_->AddChildView(label);
- control_panel_->AddChildView(text_field);
- vertical_pos += text_field->height() + kSpacing;
- return text_field;
-}
-
-gfx::Size BoxLayoutExample::GetChildPanelSize() const {
- int width;
- int height;
- if (!base::StringToInt(child_panel_size_[0]->text(), &width))
- width = kChildPanelWidth;
- if (!base::StringToInt(child_panel_size_[1]->text(), &height))
- height = kChildPanelHeight;
- return gfx::Size(std::max(0, width), std::max(0, height));
-}
-
-void BoxLayoutExample::CreateExampleView(View* container) {
- container->SetLayoutManager(std::make_unique<FillLayout>());
- full_panel_ = new FullPanel();
- container->AddChildView(full_panel_);
-
- box_layout_panel_ = new View();
- box_layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
- full_panel_->AddChildView(box_layout_panel_);
- control_panel_ = new View();
- full_panel_->AddChildView(control_panel_);
-
- int vertical_pos = kSpacing;
- int horizontal_pos = kPadding;
- add_button_ =
- MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
- add_button_->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
- add_button_->SizeToPreferredSize();
- control_panel_->AddChildView(add_button_);
- horizontal_pos += add_button_->width() + kSpacing;
- for (unsigned i = 0;
- i < sizeof(child_panel_size_) / sizeof(child_panel_size_[0]); ++i) {
- child_panel_size_[i] =
- CreateRawTextfield(horizontal_pos, vertical_pos, true);
- child_panel_size_[i]->SetY(
- vertical_pos +
- (add_button_->height() - child_panel_size_[i]->height()) / 2);
- }
- child_panel_size_[0]->SetText(base::IntToString16(kChildPanelWidth));
- child_panel_size_[1]->SetText(base::IntToString16(kChildPanelHeight));
- vertical_pos += add_button_->height() + kSpacing;
+void BoxLayoutExample::CreateAdditionalControls(int vertical_pos) {
+ static const char* orientation_values[2] = {"Horizontal", "Vertical"};
+ static const char* main_axis_values[3] = {"Start", "Center", "End"};
+ static const char* cross_axis_values[4] = {"Stretch", "Start", "Center",
+ "End"};
orientation_ = CreateCombobox(base::ASCIIToUTF16("Orientation"),
- orientation_values, 2, vertical_pos);
+ orientation_values, 2, &vertical_pos);
main_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Main axis"),
- main_axis_values, 3, vertical_pos);
+ main_axis_values, 3, &vertical_pos);
cross_axis_alignment_ = CreateCombobox(base::ASCIIToUTF16("Cross axis"),
- cross_axis_values, 4, vertical_pos);
+ cross_axis_values, 4, &vertical_pos);
between_child_spacing_ =
- CreateTextfield(base::ASCIIToUTF16("Child spacing"), vertical_pos);
+ CreateTextfield(base::ASCIIToUTF16("Child spacing"), &vertical_pos);
default_flex_ =
- CreateTextfield(base::ASCIIToUTF16("Default flex"), vertical_pos);
+ CreateTextfield(base::ASCIIToUTF16("Default flex"), &vertical_pos);
min_cross_axis_size_ =
- CreateTextfield(base::ASCIIToUTF16("Min cross axis"), vertical_pos);
+ CreateTextfield(base::ASCIIToUTF16("Min cross axis"), &vertical_pos);
- border_insets_[0] =
- CreateTextfield(base::ASCIIToUTF16("Insets"), vertical_pos);
- horizontal_pos =
- border_insets_[0]->x() + border_insets_[0]->width() + kSpacing;
- for (unsigned i = 1; i < sizeof(border_insets_) / sizeof(border_insets_[0]);
- ++i)
- border_insets_[i] =
- CreateRawTextfield(horizontal_pos, border_insets_[0]->y(), true);
+ CreateMarginsTextFields(base::ASCIIToUTF16("Insets"), border_insets_,
+ &vertical_pos);
collapse_margins_ =
- new Checkbox(base::ASCIIToUTF16("Collapse margins"), this);
- collapse_margins_->SetPosition(gfx::Point(kPadding, vertical_pos));
- collapse_margins_->SizeToPreferredSize();
- control_panel_->AddChildView(collapse_margins_);
+ CreateCheckbox(base::ASCIIToUTF16("Collapse margins"), &vertical_pos);
UpdateLayoutManager();
}
-void BoxLayoutExample::ButtonPressed(Button* sender, const ui::Event& event) {
- if (sender == add_button_) {
- if (panel_count_ < kMaxPanels) {
- ++panel_count_;
- ChildPanel* panel = new ChildPanel(this, GetChildPanelSize());
- panel->SetGroup(kChildPanelGroup);
- box_layout_panel_->AddChildView(panel);
- RefreshLayoutPanel();
- } else {
- PrintStatus("Only %i panels may be added", kMaxPanels);
- }
- } else if (sender == collapse_margins_) {
- UpdateLayoutManager();
- RefreshLayoutPanel();
+void BoxLayoutExample::ButtonPressedImpl(Button* sender) {
+ if (sender == collapse_margins_) {
+ RefreshLayoutPanel(true);
}
}
@@ -368,7 +78,7 @@ void BoxLayoutExample::OnPerformAction(Combobox* combobox) {
static_cast<BoxLayout::CrossAxisAlignment>(
cross_axis_alignment_->selected_index()));
}
- RefreshLayoutPanel();
+ RefreshLayoutPanel(false);
}
void BoxLayoutExample::ContentsChanged(Textfield* textfield,
@@ -387,21 +97,11 @@ void BoxLayoutExample::ContentsChanged(Textfield* textfield,
textfield == border_insets_[2] || textfield == border_insets_[3]) {
UpdateBorderInsets();
}
- RefreshLayoutPanel();
-}
-
-void BoxLayoutExample::RefreshLayoutPanel() {
- box_layout_panel_->Layout();
- box_layout_panel_->SchedulePaint();
+ RefreshLayoutPanel(false);
}
void BoxLayoutExample::UpdateBorderInsets() {
- int inset_values[4];
- for (unsigned i = 0; i < sizeof(border_insets_) / sizeof(border_insets_[0]);
- ++i)
- base::StringToInt(border_insets_[i]->text(), &inset_values[i]);
- layout_->set_inside_border_insets(gfx::Insets(
- inset_values[0], inset_values[1], inset_values[2], inset_values[3]));
+ layout_->set_inside_border_insets(TextfieldsToInsets(border_insets_));
}
void BoxLayoutExample::UpdateLayoutManager() {
@@ -421,16 +121,16 @@ void BoxLayoutExample::UpdateLayoutManager() {
main_axis_alignment_->selected_index()));
layout->SetDefaultFlex(default_flex);
layout->set_minimum_cross_axis_size(min_cross_size);
- layout_ = box_layout_panel_->SetLayoutManager(std::move(layout));
+ View* const panel = layout_panel();
+ layout_ = panel->SetLayoutManager(std::move(layout));
UpdateBorderInsets();
- for (int i = 0; i < box_layout_panel_->child_count(); ++i) {
- ChildPanel* panel =
- static_cast<ChildPanel*>(box_layout_panel_->child_at(i));
- int flex = panel->GetFlex();
+ for (int i = 0; i < panel->child_count(); ++i) {
+ ChildPanel* child_panel = static_cast<ChildPanel*>(panel->child_at(i));
+ int flex = child_panel->GetFlex();
if (flex < 0)
- layout_->ClearFlexForView(panel);
+ layout_->ClearFlexForView(child_panel);
else
- layout_->SetFlexForView(panel, flex);
+ layout_->SetFlexForView(child_panel, flex);
}
}
diff --git a/chromium/ui/views/examples/box_layout_example.h b/chromium/ui/views/examples/box_layout_example.h
index a11fc9e6a80..e8a9d83ab97 100644
--- a/chromium/ui/views/examples/box_layout_example.h
+++ b/chromium/ui/views/examples/box_layout_example.h
@@ -8,9 +8,7 @@
#include "base/macros.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/examples/example_base.h"
+#include "ui/views/examples/layout_example_base.h"
#include "ui/views/layout/box_layout.h"
namespace views {
@@ -21,26 +19,14 @@ class Textfield;
namespace examples {
-namespace {
-
-class ChildPanel;
-}
-
-class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase,
- public ButtonListener,
- public ComboboxListener,
- public TextfieldController {
+class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public LayoutExampleBase {
public:
BoxLayoutExample();
~BoxLayoutExample() override;
- // ExampleBase
- void CreateExampleView(View* container) override;
-
private:
- friend views::examples::ChildPanel;
- // ButtonListener
- void ButtonPressed(Button* sender, const ui::Event& event) override;
+ // Set the border insets on the current BoxLayout instance.
+ void UpdateBorderInsets();
// ComboboxListener
void OnPerformAction(Combobox* combobox) override;
@@ -49,45 +35,12 @@ class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase,
void ContentsChanged(Textfield* sender,
const base::string16& new_contents) override;
- // Force the box_layout_panel_ to layout and repaint.
- void RefreshLayoutPanel();
-
- // Set the border insets on the current BoxLayout instance.
- void UpdateBorderInsets();
-
- // Create a new BoxLayout and ensure all settings match the current state of
- // the various control_panel_ controls.
- void UpdateLayoutManager();
-
- // Create a Combobox with a label with |label_text| to the left. Adjust
- // |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
- Combobox* CreateCombobox(const base::string16& label_text,
- const char** items,
- int count,
- int& vertical_pos);
-
- // Create just a Textfield at the current position of |horizontal_pos| and
- // |vertical_pos|. Update |horizontal_pos| to |horizontal_pos| +
- // text_field->width() + kSpacing.
- Textfield* CreateRawTextfield(int& horizontal_pos,
- int vertical_pos,
- bool add);
-
- // Create a Textfield with a label with |label_text| to the left. Adjust
- // |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
- Textfield* CreateTextfield(const base::string16& label_text,
- int& vertical_pos);
-
- // Returns the current values contained in the child_panel_size_[] Textfields
- // as a gfx::Size. If either value is negative or not a valid integer,
- // default values are returned, 180 x 90 for width and height, respectively.
- gfx::Size GetChildPanelSize() const;
+ // LayoutExampleBase
+ void ButtonPressedImpl(Button* sender) override;
+ void CreateAdditionalControls(int vertical_start_pos) override;
+ void UpdateLayoutManager() override;
BoxLayout* layout_ = nullptr;
- View* full_panel_ = nullptr;
- View* box_layout_panel_ = nullptr;
- View* control_panel_ = nullptr;
- LabelButton* add_button_ = nullptr;
Combobox* orientation_ = nullptr;
Combobox* main_axis_alignment_ = nullptr;
Combobox* cross_axis_alignment_ = nullptr;
@@ -95,9 +48,7 @@ class VIEWS_EXAMPLES_EXPORT BoxLayoutExample : public ExampleBase,
Textfield* default_flex_ = nullptr;
Textfield* min_cross_axis_size_ = nullptr;
Textfield* border_insets_[4] = {nullptr, nullptr, nullptr, nullptr};
- Textfield* child_panel_size_[2] = {nullptr, nullptr};
Checkbox* collapse_margins_ = nullptr;
- int panel_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(BoxLayoutExample);
};
diff --git a/chromium/ui/views/examples/button_example.cc b/chromium/ui/views/examples/button_example.cc
index 37c31a2306e..74919124c1b 100644
--- a/chromium/ui/views/examples/button_example.cc
+++ b/chromium/ui/views/examples/button_example.cc
@@ -9,7 +9,6 @@
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/image/image.h"
#include "ui/views/background.h"
-#include "ui/views/controls/button/blue_button.h"
#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"
@@ -58,8 +57,6 @@ void ButtonExample::CreateExampleView(View* container) {
disabled_button_->SetState(Button::STATE_DISABLED);
container->AddChildView(disabled_button_);
- container->AddChildView(new BlueButton(this, ASCIIToUTF16("Blue Button")));
-
md_button_ =
MdTextButton::Create(this, base::ASCIIToUTF16("Material design"));
container->AddChildView(md_button_);
diff --git a/chromium/ui/views/examples/combobox_example.cc b/chromium/ui/views/examples/combobox_example.cc
index ff46b875648..b5ec924e533 100644
--- a/chromium/ui/views/examples/combobox_example.cc
+++ b/chromium/ui/views/examples/combobox_example.cc
@@ -4,6 +4,8 @@
#include "ui/views/examples/combobox_example.h"
+#include <memory>
+
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/geometry/insets.h"
@@ -13,65 +15,52 @@
namespace views {
namespace examples {
-ComboboxModelExample::ComboboxModelExample() {
-}
+namespace {
-ComboboxModelExample::~ComboboxModelExample() {
-}
+// A combobox model implementation that generates a list of "Item <index>".
+class ComboboxModelExample : public ui::ComboboxModel {
+ public:
+ ComboboxModelExample() = default;
+ ~ComboboxModelExample() override = default;
-int ComboboxModelExample::GetItemCount() const {
- return 10;
-}
+ private:
+ // ui::ComboboxModel:
+ int GetItemCount() const override { return 10; }
+ base::string16 GetItemAt(int index) override {
+ return base::UTF8ToUTF16(base::StringPrintf("%c item", 'A' + index));
+ }
-base::string16 ComboboxModelExample::GetItemAt(int index) {
- return base::UTF8ToUTF16(base::StringPrintf("%c item", 'A' + index));
-}
+ DISALLOW_COPY_AND_ASSIGN(ComboboxModelExample);
+};
+
+} // namespace
ComboboxExample::ComboboxExample() : ExampleBase("Combo Box") {
}
-ComboboxExample::~ComboboxExample() {
- // Delete |combobox_| first as it references |combobox_model_|.
- delete combobox_;
- delete disabled_combobox_;
- delete action_combobox_;
- combobox_ = nullptr;
- disabled_combobox_ = nullptr;
- action_combobox_ = nullptr;
-}
+ComboboxExample::~ComboboxExample() = default;
void ComboboxExample::CreateExampleView(View* container) {
- combobox_ = new Combobox(&combobox_model_);
+ combobox_ = new Combobox(std::make_unique<ComboboxModelExample>());
combobox_->set_listener(this);
combobox_->SetSelectedIndex(3);
- disabled_combobox_ = new Combobox(&combobox_model_);
+ disabled_combobox_ = new Combobox(std::make_unique<ComboboxModelExample>());
disabled_combobox_->set_listener(this);
disabled_combobox_->SetSelectedIndex(4);
disabled_combobox_->SetEnabled(false);
- action_combobox_ = new Combobox(&combobox_model_, Combobox::STYLE_ACTION);
- action_combobox_->set_listener(this);
- // Note: STYLE_ACTION comboboxes always have the first item selected by
- // default.
-
container->SetLayoutManager(
std::make_unique<BoxLayout>(BoxLayout::kVertical, gfx::Insets(10, 0), 5));
container->AddChildView(combobox_);
container->AddChildView(disabled_combobox_);
- container->AddChildView(action_combobox_);
}
void ComboboxExample::OnPerformAction(Combobox* combobox) {
- if (combobox == combobox_) {
- PrintStatus("Selected: %s", base::UTF16ToUTF8(combobox_model_.GetItemAt(
- combobox->selected_index())).c_str());
- } else if (combobox == action_combobox_) {
- PrintStatus("Action: %s", base::UTF16ToUTF8(combobox_model_.GetItemAt(
- combobox->selected_index())).c_str());
- } else {
- NOTREACHED() << "Surprising combobox.";
- }
+ DCHECK_EQ(combobox, combobox_);
+ PrintStatus("Selected: %s", base::UTF16ToUTF8(combobox->model()->GetItemAt(
+ combobox->selected_index()))
+ .c_str());
}
} // namespace examples
diff --git a/chromium/ui/views/examples/combobox_example.h b/chromium/ui/views/examples/combobox_example.h
index a2448b2fc50..868ab2b67e3 100644
--- a/chromium/ui/views/examples/combobox_example.h
+++ b/chromium/ui/views/examples/combobox_example.h
@@ -13,20 +13,6 @@
namespace views {
namespace examples {
-// A combobox model implementation that generates a list of "Item <index>".
-class VIEWS_EXAMPLES_EXPORT ComboboxModelExample : public ui::ComboboxModel {
- public:
- ComboboxModelExample();
- ~ComboboxModelExample() override;
-
- // ui::ComboboxModel:
- int GetItemCount() const override;
- base::string16 GetItemAt(int index) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ComboboxModelExample);
-};
-
class VIEWS_EXAMPLES_EXPORT ComboboxExample : public ExampleBase,
public ComboboxListener {
public:
@@ -40,10 +26,8 @@ class VIEWS_EXAMPLES_EXPORT ComboboxExample : public ExampleBase,
// ComboboxListener:
void OnPerformAction(Combobox* combobox) override;
- ComboboxModelExample combobox_model_;
Combobox* combobox_ = nullptr;
Combobox* disabled_combobox_ = nullptr;
- Combobox* action_combobox_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ComboboxExample);
};
diff --git a/chromium/ui/views/examples/examples_window.cc b/chromium/ui/views/examples/examples_window.cc
index 683d5d59711..0c3689af6c7 100644
--- a/chromium/ui/views/examples/examples_window.cc
+++ b/chromium/ui/views/examples/examples_window.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <iterator>
+#include <memory>
#include <string>
#include <utility>
@@ -134,13 +135,16 @@ class ExamplesWindowContents : public WidgetDelegateView,
public ComboboxListener {
public:
ExamplesWindowContents(base::OnceClosure on_close, ExampleVector examples)
- : combobox_(new Combobox(&combobox_model_)),
- example_shown_(new View),
+ : example_shown_(new View),
status_label_(new Label),
on_close_(std::move(on_close)) {
+ auto combobox_model = std::make_unique<ComboboxModelExampleList>();
+ combobox_model_ = combobox_model.get();
+ combobox_ = new Combobox(std::move(combobox_model));
+
instance_ = this;
combobox_->set_listener(this);
- combobox_model_.SetExamples(std::move(examples));
+ combobox_model_->SetExamples(std::move(examples));
combobox_->ModelChanged();
SetBackground(CreateStandardPanelBackground());
@@ -155,10 +159,10 @@ class ExamplesWindowContents : public WidgetDelegateView,
layout->StartRow(0 /* no expand */, 0);
layout->AddView(combobox_);
- if (combobox_model_.GetItemCount() > 0) {
+ if (combobox_model_->GetItemCount() > 0) {
layout->StartRow(1, 0);
example_shown_->SetLayoutManager(std::make_unique<FillLayout>());
- example_shown_->AddChildView(combobox_model_.GetItemViewAt(0));
+ example_shown_->AddChildView(combobox_model_->GetItemViewAt(0));
layout->AddView(example_shown_);
}
@@ -167,11 +171,7 @@ class ExamplesWindowContents : public WidgetDelegateView,
layout->AddPaddingRow(0, 5);
}
- ~ExamplesWindowContents() override {
- // Delete |combobox_| first as it references |combobox_model_|.
- delete combobox_;
- combobox_ = NULL;
- }
+ ~ExamplesWindowContents() override = default;
// Prints a message in the status area, at the bottom of the window.
void SetStatus(const std::string& status) {
@@ -200,21 +200,22 @@ class ExamplesWindowContents : public WidgetDelegateView,
// ComboboxListener:
void OnPerformAction(Combobox* combobox) override {
DCHECK_EQ(combobox, combobox_);
- DCHECK(combobox->selected_index() < combobox_model_.GetItemCount());
+ DCHECK(combobox->selected_index() < combobox_model_->GetItemCount());
example_shown_->RemoveAllChildViews(false);
- example_shown_->AddChildView(combobox_model_.GetItemViewAt(
- combobox->selected_index()));
+ example_shown_->AddChildView(
+ combobox_model_->GetItemViewAt(combobox->selected_index()));
example_shown_->RequestFocus();
SetStatus(std::string());
Layout();
}
static ExamplesWindowContents* instance_;
- ComboboxModelExampleList combobox_model_;
- Combobox* combobox_;
View* example_shown_;
Label* status_label_;
base::OnceClosure on_close_;
+ Combobox* combobox_ = nullptr;
+ // Owned by |combobox_|.
+ ComboboxModelExampleList* combobox_model_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ExamplesWindowContents);
};
diff --git a/chromium/ui/views/examples/label_example.cc b/chromium/ui/views/examples/label_example.cc
index bdf6644cc79..87189250851 100644
--- a/chromium/ui/views/examples/label_example.cc
+++ b/chromium/ui/views/examples/label_example.cc
@@ -4,6 +4,8 @@
#include "ui/views/examples/label_example.h"
+#include <memory>
+
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -66,10 +68,7 @@ LabelExample::LabelExample()
custom_label_(NULL) {
}
-LabelExample::~LabelExample() {
- // Remove the views first as some reference combobox models.
- container()->RemoveAllChildViews(true);
-}
+LabelExample::~LabelExample() = default;
void LabelExample::CreateExampleView(View* container) {
// A very simple label example, followed by additional helpful examples.
@@ -231,9 +230,8 @@ Combobox* LabelExample::AddCombobox(GridLayout* layout,
int count) {
layout->StartRow(0, 0);
layout->AddView(new Label(base::ASCIIToUTF16(name)));
- ExampleComboboxModel* model = new ExampleComboboxModel(strings, count);
- example_combobox_models_.push_back(base::WrapUnique(model));
- Combobox* combobox = new Combobox(model);
+ Combobox* combobox =
+ new Combobox(std::make_unique<ExampleComboboxModel>(strings, count));
combobox->SetSelectedIndex(0);
combobox->set_listener(this);
layout->AddView(combobox);
diff --git a/chromium/ui/views/examples/label_example.h b/chromium/ui/views/examples/label_example.h
index 87e8e2f44a5..da356115122 100644
--- a/chromium/ui/views/examples/label_example.h
+++ b/chromium/ui/views/examples/label_example.h
@@ -19,8 +19,6 @@ class Label;
namespace examples {
-class ExampleComboboxModel;
-
class VIEWS_EXAMPLES_EXPORT LabelExample : public ExampleBase,
public ButtonListener,
public ComboboxListener,
@@ -55,7 +53,6 @@ class VIEWS_EXAMPLES_EXPORT LabelExample : public ExampleBase,
Textfield* textfield_;
Combobox* alignment_;
Combobox* elide_behavior_;
- std::vector<std::unique_ptr<ExampleComboboxModel>> example_combobox_models_;
Checkbox* multiline_;
Checkbox* shadows_;
Checkbox* selectable_;
diff --git a/chromium/ui/views/examples/layout_example_base.cc b/chromium/ui/views/examples/layout_example_base.cc
new file mode 100644
index 00000000000..8b9805f5daf
--- /dev/null
+++ b/chromium/ui/views/examples/layout_example_base.cc
@@ -0,0 +1,352 @@
+// 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/layout_example_base.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/examples/example_combobox_model.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view_properties.h"
+
+namespace views {
+namespace examples {
+
+namespace {
+
+constexpr int kLayoutExampleVerticalSpacing = 3;
+constexpr int kLayoutExampleLeftPadding = 8;
+constexpr gfx::Size kLayoutExampleDefaultChildSize(180, 90);
+
+// This View holds two other views which consists of a view on the left onto
+// which the BoxLayout is attached for demonstrating its features. The view
+// on the right contains all the various controls which allow the user to
+// interactively control the various features/properties of BoxLayout. Layout()
+// will ensure the left view takes 75% and the right view fills the remaining
+// 25%.
+class FullPanel : public View {
+ public:
+ FullPanel() {}
+ ~FullPanel() override {}
+
+ // View
+ void Layout() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FullPanel);
+};
+
+void FullPanel::Layout() {
+ DCHECK_EQ(child_count(), 2);
+ View* left_panel = child_at(0);
+ View* right_panel = child_at(1);
+ gfx::Rect bounds = GetContentsBounds();
+ left_panel->SetBounds(bounds.x(), bounds.y(), (bounds.width() * 75) / 100,
+ bounds.height());
+ right_panel->SetBounds(left_panel->width(), bounds.y(),
+ bounds.width() - left_panel->width(), bounds.height());
+}
+
+} // namespace
+
+LayoutExampleBase::ChildPanel::ChildPanel(LayoutExampleBase* example,
+ const gfx::Size& preferred_size)
+ : View(), example_(example), preferred_size_(preferred_size) {
+ SetBorder(CreateSolidBorder(1, SK_ColorGRAY));
+ for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i)
+ margin_[i] = CreateTextfield();
+ flex_ = CreateTextfield();
+ flex_->SetText(base::ASCIIToUTF16(""));
+}
+
+LayoutExampleBase::ChildPanel::~ChildPanel() = default;
+
+gfx::Size LayoutExampleBase::ChildPanel::CalculatePreferredSize() const {
+ return preferred_size_;
+}
+
+bool LayoutExampleBase::ChildPanel::OnMousePressed(
+ const ui::MouseEvent& event) {
+ if (event.IsOnlyLeftMouseButton())
+ SetSelected(true);
+ return true;
+}
+
+void LayoutExampleBase::ChildPanel::Layout() {
+ const int kSpacing = 2;
+ if (selected_) {
+ gfx::Rect client = GetContentsBounds();
+ for (unsigned i = 0; i < sizeof(margin_) / sizeof(margin_[0]); ++i) {
+ gfx::Point pos;
+ Textfield* textfield = margin_[i];
+ switch (i) {
+ case 0:
+ pos = gfx::Point((client.width() - textfield->width()) / 2, kSpacing);
+ break;
+ case 1:
+ pos =
+ gfx::Point(kSpacing, (client.height() - textfield->height()) / 2);
+ break;
+ case 2:
+ pos = gfx::Point((client.width() - textfield->width()) / 2,
+ client.height() - textfield->height() - kSpacing);
+ break;
+ case 3:
+ pos = gfx::Point(client.width() - textfield->width() - kSpacing,
+ (client.height() - textfield->height()) / 2);
+ break;
+ default:
+ NOTREACHED();
+ }
+ textfield->SetPosition(pos);
+ }
+ flex_->SetPosition(gfx::Point((client.width() - flex_->width()) / 2,
+ (client.height() - flex_->height()) / 2));
+ }
+}
+
+void LayoutExampleBase::ChildPanel::SetSelected(bool value) {
+ if (value != selected_) {
+ selected_ = value;
+ SetBorder(CreateSolidBorder(1, selected_ ? SK_ColorBLACK : SK_ColorGRAY));
+ if (selected_ && parent()) {
+ for (int i = 0; i < parent()->child_count(); ++i) {
+ View* child = parent()->child_at(i);
+ if (child != this && child->GetGroup() == GetGroup()) {
+ ChildPanel* child_panel = static_cast<ChildPanel*>(child);
+ child_panel->SetSelected(false);
+ }
+ }
+ }
+ for (Textfield* textfield : margin_)
+ textfield->SetVisible(selected_);
+ flex_->SetVisible(selected_);
+ InvalidateLayout();
+ example_->RefreshLayoutPanel(false);
+ }
+}
+
+int LayoutExampleBase::ChildPanel::GetFlex() {
+ int flex;
+ if (base::StringToInt(flex_->text(), &flex))
+ return flex;
+ return -1;
+}
+
+void LayoutExampleBase::ChildPanel::ContentsChanged(
+ Textfield* sender,
+ const base::string16& new_contents) {
+ const gfx::Insets margins = LayoutExampleBase::TextfieldsToInsets(margin_);
+ if (!margins.IsEmpty())
+ this->SetProperty(kMarginsKey, new gfx::Insets(margins));
+ else
+ this->ClearProperty(kMarginsKey);
+ example_->RefreshLayoutPanel(sender == flex_);
+}
+
+Textfield* LayoutExampleBase::ChildPanel::CreateTextfield() {
+ Textfield* textfield = new Textfield();
+ textfield->SetDefaultWidthInChars(3);
+ textfield->SizeToPreferredSize();
+ textfield->SetText(base::ASCIIToUTF16("0"));
+ textfield->set_controller(this);
+ textfield->SetVisible(false);
+ AddChildView(textfield);
+ return textfield;
+}
+
+LayoutExampleBase::LayoutExampleBase(const char* title) : ExampleBase(title) {}
+
+LayoutExampleBase::~LayoutExampleBase() {}
+
+Combobox* LayoutExampleBase::CreateCombobox(const base::string16& label_text,
+ const char* const* items,
+ int count,
+ int* vertical_pos) {
+ Label* label = new Label(label_text);
+ label->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
+ label->SizeToPreferredSize();
+ Combobox* combo_box =
+ new Combobox(std::make_unique<ExampleComboboxModel>(items, count));
+ combo_box->SetPosition(
+ gfx::Point(label->x() + label->width() + kLayoutExampleVerticalSpacing,
+ *vertical_pos));
+ combo_box->SizeToPreferredSize();
+ combo_box->set_listener(this);
+ label->SetSize(gfx::Size(label->width(), combo_box->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(combo_box);
+ *vertical_pos += combo_box->height() + kLayoutExampleVerticalSpacing;
+ return combo_box;
+}
+
+Textfield* LayoutExampleBase::CreateRawTextfield(int vertical_pos,
+ bool add,
+ int* horizontal_pos) {
+ Textfield* text_field = new Textfield();
+ text_field->SetPosition(gfx::Point(*horizontal_pos, vertical_pos));
+ text_field->SetDefaultWidthInChars(3);
+ text_field->SetTextInputType(ui::TEXT_INPUT_TYPE_NUMBER);
+ text_field->SizeToPreferredSize();
+ text_field->SetText(base::ASCIIToUTF16("0"));
+ text_field->set_controller(this);
+ *horizontal_pos += text_field->width() + kLayoutExampleVerticalSpacing;
+ if (add)
+ control_panel_->AddChildView(text_field);
+ return text_field;
+}
+
+Textfield* LayoutExampleBase::CreateTextfield(const base::string16& label_text,
+ int* vertical_pos) {
+ Label* label = new Label(label_text);
+ label->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
+ label->SizeToPreferredSize();
+ int horizontal_pos =
+ label->x() + label->width() + kLayoutExampleVerticalSpacing;
+ Textfield* text_field =
+ CreateRawTextfield(*vertical_pos, false, &horizontal_pos);
+ label->SetSize(gfx::Size(label->width(), text_field->height()));
+ control_panel_->AddChildView(label);
+ control_panel_->AddChildView(text_field);
+ *vertical_pos += text_field->height() + kLayoutExampleVerticalSpacing;
+ return text_field;
+}
+
+void LayoutExampleBase::CreateMarginsTextFields(
+ const base::string16& label_text,
+ Textfield* textfields[4],
+ int* vertical_pos) {
+ textfields[0] = CreateTextfield(label_text, vertical_pos);
+ int center = textfields[0]->x() + textfields[0]->width() / 2;
+ int horizontal_pos = std::max(
+ 0, center - (textfields[0]->width() + kLayoutExampleVerticalSpacing / 2));
+ textfields[1] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
+ textfields[3] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
+ *vertical_pos = textfields[1]->y() + textfields[1]->height() +
+ kLayoutExampleVerticalSpacing;
+ horizontal_pos = textfields[0]->x();
+ textfields[2] = CreateRawTextfield(*vertical_pos, true, &horizontal_pos);
+ *vertical_pos = textfields[2]->y() + textfields[2]->height() +
+ kLayoutExampleVerticalSpacing;
+}
+
+Checkbox* LayoutExampleBase::CreateCheckbox(const base::string16& label_text,
+ int* vertical_pos) {
+ Checkbox* checkbox = new Checkbox(label_text, this);
+ checkbox->SetPosition(gfx::Point(kLayoutExampleLeftPadding, *vertical_pos));
+ checkbox->SizeToPreferredSize();
+ control_panel_->AddChildView(checkbox);
+ *vertical_pos += checkbox->height() + kLayoutExampleVerticalSpacing;
+ return checkbox;
+}
+
+void LayoutExampleBase::CreateExampleView(View* container) {
+ container->SetLayoutManager(std::make_unique<FillLayout>());
+ full_panel_ = new FullPanel();
+ container->AddChildView(full_panel_);
+
+ layout_panel_ = new View();
+ layout_panel_->SetBorder(CreateSolidBorder(1, SK_ColorLTGRAY));
+ full_panel_->AddChildView(layout_panel_);
+ control_panel_ = new View();
+ full_panel_->AddChildView(control_panel_);
+
+ int vertical_pos = kLayoutExampleVerticalSpacing;
+ int horizontal_pos = kLayoutExampleLeftPadding;
+ add_button_ =
+ MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Add"));
+ add_button_->SetPosition(gfx::Point(horizontal_pos, vertical_pos));
+ add_button_->SizeToPreferredSize();
+ control_panel_->AddChildView(add_button_);
+ horizontal_pos += add_button_->width() + kLayoutExampleVerticalSpacing;
+ for (unsigned i = 0;
+ i < sizeof(child_panel_size_) / sizeof(child_panel_size_[0]); ++i) {
+ child_panel_size_[i] =
+ CreateRawTextfield(vertical_pos, true, &horizontal_pos);
+ child_panel_size_[i]->SetY(
+ vertical_pos +
+ (add_button_->height() - child_panel_size_[i]->height()) / 2);
+ }
+ child_panel_size_[0]->SetText(
+ base::IntToString16(kLayoutExampleDefaultChildSize.width()));
+ child_panel_size_[1]->SetText(
+ base::IntToString16(kLayoutExampleDefaultChildSize.height()));
+
+ CreateAdditionalControls(add_button_->y() + add_button_->height() +
+ kLayoutExampleVerticalSpacing);
+}
+
+void LayoutExampleBase::ButtonPressed(Button* sender, const ui::Event& event) {
+ constexpr int kMaxPanels = 5;
+ constexpr int kChildPanelGroup = 100;
+
+ if (sender == add_button_) {
+ if (panel_count_ < kMaxPanels) {
+ ++panel_count_;
+ ChildPanel* panel = new ChildPanel(
+ this,
+ TextfieldsToSize(child_panel_size_, kLayoutExampleDefaultChildSize));
+ panel->SetGroup(kChildPanelGroup);
+ layout_panel_->AddChildView(panel);
+ RefreshLayoutPanel(false);
+ } else {
+ PrintStatus("Only %i panels may be added", kMaxPanels);
+ }
+ } else {
+ ButtonPressedImpl(sender);
+ }
+}
+
+// Default implementation is to do nothing.
+void LayoutExampleBase::ButtonPressedImpl(Button* sender) {}
+
+void LayoutExampleBase::RefreshLayoutPanel(bool update_layout) {
+ if (update_layout)
+ UpdateLayoutManager();
+ layout_panel_->Layout();
+ layout_panel_->SchedulePaint();
+}
+
+gfx::Size LayoutExampleBase::TextfieldsToSize(Textfield* textfields[2],
+ const gfx::Size& default_size) {
+ int width;
+ int height;
+ if (!base::StringToInt(textfields[0]->text(), &width))
+ width = default_size.width();
+ if (!base::StringToInt(textfields[1]->text(), &height))
+ height = default_size.height();
+ return gfx::Size(std::max(0, width), std::max(0, height));
+}
+
+gfx::Insets LayoutExampleBase::TextfieldsToInsets(
+ Textfield* textfields[4],
+ const gfx::Insets& default_insets) {
+ int top;
+ int left;
+ int bottom;
+ int right;
+ if (!base::StringToInt(textfields[0]->text(), &top))
+ top = default_insets.top();
+ if (!base::StringToInt(textfields[1]->text(), &left))
+ left = default_insets.left();
+ if (!base::StringToInt(textfields[2]->text(), &bottom))
+ bottom = default_insets.bottom();
+ if (!base::StringToInt(textfields[3]->text(), &right))
+ right = default_insets.right();
+
+ return gfx::Insets(std::max(0, top), std::max(0, left), std::max(0, bottom),
+ std::max(0, right));
+}
+
+} // namespace examples
+} // namespace views
diff --git a/chromium/ui/views/examples/layout_example_base.h b/chromium/ui/views/examples/layout_example_base.h
new file mode 100644
index 00000000000..e61d626b12d
--- /dev/null
+++ b/chromium/ui/views/examples/layout_example_base.h
@@ -0,0 +1,147 @@
+// 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_LAYOUT_EXAMPLE_BASE_H_
+#define UI_VIEWS_EXAMPLES_LAYOUT_EXAMPLE_BASE_H_
+
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/combobox/combobox_listener.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/examples/example_base.h"
+#include "ui/views/view.h"
+
+namespace views {
+namespace examples {
+
+// Provides an example of a layout manager with arbitrary specific manager and
+// controls. Lays out a sequence of ChildPanels in a view using the layout
+// manager of choice.
+class VIEWS_EXAMPLES_EXPORT LayoutExampleBase : public ExampleBase,
+ public ButtonListener,
+ public ComboboxListener,
+ public TextfieldController {
+ public:
+ // This view is created and added to the left-side view in the FullPanel each
+ // time the "Add" button is pressed. It also will display Textfield controls
+ // when the mouse is pressed over the view. These Textfields allow the user to
+ // interactively set each margin and the "flex" for the given view.
+ class ChildPanel : public View, public TextfieldController {
+ public:
+ ChildPanel(LayoutExampleBase* example, const gfx::Size& preferred_size);
+ ~ChildPanel() override;
+
+ // View
+ gfx::Size CalculatePreferredSize() const override;
+ bool OnMousePressed(const ui::MouseEvent& event) override;
+ void Layout() override;
+
+ void SetSelected(bool value);
+ bool selected() const { return selected_; }
+
+ int GetFlex();
+
+ private:
+ // TextfieldController
+ void ContentsChanged(Textfield* sender,
+ const base::string16& new_contents) override;
+
+ Textfield* CreateTextfield();
+
+ LayoutExampleBase* example_;
+ bool selected_ = false;
+ Textfield* flex_;
+ Textfield* margin_[4];
+ gfx::Size preferred_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildPanel);
+ };
+
+ explicit LayoutExampleBase(const char* title);
+ ~LayoutExampleBase() override;
+
+ // Force the box_layout_panel_ to layout and repaint.
+ void RefreshLayoutPanel(bool update_layout);
+
+ static gfx::Size TextfieldsToSize(
+ Textfield* textfields[2],
+ const gfx::Size& default_size = gfx::Size());
+ static gfx::Insets TextfieldsToInsets(
+ Textfield* textfields[4],
+ const gfx::Insets& default_insets = gfx::Insets());
+
+ protected:
+ View* layout_panel() { return layout_panel_; }
+
+ // Creates a Combobox with a label with |label_text| to the left. Adjust
+ // |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
+ Combobox* CreateCombobox(const base::string16& label_text,
+ const char* const* items,
+ int count,
+ int* vertical_pos);
+
+ // Creates just a Textfield at the current position of |horizontal_pos| and
+ // |vertical_pos|. Update |horizontal_pos| to |horizontal_pos| +
+ // text_field->width() + kSpacing.
+ Textfield* CreateRawTextfield(int vertical_pos,
+ bool add,
+ int* horizontal_pos);
+
+ // Creates a Textfield with a label with |label_text| to the left. Adjust
+ // |vertical_pos| to |vertical_pos| + combo_box->height() + kSpacing.
+ Textfield* CreateTextfield(const base::string16& label_text,
+ int* vertical_pos);
+
+ // Creates a set of labeled Textfields with |label_text|, and four text fields
+ // arranged at compass points representing a set of insets. |vertical_pos| is
+ // updated to the bottom of the last Textfield + kSpacing, and |textfields| is
+ // populated with the fieds that are created.
+ void CreateMarginsTextFields(const base::string16& label_text,
+ Textfield* textfields[4],
+ int* vertical_pos);
+
+ // Creates a Checkbox with label |label_text|. Adjust |vertical_pos| to
+ // |vertical_pos| + checkbox->height() + kSpacing.
+ Checkbox* CreateCheckbox(const base::string16& label_text, int* vertical_pos);
+
+ // ButtonListener:
+ // Be sure to call LayoutExampleBase::ButtonPressed() to ensure the "add"
+ // button works correctly.
+ void ButtonPressed(Button* sender, const ui::Event& event) final;
+
+ // ExampleBase:
+ // Be sure to call LayoutExampleBase::CreateExampleView() to ensure default
+ // controls are created correctly.
+ void CreateExampleView(View* container) final;
+
+ // Called by CreateExampleView() to create any additional controls required by
+ // the specific layout. |vertical_start_pos| tells the control where to start
+ // placing new controls (i.e. the bottom of the existing common controls).
+ virtual void CreateAdditionalControls(int vertical_start_pos) = 0;
+
+ // Handles buttons added by derived classes after button handling for
+ // common controls is done.
+ virtual void ButtonPressedImpl(Button* sender);
+
+ // Performs layout-specific update of the layout manager.
+ virtual void UpdateLayoutManager() = 0;
+
+ private:
+ View* full_panel_ = nullptr;
+ View* layout_panel_ = nullptr;
+ View* control_panel_ = nullptr;
+ LabelButton* add_button_ = nullptr;
+ Textfield* child_panel_size_[2] = {nullptr, nullptr};
+ int panel_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(LayoutExampleBase);
+};
+
+} // namespace examples
+} // namespace views
+
+#endif // UI_VIEWS_EXAMPLES_LAYOUT_EXAMPLE_BASE_H_
diff --git a/chromium/ui/views/examples/menu_example.cc b/chromium/ui/views/examples/menu_example.cc
index 3c2713a432c..acc199a7aee 100644
--- a/chromium/ui/views/examples/menu_example.cc
+++ b/chromium/ui/views/examples/menu_example.cc
@@ -171,10 +171,9 @@ void ExampleMenuModel::ExecuteCommand(int command_id, int event_flags) {
// ExampleMenuButton -----------------------------------------------------------
ExampleMenuButton::ExampleMenuButton(const base::string16& test)
- : MenuButton(test, this, true) {}
+ : MenuButton(test, this) {}
-ExampleMenuButton::~ExampleMenuButton() {
-}
+ExampleMenuButton::~ExampleMenuButton() {}
void ExampleMenuButton::OnMenuButtonClicked(MenuButton* source,
const gfx::Point& point,
diff --git a/chromium/ui/views/examples/text_example.cc b/chromium/ui/views/examples/text_example.cc
index 11db9591b83..c37608c4f2e 100644
--- a/chromium/ui/views/examples/text_example.cc
+++ b/chromium/ui/views/examples/text_example.cc
@@ -4,6 +4,8 @@
#include "ui/views/examples/text_example.h"
+#include <memory>
+
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/canvas.h"
@@ -129,10 +131,7 @@ class TextExample::TextExampleView : public View {
TextExample::TextExample() : ExampleBase("Text Styles") {}
-TextExample::~TextExample() {
- // Remove the views first as some reference combobox models.
- container()->RemoveAllChildViews(true);
-}
+TextExample::~TextExample() = default;
Checkbox* TextExample::AddCheckbox(GridLayout* layout, const char* name) {
Checkbox* checkbox = new Checkbox(base::ASCIIToUTF16(name), this);
@@ -146,9 +145,8 @@ Combobox* TextExample::AddCombobox(GridLayout* layout,
int count) {
layout->StartRow(0, 0);
layout->AddView(new Label(base::ASCIIToUTF16(name)));
- example_combobox_model_.push_back(
- std::make_unique<ExampleComboboxModel>(strings, count));
- Combobox* combobox = new Combobox(example_combobox_model_.back().get());
+ Combobox* combobox =
+ new Combobox(std::make_unique<ExampleComboboxModel>(strings, count));
combobox->SetSelectedIndex(0);
combobox->set_listener(this);
layout->AddView(combobox, kNumColumns - 1, 1);
@@ -204,7 +202,8 @@ void TextExample::ButtonPressed(Button* button, const ui::Event& event) {
int flags = text_view_->flags();
int style = text_view_->GetStyle();
SetFlagFromCheckbox(multiline_checkbox_, &flags, gfx::Canvas::MULTI_LINE);
- SetFlagFromCheckbox(break_checkbox_, &flags, gfx::Canvas::CHARACTER_BREAK);
+ SetFlagFromCheckbox(break_checkbox_, &flags,
+ gfx::Canvas::CHARACTER_BREAKABLE);
SetFlagFromCheckbox(italic_checkbox_, &style, gfx::Font::ITALIC);
SetFlagFromCheckbox(underline_checkbox_, &style, gfx::Font::UNDERLINE);
text_view_->set_flags(flags);
diff --git a/chromium/ui/views/examples/text_example.h b/chromium/ui/views/examples/text_example.h
index e26b0439dd3..fc0f5c424f0 100644
--- a/chromium/ui/views/examples/text_example.h
+++ b/chromium/ui/views/examples/text_example.h
@@ -19,8 +19,6 @@ class GridLayout;
namespace examples {
-class ExampleComboboxModel;
-
class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase,
public ButtonListener,
public ComboboxListener {
@@ -78,10 +76,6 @@ class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase,
// Check box to enable/disable underline style.
Checkbox* underline_checkbox_;
- // We create a model for each of the combobox, so we need to keep them
- // around until destruction time.
- std::vector<std::unique_ptr<ExampleComboboxModel>> example_combobox_model_;
-
DISALLOW_COPY_AND_ASSIGN(TextExample);
};
diff --git a/chromium/ui/views/examples/webview_example.cc b/chromium/ui/views/examples/webview_example.cc
index f23b646fd55..3910b8760b1 100644
--- a/chromium/ui/views/examples/webview_example.cc
+++ b/chromium/ui/views/examples/webview_example.cc
@@ -31,10 +31,10 @@ void WebViewExample::CreateExampleView(View* container) {
webview_->GetWebContents()->Focus();
}
-void WebViewExample::HandleKeyboardEvent(
+bool WebViewExample::HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) {
- unhandled_keyboard_event_handler_.HandleKeyboardEvent(
+ return unhandled_keyboard_event_handler_.HandleKeyboardEvent(
event, webview_->GetFocusManager());
}
diff --git a/chromium/ui/views/examples/webview_example.h b/chromium/ui/views/examples/webview_example.h
index f04c87e8403..600feaa1970 100644
--- a/chromium/ui/views/examples/webview_example.h
+++ b/chromium/ui/views/examples/webview_example.h
@@ -28,7 +28,7 @@ class WebViewExample : public ExampleBase, public content::WebContentsDelegate {
void CreateExampleView(View* container) override;
// content::WebContentsDelegate:
- void HandleKeyboardEvent(
+ bool HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
diff --git a/chromium/ui/views/focus/focus_manager.cc b/chromium/ui/views/focus/focus_manager.cc
index faded394493..85c803994b2 100644
--- a/chromium/ui/views/focus/focus_manager.cc
+++ b/chromium/ui/views/focus/focus_manager.cc
@@ -68,8 +68,11 @@ bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
return false;
}
- if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
+ if ((arrow_key_traversal_enabled_ ||
+ arrow_key_traversal_enabled_for_widget_) &&
+ ProcessArrowKeyTraversal(event)) {
return false;
+ }
// Intercept arrow key messages to switch between grouped views.
bool is_left = key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP;
diff --git a/chromium/ui/views/focus/focus_manager.h b/chromium/ui/views/focus/focus_manager.h
index d36ac497473..3d8d3f37566 100644
--- a/chromium/ui/views/focus/focus_manager.h
+++ b/chromium/ui/views/focus/focus_manager.h
@@ -75,7 +75,7 @@ namespace ui {
class Accelerator;
class AcceleratorTarget;
class KeyEvent;
-}
+} // namespace ui
namespace views {
@@ -176,9 +176,7 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
}
// Get the reason why the focus most recently changed.
- FocusChangeReason focus_change_reason() const {
- return focus_change_reason_;
- }
+ FocusChangeReason focus_change_reason() const { return focus_change_reason_; }
// Clears the focused view. The window associated with the top root view gets
// the native focus (so we still get keyboard events).
@@ -297,6 +295,13 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
return arrow_key_traversal_enabled_;
}
+ // TODO(weidongg): converts compatible usages of
+ // |arrow_key_traversal_enabled_| to this (https://crbug.com/899431).
+ // Similar to above, but only for the widget that owns this FocusManager.
+ void set_arrow_key_traversal_enabled_for_widget(bool enabled) {
+ arrow_key_traversal_enabled_for_widget_ = enabled;
+ }
+
// Returns the next focusable view. Traversal starts at |starting_view|. If
// |starting_view| is NULL |starting_widget| is consuled to determine which
// Widget to start from. See
@@ -334,9 +339,13 @@ class VIEWS_EXPORT FocusManager : public ViewObserver {
// ViewObserver:
void OnViewIsDeleting(View* view) override;
- // Whether arrow key traversal is enabled.
+ // Whether arrow key traversal is enabled globally.
static bool arrow_key_traversal_enabled_;
+ // Whether arrow key traversal is enabled for all widgets under the top-level
+ // widget that owns the FocusManager.
+ bool arrow_key_traversal_enabled_for_widget_ = false;
+
// The top-level Widget this FocusManager is associated with.
Widget* widget_;
diff --git a/chromium/ui/views/focus/focus_manager_unittest.cc b/chromium/ui/views/focus/focus_manager_unittest.cc
index 10da1cd7fb3..0ee56a6217d 100644
--- a/chromium/ui/views/focus/focus_manager_unittest.cc
+++ b/chromium/ui/views/focus/focus_manager_unittest.cc
@@ -154,14 +154,14 @@ TEST_F(FocusManagerTest, WidgetFocusChangeListener) {
gfx::NativeView native_view1 = widget1->GetNativeView();
test::WidgetTest::SimulateNativeActivate(widget1.get());
ASSERT_EQ(2u, widget_listener.focus_changes().size());
- EXPECT_EQ(nullptr, widget_listener.focus_changes()[0]);
+ EXPECT_EQ(gfx::kNullNativeView, widget_listener.focus_changes()[0]);
EXPECT_EQ(native_view1, widget_listener.focus_changes()[1]);
widget_listener.ClearFocusChanges();
gfx::NativeView native_view2 = widget2->GetNativeView();
test::WidgetTest::SimulateNativeActivate(widget2.get());
ASSERT_EQ(2u, widget_listener.focus_changes().size());
- EXPECT_EQ(nullptr, widget_listener.focus_changes()[0]);
+ EXPECT_EQ(gfx::kNullNativeView, widget_listener.focus_changes()[0]);
EXPECT_EQ(native_view2, widget_listener.focus_changes()[1]);
}
@@ -931,11 +931,21 @@ TEST_F(FocusManagerTest, NavigateIntoAnchoredDialog) {
GetWidget()->GetRootView()->AddChildView(parent3);
GetWidget()->GetRootView()->AddChildView(parent4);
+ // Add an unfocusable child view to the dialog anchor view. This is a
+ // regression test that makes sure focus is able to navigate past unfocusable
+ // children and try to go into the anchored dialog. |kAnchoredDialogKey| was
+ // previously not checked if a recursive search to find a focusable child view
+ // was attempted (and failed), so the dialog would previously be skipped.
+ parent3->AddChildView(new View());
+
BubbleDialogDelegateView* bubble_delegate =
new TestBubbleDialogDelegateView(parent3);
test::WidgetTest::WidgetAutoclosePtr bubble_widget(
BubbleDialogDelegateView::CreateBubble(bubble_delegate));
- bubble_delegate->EnableFocusTraversalFromAnchorView();
+ bubble_widget->SetFocusTraversableParent(
+ bubble_delegate->anchor_widget()->GetFocusTraversable());
+
+ bubble_widget->SetFocusTraversableParentView(parent3);
View* child1 = new View();
View* child2 = new View();
child1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -996,7 +1006,9 @@ TEST_F(FocusManagerTest, AnchoredDialogOnContainerView) {
new TestBubbleDialogDelegateView(parent_group);
test::WidgetTest::WidgetAutoclosePtr bubble_widget(
BubbleDialogDelegateView::CreateBubble(bubble_delegate));
- bubble_delegate->EnableFocusTraversalFromAnchorView();
+ bubble_widget->SetFocusTraversableParent(
+ bubble_delegate->anchor_widget()->GetFocusTraversable());
+ bubble_widget->SetFocusTraversableParentView(parent_group);
View* child1 = new View();
View* child2 = new View();
child1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -1060,7 +1072,9 @@ TEST_F(FocusManagerTest, AnchoredDialogInDesktopNativeWidgetAura) {
bubble_delegate->UseNativeWidgetAura();
test::WidgetTest::WidgetAutoclosePtr bubble_widget(
BubbleDialogDelegateView::CreateBubble(bubble_delegate));
- bubble_delegate->EnableFocusTraversalFromAnchorView();
+ bubble_widget->SetFocusTraversableParent(
+ bubble_delegate->anchor_widget()->GetFocusTraversable());
+ bubble_widget->SetFocusTraversableParentView(parent2);
View* child = new View();
child->SetFocusBehavior(View::FocusBehavior::ALWAYS);
bubble_widget->GetRootView()->AddChildView(child);
diff --git a/chromium/ui/views/focus/focus_search.cc b/chromium/ui/views/focus/focus_search.cc
index c0e33176e20..8351f8f9225 100644
--- a/chromium/ui/views/focus/focus_search.cc
+++ b/chromium/ui/views/focus/focus_search.cc
@@ -183,15 +183,14 @@ View* FocusSearch::FindNextFocusableViewImpl(
focus_traversable_view);
if (v || *focus_traversable)
return v;
- } else {
- // Check to see if we should navigate into a dialog anchored at this view.
- BubbleDialogDelegateView* bubble =
- starting_view->GetProperty(kAnchoredDialogKey);
- if (bubble) {
- *focus_traversable = bubble->GetWidget()->GetFocusTraversable();
- *focus_traversable_view = starting_view;
- return nullptr;
- }
+ }
+ // Check to see if we should navigate into a dialog anchored at this view.
+ BubbleDialogDelegateView* bubble =
+ starting_view->GetProperty(kAnchoredDialogKey);
+ if (bubble) {
+ *focus_traversable = bubble->GetWidget()->GetFocusTraversable();
+ *focus_traversable_view = starting_view;
+ return nullptr;
}
}
diff --git a/chromium/ui/views/layout/box_layout.h b/chromium/ui/views/layout/box_layout.h
index 653d810eb9e..baa4c7e738f 100644
--- a/chromium/ui/views/layout/box_layout.h
+++ b/chromium/ui/views/layout/box_layout.h
@@ -15,7 +15,7 @@
namespace gfx {
class Rect;
class Size;
-}
+} // namespace gfx
namespace views {
@@ -129,6 +129,10 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
minimum_cross_axis_size_ = size;
}
+ void set_between_child_spacing(int spacing) {
+ between_child_spacing_ = spacing;
+ }
+
// Sets the flex weight for the given |view|. Using the preferred size as
// the basis, free space along the main axis is distributed to views in the
// ratio of their flex weights. Similarly, if the views will overflow the
@@ -307,7 +311,7 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
gfx::Insets inside_border_insets_;
// Spacing to put in between child views.
- const int between_child_spacing_;
+ int between_child_spacing_;
// The alignment of children in the main axis. This is
// MAIN_AXIS_ALIGNMENT_START by default.
@@ -335,6 +339,6 @@ class VIEWS_EXPORT BoxLayout : public LayoutManager {
DISALLOW_IMPLICIT_CONSTRUCTORS(BoxLayout);
};
-} // namespace views
+} // namespace views
#endif // UI_VIEWS_LAYOUT_BOX_LAYOUT_H_
diff --git a/chromium/ui/views/layout/layout_manager.cc b/chromium/ui/views/layout/layout_manager.cc
index eb91c183149..877a9f31139 100644
--- a/chromium/ui/views/layout/layout_manager.cc
+++ b/chromium/ui/views/layout/layout_manager.cc
@@ -14,6 +14,20 @@ LayoutManager::~LayoutManager() {
void LayoutManager::Installed(View* host) {
}
+void LayoutManager::InvalidateLayout() {}
+
+gfx::Size LayoutManager::GetMinimumSize(const View* host) const {
+ // Fall back to using preferred size if no minimum size calculation is
+ // available (e.g. legacy layout managers).
+ //
+ // Ideally we'd just call GetPreferredSize() on ourselves here, but because
+ // some legacy views with layout managers override GetPreferredSize(), we need
+ // to call GetPreferredSize() on the host view instead. The default
+ // views::View behavior will be to call GetPreferredSize() on this layout
+ // manager, so the fallback behavior in all other cases is as expected.
+ return host->GetPreferredSize();
+}
+
int LayoutManager::GetPreferredHeightForWidth(const View* host,
int width) const {
return GetPreferredSize(host).height();
diff --git a/chromium/ui/views/layout/layout_manager.h b/chromium/ui/views/layout/layout_manager.h
index 5e4a1e417e0..ee1bfda10c0 100644
--- a/chromium/ui/views/layout/layout_manager.h
+++ b/chromium/ui/views/layout/layout_manager.h
@@ -34,16 +34,27 @@ class VIEWS_EXPORT LayoutManager {
// Notification that this LayoutManager has been installed on |host|.
virtual void Installed(View* host);
+ // For layout managers that can cache layout data, it's useful to let the
+ // layout manager know that its current layout might not be valid.
+ // TODO(dfried): consider if we should include some default behavior (like a
+ // rolling layout counter).
+ virtual void InvalidateLayout();
+
// Called by View::Layout() to position and size the children of |host|.
// Generally this queries |host| for its size and positions and sizes the
// children in a LayoutManager specific way.
virtual void Layout(View* host) = 0;
- // Return the preferred size, which is typically the size needed to give each
+ // Returns the preferred size, which is typically the size needed to give each
// child of |host| its preferred size. Generally this is calculated using the
// View::CalculatePreferredSize() on each of the children of |host|.
virtual gfx::Size GetPreferredSize(const View* host) const = 0;
+ // Returns the minimum size, which defaults to the preferred size. Layout
+ // managers with the ability to collapse or hide child views may override this
+ // behavior.
+ virtual gfx::Size GetMinimumSize(const View* host) const;
+
// Return the preferred height for a particular width. Generally this is
// calculated using View::GetHeightForWidth() or
// View::CalculatePreferredSize() on each of the children of |host|. Override
diff --git a/chromium/ui/views/layout/layout_provider.cc b/chromium/ui/views/layout/layout_provider.cc
index 310d695c175..63ea37d20bc 100644
--- a/chromium/ui/views/layout/layout_provider.cc
+++ b/chromium/ui/views/layout/layout_provider.cc
@@ -143,19 +143,18 @@ gfx::Insets LayoutProvider::GetDialogInsetsForContentType(
int LayoutProvider::GetCornerRadiusMetric(EmphasisMetric emphasis_metric,
const gfx::Size& size) const {
- const bool is_touch =
- ui::MaterialDesignController::IsTouchOptimizedUiEnabled();
+ const bool touch_ui = ui::MaterialDesignController::touch_ui();
switch (emphasis_metric) {
case views::EMPHASIS_NONE:
NOTREACHED();
return 0;
case EMPHASIS_LOW:
case EMPHASIS_MEDIUM:
- return is_touch ? 4 : 2;
+ return touch_ui ? 4 : 2;
case EMPHASIS_HIGH:
- return is_touch ? 8 : 4;
+ return touch_ui ? 8 : 4;
case EMPHASIS_MAXIMUM:
- return is_touch ? std::min(size.width(), size.height()) / 2 : 4;
+ return touch_ui ? std::min(size.width(), size.height()) / 2 : 4;
}
}
diff --git a/chromium/ui/views/linux_ui/linux_ui.cc b/chromium/ui/views/linux_ui/linux_ui.cc
index 9430addaabe..d3dc2f9658b 100644
--- a/chromium/ui/views/linux_ui/linux_ui.cc
+++ b/chromium/ui/views/linux_ui/linux_ui.cc
@@ -5,7 +5,7 @@
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
-#include "ui/gfx/linux_font_delegate.h"
+#include "ui/gfx/skia_font_delegate.h"
#include "ui/shell_dialogs/shell_dialog_linux.h"
namespace {
@@ -20,7 +20,7 @@ void LinuxUI::SetInstance(LinuxUI* instance) {
delete g_linux_ui;
g_linux_ui = instance;
LinuxInputMethodContextFactory::SetInstance(instance);
- LinuxFontDelegate::SetInstance(instance);
+ SkiaFontDelegate::SetInstance(instance);
ShellDialogLinux::SetInstance(instance);
ui::SetTextEditKeyBindingsDelegate(instance);
}
diff --git a/chromium/ui/views/linux_ui/linux_ui.h b/chromium/ui/views/linux_ui/linux_ui.h
index 759d4ab03f0..bebe2a6fe06 100644
--- a/chromium/ui/views/linux_ui/linux_ui.h
+++ b/chromium/ui/views/linux_ui/linux_ui.h
@@ -12,7 +12,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
#include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
-#include "ui/gfx/linux_font_delegate.h"
+#include "ui/gfx/skia_font_delegate.h"
#include "ui/shell_dialogs/shell_dialog_linux.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/features.h"
@@ -58,7 +58,7 @@ class NavButtonProvider;
// Adapter class with targets to render like different toolkits. Set by any
// project that wants to do linux desktop native rendering.
class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
- public gfx::LinuxFontDelegate,
+ public gfx::SkiaFontDelegate,
public ui::ShellDialogLinux,
public ui::TextEditKeyBindingsDelegateAuraLinux {
public:
@@ -130,10 +130,12 @@ class VIEWS_EXPORT LinuxUI : public ui::LinuxInputMethodContextFactory,
// Checks for platform support for status icons.
virtual bool IsStatusIconSupported() const = 0;
- // Create a native status icon.
+ // Create a native status icon. The id_prefix is used to distinguish Chrome's
+ // status icons from other apps' status icons, and should be unique.
virtual std::unique_ptr<StatusIconLinux> CreateLinuxStatusIcon(
const gfx::ImageSkia& image,
- const base::string16& tool_tip) const = 0;
+ const base::string16& tool_tip,
+ const char* id_prefix) const = 0;
// Returns the icon for a given content type from the icon theme.
// TODO(davidben): Add an observer for the theme changing, so we can drop the
diff --git a/chromium/ui/views/mouse_watcher.cc b/chromium/ui/views/mouse_watcher.cc
index 5a91062a11b..713e15a73ad 100644
--- a/chromium/ui/views/mouse_watcher.cc
+++ b/chromium/ui/views/mouse_watcher.cc
@@ -13,7 +13,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
-#include "ui/events/event_handler.h"
+#include "ui/events/event_observer.h"
#include "ui/events/event_utils.h"
#include "ui/events/platform_event.h"
#include "ui/views/event_monitor.h"
@@ -24,16 +24,19 @@ namespace views {
// the listener is notified.
const int kNotifyListenerTimeMs = 300;
-class MouseWatcher::Observer : public ui::EventHandler {
+class MouseWatcher::Observer : public ui::EventObserver {
public:
Observer(MouseWatcher* mouse_watcher, gfx::NativeWindow window)
- : mouse_watcher_(mouse_watcher),
- event_monitor_(EventMonitor::CreateApplicationMonitor(this, window)),
- notify_listener_factory_(this) {}
+ : mouse_watcher_(mouse_watcher), notify_listener_factory_(this) {
+ event_monitor_ = EventMonitor::CreateApplicationMonitor(
+ this, window,
+ {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_MOVED, ui::ET_MOUSE_EXITED,
+ ui::ET_MOUSE_DRAGGED});
+ }
- // ui::EventHandler implementation:
- void OnMouseEvent(ui::MouseEvent* event) override {
- switch (event->type()) {
+ // ui::EventObserver:
+ void OnEvent(const ui::Event& event) override {
+ switch (event.type()) {
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_DRAGGED:
HandleMouseEvent(MouseWatcherHost::MOUSE_MOVE);
@@ -45,6 +48,7 @@ class MouseWatcher::Observer : public ui::EventHandler {
HandleMouseEvent(MouseWatcherHost::MOUSE_PRESS);
break;
default:
+ NOTREACHED();
break;
}
}
@@ -92,11 +96,9 @@ class MouseWatcher::Observer : public ui::EventHandler {
DISALLOW_COPY_AND_ASSIGN(Observer);
};
-MouseWatcherListener::~MouseWatcherListener() {
-}
+MouseWatcherListener::~MouseWatcherListener() = default;
-MouseWatcherHost::~MouseWatcherHost() {
-}
+MouseWatcherHost::~MouseWatcherHost() = default;
MouseWatcher::MouseWatcher(std::unique_ptr<MouseWatcherHost> host,
MouseWatcherListener* listener)
@@ -105,8 +107,7 @@ MouseWatcher::MouseWatcher(std::unique_ptr<MouseWatcherHost> host,
notify_on_exit_time_(
base::TimeDelta::FromMilliseconds(kNotifyListenerTimeMs)) {}
-MouseWatcher::~MouseWatcher() {
-}
+MouseWatcher::~MouseWatcher() = default;
void MouseWatcher::Start(gfx::NativeWindow window) {
if (!is_observing())
diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn
index 883a69b8bbb..8740e56c70d 100644
--- a/chromium/ui/views/mus/BUILD.gn
+++ b/chromium/ui/views/mus/BUILD.gn
@@ -6,7 +6,6 @@ import("//build/config/features.gni")
import("//build/config/jumbo.gni")
import("//build/config/ui.gni")
import("//services/catalog/public/tools/catalog.gni")
-import("//services/service_manager/public/cpp/service.gni")
import("//services/service_manager/public/service_manifest.gni")
import("//testing/test.gni")
import("//tools/grit/repack.gni")
@@ -30,8 +29,6 @@ jumbo_component("mus") {
"mus_property_mirror.h",
"mus_views_delegate.cc",
"mus_views_delegate.h",
- "pointer_watcher_event_router.cc",
- "pointer_watcher_event_router.h",
"screen_mus.cc",
"screen_mus.h",
"screen_mus_delegate.h",
@@ -156,7 +153,6 @@ test("views_mus_unittests") {
"ax_remote_host_unittest.cc",
"ax_tree_source_mus_unittest.cc",
"desktop_window_tree_host_mus_unittest.cc",
- "pointer_watcher_event_router_unittest.cc",
"run_all_unittests_mus.cc",
"screen_mus_unittest.cc",
]
@@ -172,6 +168,7 @@ test("views_mus_unittests") {
"//cc",
"//net",
"//services/ws/public/mojom",
+ "//services/ws/test_ws:mojom",
"//skia",
"//testing/gtest",
"//third_party/icu",
diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc
index c6c4966ef68..97747a0026e 100644
--- a/chromium/ui/views/mus/aura_init.cc
+++ b/chromium/ui/views/mus/aura_init.cc
@@ -53,10 +53,7 @@ bool AuraInit::Init(const InitParams& params) {
mus_params.create_wm_state = true;
mus_params.use_accessibility_host = params.use_accessibility_host;
mus_client_ = std::make_unique<MusClient>(mus_params);
- // MaterialDesignController may have initialized already (such as happens
- // in the utility process).
- if (!ui::MaterialDesignController::is_mode_initialized())
- ui::MaterialDesignController::Initialize();
+ ui::MaterialDesignController::Initialize();
if (!InitializeResources(params))
return false;
diff --git a/chromium/ui/views/mus/ax_remote_host.cc b/chromium/ui/views/mus/ax_remote_host.cc
index 01511da2296..8c6eb24c412 100644
--- a/chromium/ui/views/mus/ax_remote_host.cc
+++ b/chromium/ui/views/mus/ax_remote_host.cc
@@ -18,6 +18,7 @@
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_event_manager.h"
#include "ui/views/mus/ax_tree_source_mus.h"
#include "ui/views/mus/mus_client.h"
#include "ui/views/view.h"
@@ -30,6 +31,7 @@ using display::Screen;
namespace views {
AXRemoteHost::AXRemoteHost() {
+ AXEventManager::Get()->AddObserver(this);
AXAuraObjCache::GetInstance()->SetDelegate(this);
}
@@ -37,6 +39,7 @@ AXRemoteHost::~AXRemoteHost() {
if (widget_)
StopMonitoringWidget();
AXAuraObjCache::GetInstance()->SetDelegate(nullptr);
+ AXEventManager::Get()->RemoveObserver(this);
}
void AXRemoteHost::Init(service_manager::Connector* connector) {
@@ -98,22 +101,6 @@ void AXRemoteHost::StopMonitoringWidget() {
tree_source_.reset();
}
-void AXRemoteHost::HandleEvent(View* view, ax::mojom::Event event_type) {
- if (!enabled_)
- return;
-
- 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);
-}
-
void AXRemoteHost::OnAutomationEnabled(bool enabled) {
if (enabled)
Enable();
@@ -173,6 +160,19 @@ void AXRemoteHost::OnEvent(AXAuraObjWrapper* aura_obj,
SendEvent(aura_obj, event_type);
}
+void AXRemoteHost::OnViewEvent(View* view, ax::mojom::Event event_type) {
+ CHECK(view);
+
+ if (!enabled_)
+ 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);
+}
+
void AXRemoteHost::FlushForTesting() {
ax_host_ptr_.FlushForTesting();
}
@@ -226,12 +226,12 @@ void AXRemoteHost::Disable() {
void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
ax::mojom::Event event_type) {
DCHECK(aura_obj);
- if (!enabled_ || !widget_)
+ // Early return when this host is disabled or only partially initialized.
+ // This roughly matches the behavior in AutomationManagerAura::SendEvent.
+ // Toggling ChromeVox off does not disable the host, etc: crbug.com/910224
+ if (!enabled_ || !widget_ || !tree_serializer_ || !tree_source_)
return;
- DCHECK(tree_source_);
- DCHECK(tree_serializer_);
-
ui::AXTreeUpdate update;
if (!tree_serializer_->SerializeChanges(aura_obj, &update)) {
LOG(ERROR) << "Unable to serialize accessibility tree.";
@@ -250,7 +250,7 @@ void AXRemoteHost::SendEvent(AXAuraObjWrapper* aura_obj,
}
ui::AXEvent event;
- event.id = aura_obj->GetUniqueId().Get();
+ event.id = aura_obj->GetUniqueId();
event.event_type = event_type;
// Other fields are not used.
diff --git a/chromium/ui/views/mus/ax_remote_host.h b/chromium/ui/views/mus/ax_remote_host.h
index bb432ba5073..f9db944d5d2 100644
--- a/chromium/ui/views/mus/ax_remote_host.h
+++ b/chromium/ui/views/mus/ax_remote_host.h
@@ -15,6 +15,7 @@
#include "ui/accessibility/mojom/ax_host.mojom.h"
#include "ui/display/display_observer.h"
#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_event_observer.h"
#include "ui/views/mus/mus_export.h"
#include "ui/views/widget/widget_observer.h"
@@ -40,7 +41,8 @@ class Widget;
class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
public WidgetObserver,
public display::DisplayObserver,
- public AXAuraObjCache::Delegate {
+ public AXAuraObjCache::Delegate,
+ public AXEventObserver {
public:
AXRemoteHost();
~AXRemoteHost() override;
@@ -56,9 +58,6 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void StartMonitoringWidget(Widget* widget);
void StopMonitoringWidget();
- // Handles an event fired upon a |view|.
- void HandleEvent(View* view, ax::mojom::Event event_type);
-
// ax::mojom::AXRemoteHost:
void OnAutomationEnabled(bool enabled) override;
void PerformAction(const ui::AXActionData& action) override;
@@ -76,6 +75,9 @@ class VIEWS_MUS_EXPORT AXRemoteHost : public ax::mojom::AXRemoteHost,
void OnEvent(AXAuraObjWrapper* aura_obj,
ax::mojom::Event event_type) override;
+ // AXEventObserver:
+ void OnViewEvent(View* view, ax::mojom::Event event_type) override;
+
void FlushForTesting();
Widget* widget_for_testing() { return widget_; }
diff --git a/chromium/ui/views/mus/ax_remote_host_unittest.cc b/chromium/ui/views/mus/ax_remote_host_unittest.cc
index d6620cf9b2a..934dcfe3ed5 100644
--- a/chromium/ui/views/mus/ax_remote_host_unittest.cc
+++ b/chromium/ui/views/mus/ax_remote_host_unittest.cc
@@ -117,8 +117,9 @@ AXRemoteHost* CreateRemote(TestAXHostService* service) {
remote->InitForTesting(service->CreateInterfacePtr());
remote->FlushForTesting();
// Install the AXRemoteHost on MusClient so it monitors Widget creation.
+ AXRemoteHost* remote_raw = remote.get();
MusClientTestApi::SetAXRemoteHost(std::move(remote));
- return MusClient::Get()->ax_remote_host();
+ return remote_raw;
}
std::unique_ptr<Widget> CreateTestWidget() {
@@ -193,7 +194,7 @@ TEST_F(AXRemoteHostTest, SendEventOnViewWithNoWidget) {
// Create a view that is not yet associated with the widget.
views::View view;
- remote->HandleEvent(&view, ax::mojom::Event::kLocationChanged);
+ remote->OnViewEvent(&view, ax::mojom::Event::kLocationChanged);
// No crash.
}
@@ -315,7 +316,8 @@ TEST_F(AXRemoteHostTest, ScaleFactor) {
// Widget transform is scaled by a factor of 2.
ASSERT_FALSE(service.last_updates_.empty());
- gfx::Transform* transform = service.last_updates_[0].nodes[0].transform.get();
+ gfx::Transform* transform =
+ service.last_updates_[0].nodes[0].relative_bounds.transform.get();
ASSERT_TRUE(transform);
EXPECT_TRUE(transform->IsScale2d());
EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), transform->Scale2d());
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.cc b/chromium/ui/views/mus/ax_tree_source_mus.cc
index 6199fb3cabf..842a32f9969 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus.cc
@@ -4,47 +4,37 @@
#include "ui/views/mus/ax_tree_source_mus.h"
+#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/transform.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
-#include "ui/views/mus/ax_remote_host.h"
namespace views {
AXTreeSourceMus::AXTreeSourceMus(AXAuraObjWrapper* root,
- const ui::AXTreeID& tree_id)
- : root_(root), tree_id_(tree_id) {
- DCHECK(root_);
- DCHECK_NE(tree_id_, ui::AXTreeIDUnknown());
+ const ui::AXTreeID& tree_id) {
+ Init(root, tree_id);
}
AXTreeSourceMus::~AXTreeSourceMus() = default;
-bool AXTreeSourceMus::GetTreeData(ui::AXTreeData* tree_data) const {
- tree_data->tree_id = tree_id_;
- return AXTreeSourceViews::GetTreeData(tree_data);
-}
-
-AXAuraObjWrapper* AXTreeSourceMus::GetRoot() const {
- return root_;
-}
-
void AXTreeSourceMus::SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const {
- if (IsEqual(node, root_)) {
+ if (IsEqual(node, GetRoot())) {
node->Serialize(out_data);
// Root is a contents view with an offset from the containing Widget.
// However, the contents view in the host (browser) already has an offset
// from its Widget, so the root should start at (0,0).
- out_data->location.set_origin(gfx::PointF());
+ out_data->relative_bounds.bounds.set_origin(gfx::PointF());
// Adjust for display device scale factor.
if (device_scale_factor_ == 1.f) {
// The AX system represents the identity transform with null.
- out_data->transform.reset();
+ out_data->relative_bounds.transform.reset();
} else {
- out_data->transform = std::make_unique<gfx::Transform>();
- out_data->transform->Scale(device_scale_factor_, device_scale_factor_);
+ out_data->relative_bounds.transform = std::make_unique<gfx::Transform>();
+ out_data->relative_bounds.transform->Scale(device_scale_factor_,
+ device_scale_factor_);
}
return;
}
diff --git a/chromium/ui/views/mus/ax_tree_source_mus.h b/chromium/ui/views/mus/ax_tree_source_mus.h
index 6c9170747ed..a14d78ea673 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus.h
+++ b/chromium/ui/views/mus/ax_tree_source_mus.h
@@ -6,7 +6,6 @@
#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"
@@ -27,18 +26,10 @@ class VIEWS_MUS_EXPORT AXTreeSourceMus : public AXTreeSourceViews {
void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
// AXTreeSource:
- bool GetTreeData(ui::AXTreeData* data) const override;
- AXAuraObjWrapper* GetRoot() const override;
void SerializeNode(AXAuraObjWrapper* node,
ui::AXNodeData* out_data) const override;
private:
- // 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 b4fbdd54ac4..51f5cd2d57b 100644
--- a/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
+++ b/chromium/ui/views/mus/ax_tree_source_mus_unittest.cc
@@ -78,15 +78,15 @@ TEST_F(AXTreeSourceMusTest, Serialize) {
tree.SerializeNode(root, &node_data);
// Root is at the origin and has no parent container.
- EXPECT_EQ(gfx::RectF(0, 0, 333, 444), node_data.location);
- EXPECT_EQ(-1, node_data.offset_container_id);
+ EXPECT_EQ(gfx::RectF(0, 0, 333, 444), node_data.relative_bounds.bounds);
+ EXPECT_EQ(-1, node_data.relative_bounds.offset_container_id);
// Serialize a child.
tree.SerializeNode(cache->GetOrCreate(label_), &node_data);
// Child has relative position with the root as the container.
- EXPECT_EQ(gfx::RectF(1, 1, 111, 111), node_data.location);
- EXPECT_EQ(root->GetUniqueId().Get(), node_data.offset_container_id);
+ EXPECT_EQ(gfx::RectF(1, 1, 111, 111), node_data.relative_bounds.bounds);
+ EXPECT_EQ(root->GetUniqueId(), node_data.relative_bounds.offset_container_id);
}
TEST_F(AXTreeSourceMusTest, ScaleFactor) {
@@ -102,9 +102,10 @@ TEST_F(AXTreeSourceMusTest, ScaleFactor) {
tree.SerializeNode(root, &node_data);
// Transform is scaled.
- ASSERT_TRUE(node_data.transform);
- EXPECT_TRUE(node_data.transform->IsScale2d());
- EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), node_data.transform->Scale2d());
+ ASSERT_TRUE(node_data.relative_bounds.transform);
+ EXPECT_TRUE(node_data.relative_bounds.transform->IsScale2d());
+ EXPECT_EQ(gfx::Vector2dF(2.f, 2.f),
+ node_data.relative_bounds.transform->Scale2d());
}
} // namespace
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 61fd282fbb4..01b7f545742 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -12,15 +12,20 @@
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/transient_window_client.h"
+#include "ui/aura/env.h"
#include "ui/aura/mus/focus_synchronizer.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tracker.h"
#include "ui/base/hit_test.h"
#include "ui/display/screen.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/events/gestures/gesture_recognizer_observer.h"
#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/mus/mus_client.h"
@@ -34,10 +39,6 @@
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
-#if defined(USE_OZONE)
-#include "ui/base/cursor/ozone/cursor_data_factory_ozone.h"
-#endif
-
namespace views {
namespace {
@@ -51,7 +52,7 @@ class ClientSideNonClientFrameView : public NonClientFrameView,
: widget_(widget) {
// Not part of the accessibility node hierarchy because the window frame is
// provided by the window manager.
- GetViewAccessibility().set_is_ignored(true);
+ GetViewAccessibility().OverrideIsIgnored(true);
// Initialize kTopViewInset to a default value. Further updates will come
// from Ash. This is necessary so that during app window creation,
@@ -169,15 +170,10 @@ class NativeCursorManagerMus : public wm::NativeCursorManager {
void SetCursor(gfx::NativeCursor cursor,
wm::NativeCursorManagerDelegate* delegate) override {
ui::CursorData mojo_cursor;
- if (cursor.platform()) {
-#if defined(USE_OZONE)
+ if (cursor.native_type() == ui::CursorType::kCustom) {
mojo_cursor =
- ui::CursorDataFactoryOzone::GetCursorData(cursor.platform());
-#else
- NOTIMPLEMENTED()
- << "Can't pass native platform cursors on non-ozone platforms";
- mojo_cursor = ui::CursorData(ui::CursorType::kPointer);
-#endif
+ ui::CursorData(cursor.GetHotspot(), {cursor.GetBitmap()},
+ cursor.device_scale_factor(), base::TimeDelta());
} else {
mojo_cursor = ui::CursorData(cursor.native_type());
}
@@ -232,8 +228,97 @@ void OnMoveLoopEnd(bool* out_success,
quit_closure.Run();
}
+// ScopedTouchTransferController controls the transfer of touch events for
+// window move loop. It transfers touches before the window move starts, and
+// then transfers them back to the original window when the window move ends.
+// However this transferring back to the original shouldn't happen if the client
+// wants to continue the dragging on another window (like attaching the dragged
+// tab to another window).
+class ScopedTouchTransferController : public ui::GestureRecognizerObserver {
+ public:
+ ScopedTouchTransferController(aura::Window* source, aura::Window* dest)
+ : tracker_({source, dest}),
+ gesture_recognizer_(source->env()->gesture_recognizer()) {
+ gesture_recognizer_->TransferEventsTo(
+ source, dest, ui::TransferTouchesBehavior::kDontCancel);
+ gesture_recognizer_->AddObserver(this);
+ }
+ ~ScopedTouchTransferController() override {
+ gesture_recognizer_->RemoveObserver(this);
+ if (tracker_.windows().size() == 2) {
+ aura::Window* source = tracker_.Pop();
+ aura::Window* dest = tracker_.Pop();
+ gesture_recognizer_->TransferEventsTo(
+ dest, source, ui::TransferTouchesBehavior::kDontCancel);
+ }
+ }
+
+ private:
+ // ui::GestureRecognizerObserver:
+ void OnActiveTouchesCanceledExcept(
+ ui::GestureConsumer* not_cancelled) override {}
+ void OnEventsTransferred(
+ ui::GestureConsumer* current_consumer,
+ ui::GestureConsumer* new_consumer,
+ ui::TransferTouchesBehavior transfer_touches_behavior) override {
+ if (tracker_.windows().size() <= 1)
+ return;
+ aura::Window* dest = tracker_.windows()[1];
+ if (current_consumer == dest)
+ tracker_.Remove(dest);
+ }
+ void OnActiveTouchesCanceled(ui::GestureConsumer* consumer) override {}
+
+ aura::WindowTracker tracker_;
+
+ ui::GestureRecognizer* gesture_recognizer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTouchTransferController);
+};
+
} // namespace
+// WindowObserver installed on DesktopWindowTreeHostMus::window(). Mostly
+// forwards interesting events to DesktopWindowTreeHostMus. To avoid having
+// DesktopWindowTreeHostMus be a WindowObserver on two windows (which is mildly
+// error prone), this helper class is used.
+class DesktopWindowTreeHostMus::WindowTreeHostWindowObserver
+ : public aura::WindowObserver {
+ public:
+ explicit WindowTreeHostWindowObserver(DesktopWindowTreeHostMus* host)
+ : host_(host) {
+ host->window()->AddObserver(this);
+ }
+ ~WindowTreeHostWindowObserver() override {
+ host_->window()->RemoveObserver(this);
+ }
+
+ void set_is_waiting_for_restore(bool value) {
+ is_waiting_for_restore_ = value;
+ }
+ bool is_waiting_for_restore() const { return is_waiting_for_restore_; }
+
+ // aura::WindowObserver:
+ void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
+ if (window == host_->window())
+ host_->OnWindowTreeHostWindowVisibilityChanged(visible);
+ }
+ void OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) override {
+ if (key == aura::client::kShowStateKey)
+ is_waiting_for_restore_ = false;
+ }
+
+ private:
+ DesktopWindowTreeHostMus* host_;
+
+ // True while waiting for the show state to change.
+ bool is_waiting_for_restore_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeHostWindowObserver);
+};
+
DesktopWindowTreeHostMus::DesktopWindowTreeHostMus(
aura::WindowTreeHostMusInitParams init_params,
internal::NativeWidgetDelegate* native_widget_delegate,
@@ -251,11 +336,16 @@ DesktopWindowTreeHostMus::DesktopWindowTreeHostMus(
// Widget. This call enables that.
NativeWidgetAura::RegisterNativeWidgetForWindow(desktop_native_widget_aura,
window());
+
+ window_tree_host_window_observer_ =
+ std::make_unique<WindowTreeHostWindowObserver>(this);
// TODO: use display id and bounds if available, likely need to pass in
// InitParams for that.
}
DesktopWindowTreeHostMus::~DesktopWindowTreeHostMus() {
+ window_tree_host_window_observer_.reset();
+
// The cursor-client can be accessed during WindowTreeHostMus tear-down. So
// the cursor-client needs to be unset on the root-window before
// |cursor_manager_| is destroyed.
@@ -276,6 +366,10 @@ void DesktopWindowTreeHostMus::SendClientAreaToServer() {
if (!non_client_view || !non_client_view->client_view())
return;
+ View* client_view = non_client_view->client_view();
+ if (!observed_client_view_.IsObserving(client_view))
+ observed_client_view_.Add(client_view);
+
const gfx::Rect client_area_rect(non_client_view->client_view()->bounds());
SetClientArea(
gfx::Insets(
@@ -305,7 +399,11 @@ void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
const gfx::Rect rect(
gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), GetScaleFactor()),
gfx::ScaleToCeiledSize(bounds_in_dip.size(), GetScaleFactor()));
- SetBoundsInPixels(rect, viz::LocalSurfaceId());
+ SetBoundsInPixels(rect, viz::LocalSurfaceIdAllocation());
+}
+
+bool DesktopWindowTreeHostMus::IsWaitingForRestoreToComplete() const {
+ return window_tree_host_window_observer_->is_waiting_for_restore();
}
bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
@@ -317,13 +415,38 @@ bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL;
}
+void DesktopWindowTreeHostMus::RestoreToPreminimizedState() {
+ DCHECK(IsMinimized());
+ window_tree_host_window_observer_->set_is_waiting_for_restore(true);
+ base::AutoReset<bool> setter(&is_updating_window_visibility_, true);
+ window()->Show();
+}
+
+void DesktopWindowTreeHostMus::OnWindowTreeHostWindowVisibilityChanged(
+ bool visible) {
+ if (is_updating_window_visibility_)
+ return;
+
+ // Call Show()/Hide() so that the visibility state is mirrored correctly. This
+ // function makes it so that calling Show()/Hide() on window() is the same as
+ // calling Show()/Hide() on the Widget.
+ base::AutoReset<bool> setter(&is_updating_window_visibility_, true);
+ if (visible)
+ Show(ui::SHOW_STATE_INACTIVE, gfx::Rect());
+ else
+ Hide();
+}
+
void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
const bool translucent =
MusClient::ShouldMakeWidgetWindowsTranslucent(params);
content_window()->SetTransparent(translucent);
window()->SetTransparent(translucent);
- window()->SetProperty(aura::client::kShowStateKey, params.show_state);
+ // The window manager may provide the initial show state, for example for
+ // Chrome OS lock screen windows. https://crbug.com/899055
+ if (params.show_state != ui::SHOW_STATE_DEFAULT)
+ window()->SetProperty(aura::client::kShowStateKey, params.show_state);
if (!params.bounds.IsEmpty()) {
// Init the scale now (before InitHost below), it is used by SetBoundsInDIP.
@@ -381,6 +504,13 @@ void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
window()->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::NONE);
else
aura::WindowPortMus::Get(content_window())->SetCanAcceptDrops(true);
+
+ // Sets the has-content info for the occlusion tracker that runs on the Window
+ // Service side.
+ content_window()->SetProperty(
+ aura::client::kClientWindowHasContent,
+ params.layer_type != ui::LAYER_NOT_DRAWN &&
+ params.opacity == views::Widget::InitParams::OPAQUE_WINDOW);
}
void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
@@ -424,9 +554,9 @@ void DesktopWindowTreeHostMus::OnWidgetInitDone() {
// window frame is provided by the window manager.
Widget* widget = native_widget_delegate_->AsWidget();
if (widget->non_client_view())
- widget->non_client_view()->GetViewAccessibility().set_is_ignored(true);
+ widget->non_client_view()->GetViewAccessibility().OverrideIsIgnored(true);
if (widget->client_view())
- widget->client_view()->GetViewAccessibility().set_is_ignored(true);
+ widget->client_view()->GetViewAccessibility().OverrideIsIgnored(true);
MusClient::Get()->OnWidgetInitDone(widget);
}
@@ -488,7 +618,16 @@ aura::WindowTreeHost* DesktopWindowTreeHostMus::AsWindowTreeHost() {
void DesktopWindowTreeHostMus::Show(ui::WindowShowState show_state,
const gfx::Rect& restore_bounds) {
- native_widget_delegate_->OnNativeWidgetVisibilityChanging(true);
+ // Only notify if the visibility is really changing.
+ const bool notify_visibility_change =
+ is_updating_window_visibility_ || !IsVisible();
+ if (notify_visibility_change)
+ native_widget_delegate_->OnNativeWidgetVisibilityChanging(true);
+
+ // NOTE: this code is called from Widget::Show() (no args). Widget::Show()
+ // supplies ui::SHOW_STATE_DEFAULT as the |show_state| after the first call.
+ // If SHOW_STATE_DEFAULT is supplied, and the Window is currently minimized,
+ // the window should be restored to its preminimized state.
if (show_state == ui::SHOW_STATE_MAXIMIZED && !restore_bounds.IsEmpty()) {
window()->SetProperty(aura::client::kRestoreBoundsKey,
@@ -497,13 +636,21 @@ void DesktopWindowTreeHostMus::Show(ui::WindowShowState show_state,
if (show_state == ui::SHOW_STATE_MAXIMIZED ||
show_state == ui::SHOW_STATE_FULLSCREEN) {
window()->SetProperty(aura::client::kShowStateKey, show_state);
+ window_tree_host_window_observer_->set_is_waiting_for_restore(false);
+ } else if (show_state == ui::SHOW_STATE_DEFAULT && IsMinimized()) {
+ RestoreToPreminimizedState();
+ } else if (show_state == ui::SHOW_STATE_MINIMIZED && !IsMinimized()) {
+ Minimize();
}
// DesktopWindowTreeHostMus is unique in that it calls window()->Show() here.
// All other implementations call window()->Show() from the constructor. This
// is necessary as window()'s visibility is mirrored in the server, on other
// platforms it's the visibility of the AcceleratedWidget that matters and
// dictates what is actually drawn on screen.
- window()->Show();
+ {
+ base::AutoReset<bool> setter(&is_updating_window_visibility_, true);
+ window()->Show();
+ }
if (compositor())
compositor()->SetVisible(true);
@@ -512,11 +659,14 @@ void DesktopWindowTreeHostMus::Show(ui::WindowShowState show_state,
// otherwise focus goes to window().
content_window()->Show();
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
+ if (notify_visibility_change)
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
if (native_widget_delegate_->CanActivate()) {
- if (show_state != ui::SHOW_STATE_INACTIVE)
+ if (show_state != ui::SHOW_STATE_INACTIVE &&
+ show_state != ui::SHOW_STATE_MINIMIZED) {
Activate();
+ }
// SetInitialFocus() should be always be called, even for
// SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
@@ -586,7 +736,13 @@ void DesktopWindowTreeHostMus::GetWindowPlacement(
ui::WindowShowState* show_state) const {
// Implementation matches that of NativeWidgetAura.
*bounds = GetRestoredBounds();
- *show_state = window()->GetProperty(aura::client::kShowStateKey);
+ if (IsWaitingForRestoreToComplete()) {
+ // The real state is not known, use ui::SHOW_STATE_NORMAL to avoid saving
+ // the minimized state.
+ *show_state = ui::SHOW_STATE_NORMAL;
+ } else {
+ *show_state = window()->GetProperty(aura::client::kShowStateKey);
+ }
}
gfx::Rect DesktopWindowTreeHostMus::GetWindowBoundsInScreen() const {
@@ -629,9 +785,13 @@ void DesktopWindowTreeHostMus::SetShape(
}
void DesktopWindowTreeHostMus::Activate() {
- if (!IsVisible())
+ if (!IsVisible() && !IsMinimized())
return;
+ // Activate() is expected to restore a minimized window.
+ if (IsMinimized())
+ RestoreToPreminimizedState();
+
// This should result in OnActiveFocusClientChanged() being called, which
// triggers a call to DesktopNativeWidgetAura::HandleActivationChanged(),
// which focuses the right window.
@@ -671,6 +831,14 @@ void DesktopWindowTreeHostMus::Maximize() {
void DesktopWindowTreeHostMus::Minimize() {
window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
+
+ // When minimized, this should no longer be active.
+ if (IsFocusClientInstalledOnFocusSynchronizer()) {
+ MusClient::Get()
+ ->window_tree_client()
+ ->focus_synchronizer()
+ ->SetActiveFocusClient(nullptr, nullptr);
+ }
}
void DesktopWindowTreeHostMus::Restore() {
@@ -684,7 +852,8 @@ bool DesktopWindowTreeHostMus::IsMaximized() const {
bool DesktopWindowTreeHostMus::IsMinimized() const {
return window()->GetProperty(aura::client::kShowStateKey) ==
- ui::SHOW_STATE_MINIMIZED;
+ ui::SHOW_STATE_MINIMIZED &&
+ !IsWaitingForRestoreToComplete();
}
bool DesktopWindowTreeHostMus::HasCapture() const {
@@ -733,6 +902,11 @@ Widget::MoveLoopResult DesktopWindowTreeHostMus::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
+ // When using WindowService, the touch events for the window move will
+ // happen on the root window, so the events need to be transferred from
+ // widget to its root before starting move loop.
+ ScopedTouchTransferController scoped_controller(content_window(), window());
+
static_cast<internal::NativeWidgetPrivate*>(
desktop_native_widget_aura_)->ReleaseCapture();
@@ -744,8 +918,11 @@ Widget::MoveLoopResult DesktopWindowTreeHostMus::RunMoveLoop(
: ws::mojom::MoveLoopSource::TOUCH;
bool success = false;
- gfx::Point cursor_location =
- display::Screen::GetScreen()->GetCursorScreenPoint();
+ // Don't use display::Screen::GetCursorScreenPoint() -- that's incorrect for
+ // touch events. Rather the cursor location can be computed from window's
+ // location with drag_offset.
+ gfx::Point cursor_location = window()->GetBoundsInScreen().origin() +
+ gfx::ToFlooredVector2d(drag_offset);
WindowTreeHostMus::PerformWindowMove(
mus_source, cursor_location,
base::Bind(OnMoveLoopEnd, &success, run_loop.QuitClosure()));
@@ -768,10 +945,7 @@ NonClientFrameView* DesktopWindowTreeHostMus::CreateNonClientFrameView() {
if (!ShouldSendClientAreaToServer())
return nullptr;
- auto* frame =
- new ClientSideNonClientFrameView(native_widget_delegate_->AsWidget());
- observed_frame_.Add(frame);
- return frame;
+ return new ClientSideNonClientFrameView(native_widget_delegate_->AsWidget());
}
bool DesktopWindowTreeHostMus::ShouldUseNativeFrame() const {
@@ -889,28 +1063,43 @@ void DesktopWindowTreeHostMus::OnWindowPropertyChanged(aura::Window* window,
}
void DesktopWindowTreeHostMus::ShowImpl() {
- Show(ui::SHOW_STATE_NORMAL, gfx::Rect());
+ // This code path is hit when the server initiated the change. In such a case
+ // the window should not be made active. If the server wants the window to be
+ // active, it will make the window active.
+ Show(ui::SHOW_STATE_INACTIVE, gfx::Rect());
}
void DesktopWindowTreeHostMus::HideImpl() {
+ // If |is_updating_window_visibility_| is true, this is being called in
+ // response to window()'s visibility changing, in which case we need to
+ // continue on to complete processing of the hide.
+ if (!IsVisible() && !is_updating_window_visibility_)
+ return;
+
+ native_widget_delegate_->OnNativeWidgetVisibilityChanging(false);
+ {
+ base::AutoReset<bool> setter(&is_updating_window_visibility_, true);
+ WindowTreeHostMus::HideImpl();
+ }
+ native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
+
// When hiding we can't possibly be active any more. Reset the FocusClient,
// which effectively triggers giving up focus (and activation). Mus will
- // eventually generate a focus event, but that's async.
+ // eventually generate a focus event, but that's async. This should be done
+ // after the window gets hidden actually, since some code (like
+ // WindowActivityWatcher) assumes closing window is already invisible when the
+ // focus is lost. See https://crbug.com/896080.
if (IsFocusClientInstalledOnFocusSynchronizer()) {
MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->SetActiveFocusClient(nullptr, nullptr);
}
-
- native_widget_delegate_->OnNativeWidgetVisibilityChanging(false);
- WindowTreeHostMus::HideImpl();
- native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
}
void DesktopWindowTreeHostMus::SetBoundsInPixels(
const gfx::Rect& bounds_in_pixels,
- const viz::LocalSurfaceId& local_surface_id) {
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
gfx::Rect final_bounds_in_pixels = bounds_in_pixels;
if (GetBoundsInPixels().size() != bounds_in_pixels.size()) {
gfx::Size size = bounds_in_pixels.size();
@@ -923,19 +1112,19 @@ void DesktopWindowTreeHostMus::SetBoundsInPixels(
final_bounds_in_pixels.set_size(size);
}
WindowTreeHostMus::SetBoundsInPixels(final_bounds_in_pixels,
- local_surface_id);
+ local_surface_id_allocation);
}
void DesktopWindowTreeHostMus::OnViewBoundsChanged(views::View* observed_view) {
DCHECK_EQ(
observed_view,
- native_widget_delegate_->AsWidget()->non_client_view()->frame_view());
+ native_widget_delegate_->AsWidget()->non_client_view()->client_view());
SendClientAreaToServer();
}
void DesktopWindowTreeHostMus::OnViewIsDeleting(View* observed_view) {
- observed_frame_.Remove(observed_view);
+ observed_client_view_.Remove(observed_view);
}
aura::Window* DesktopWindowTreeHostMus::content_window() {
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.h b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
index 17c0655e987..6d61f260e33 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.h
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
@@ -48,6 +48,8 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
}
private:
+ class WindowTreeHostWindowObserver;
+
void SendClientAreaToServer();
// Returns true if the FocusClient associated with our window is installed on
@@ -62,6 +64,26 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
// Returns true if the client area should be set on this.
bool ShouldSendClientAreaToServer() const;
+ bool IsWaitingForRestoreToComplete() const;
+
+ // Restores the window to its pre-minimized state. There are two paths to
+ // unminimizing/restoring a window:
+ // . Implicitly by calling Show()/Activate(). In this scenario the expectation
+ // is the Widget returns to its pre-minimized state.
+ // DesktopWindowTreeHostMus does *not* cache the pre-minimized state, only
+ // the server knows it.
+ // . By calling Restore(). Restore sets the state to normal, circumventing
+ // the pre-minimized state in the server. This mirrors what NativeWidgetAura
+ // does.
+ // This function handles the first case. As DesktopWindowTreeHostMus doesn't
+ // know the new state, an observer is added that tracks when the show state
+ // changes. While waiting, IsMinimized() returns false.
+ void RestoreToPreminimizedState();
+
+ // Called when window()'s visibility changes to |visible|. This is called from
+ // WindowObserver::OnWindowVisibilityChanged().
+ void OnWindowTreeHostWindowVisibilityChanged(bool visible);
+
// DesktopWindowTreeHost:
void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
@@ -144,7 +166,8 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
void ShowImpl() override;
void HideImpl() override;
void SetBoundsInPixels(const gfx::Rect& bounds_in_pixels,
- const viz::LocalSurfaceId& local_surface_id) override;
+ const viz::LocalSurfaceIdAllocation&
+ local_surface_id_allocation) override;
// views::ViewObserver:
void OnViewBoundsChanged(views::View* observed_view) override;
@@ -168,7 +191,17 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
bool auto_update_client_area_ = true;
- ScopedObserver<views::View, views::ViewObserver> observed_frame_{this};
+ // Observes changes to the ClientView. Used to update the client area in the
+ // server.
+ ScopedObserver<views::View, views::ViewObserver> observed_client_view_{this};
+
+ // If true, |this| is changing the visibility of window(), or is processing
+ // a change in the visibility of window().
+ bool is_updating_window_visibility_ = false;
+
+ // aura::WindowObserver on window().
+ std::unique_ptr<WindowTreeHostWindowObserver>
+ window_tree_host_window_observer_;
// Used so that Close() isn't immediate.
base::WeakPtrFactory<DesktopWindowTreeHostMus> close_widget_factory_;
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index 159770b5a1c..f5c2ba853eb 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
@@ -4,7 +4,10 @@
#include "ui/views/mus/desktop_window_tree_host_mus.h"
+#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "services/ws/test_ws/test_ws.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
@@ -15,11 +18,17 @@
#include "ui/aura/mus/in_flight_change.h"
#include "ui/aura/mus/window_mus.h"
#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/mus/window_tree_client_test_observer.h"
#include "ui/aura/test/mus/change_completion_waiter.h"
-#include "ui/aura/test/mus/window_tree_client_private.h"
+#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/aura/test/mus/window_tree_client_test_api.h"
#include "ui/aura/window.h"
+#include "ui/display/display_switches.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
+#include "ui/events/gestures/gesture_recognizer.h"
+#include "ui/events/gestures/gesture_recognizer_observer.h"
+#include "ui/gfx/geometry/dip_util.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/mus/mus_client.h"
#include "ui/views/mus/mus_client_test_api.h"
@@ -29,6 +38,7 @@
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/wm/core/shadow_types.h"
+#include "ui/wm/core/transient_window_manager.h"
namespace views {
@@ -97,6 +107,29 @@ class ExpectsNullCursorClientDuringTearDown : public aura::WindowObserver {
DISALLOW_COPY_AND_ASSIGN(ExpectsNullCursorClientDuringTearDown);
};
+// Tests that the window service can set the initial show state for a window.
+// https://crbug.com/899055
+TEST_F(DesktopWindowTreeHostMusTest, ShowStateFromWindowService) {
+ // Configure the window service to maximize the next top-level window.
+ test_ws::mojom::TestWsPtr test_ws_ptr;
+ MusClient::Get()->window_tree_client()->connector()->BindInterface(
+ test_ws::mojom::kServiceName, &test_ws_ptr);
+ test_ws::mojom::TestWsAsyncWaiter wait_for(test_ws_ptr.get());
+ wait_for.MaximizeNextWindow();
+
+ // Create a widget with the default show state.
+ Widget widget;
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ EXPECT_EQ(ui::SHOW_STATE_DEFAULT, params.show_state);
+ widget.Init(params);
+ aura::test::WaitForAllChangesToComplete();
+
+ // Window service provided the show state.
+ EXPECT_TRUE(widget.IsMaximized());
+}
+
TEST_F(DesktopWindowTreeHostMusTest, Visibility) {
std::unique_ptr<Widget> widget(CreateWidget());
EXPECT_FALSE(widget->IsVisible());
@@ -215,7 +248,7 @@ TEST_F(DesktopWindowTreeHostMusTest, BecomesActiveOnMousePress) {
// The mouse event should generate a focus request to the server.
EXPECT_TRUE(
- aura::WindowTreeClientPrivate(MusClient::Get()->window_tree_client())
+ aura::WindowTreeClientTestApi(MusClient::Get()->window_tree_client())
.HasChangeInFlightOfType(aura::ChangeType::FOCUS));
}
@@ -383,6 +416,87 @@ TEST_F(DesktopWindowTreeHostMusTest, CreateFullscreenWidget) {
}
}
+TEST_F(DesktopWindowTreeHostMusTest, ClientWindowHasContent) {
+ // Opaque window has content.
+ {
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+
+ Widget widget;
+ widget.Init(params);
+ EXPECT_TRUE(widget.GetNativeWindow()->GetProperty(
+ aura::client::kClientWindowHasContent));
+ }
+
+ // Translucent window does not have content.
+ {
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+
+ Widget widget;
+ widget.Init(params);
+ EXPECT_FALSE(widget.GetNativeWindow()->GetProperty(
+ aura::client::kClientWindowHasContent));
+ }
+
+ // Window with LAYER_NOT_DRAWN does not have content.
+ {
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.layer_type = ui::LAYER_NOT_DRAWN;
+
+ Widget widget;
+ widget.Init(params);
+ EXPECT_FALSE(widget.GetNativeWindow()->GetProperty(
+ aura::client::kClientWindowHasContent));
+ }
+}
+
+// DesktopWindowTreeHostMusTest with --force-device-scale-factor=2.
+class DesktopWindowTreeHostMusTestHighDPI
+ : public DesktopWindowTreeHostMusTest {
+ public:
+ DesktopWindowTreeHostMusTestHighDPI() = default;
+ ~DesktopWindowTreeHostMusTestHighDPI() override = default;
+
+ // DesktopWindowTreeHostMusTest:
+ void SetUp() override {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kForceDeviceScaleFactor, "2");
+ DesktopWindowTreeHostMusTest::SetUp();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostMusTestHighDPI);
+};
+
+// Ensure menu widgets correctly scale initial bounds: http://crbug.com/899084
+TEST_F(DesktopWindowTreeHostMusTestHighDPI, InitializeMenuWithDIPBounds) {
+ // Swap the WindowTree implementation to verify SetWindowBounds() is called
+ // with the correct DIP bounds, using the host's cached device_scale_factor.
+ aura::TestWindowTree test_window_tree;
+ aura::WindowTreeClientTestApi test_api(
+ MusClient::Get()->window_tree_client());
+ ws::mojom::WindowTree* old_tree = test_api.SwapTree(&test_window_tree);
+
+ Widget widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_MENU);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(2, 4, 60, 80);
+ widget.Init(params);
+
+ // Check the second-last set window bounds (for the frame, not the content).
+ EXPECT_EQ(params.bounds, test_window_tree.second_last_set_window_bounds());
+ EXPECT_EQ(params.bounds, widget.GetWindowBoundsInScreen());
+ EXPECT_EQ(2.0f, widget.GetNativeWindow()->GetHost()->device_scale_factor());
+ gfx::Rect pixels(gfx::ConvertRectToPixel(2.0f, params.bounds));
+ EXPECT_EQ(pixels, widget.GetNativeWindow()->GetHost()->GetBoundsInPixels());
+
+ widget.CloseNow();
+ test_api.SwapTree(old_tree);
+}
+
TEST_F(DesktopWindowTreeHostMusTest, GetWindowBoundsInScreen) {
ScreenMus* screen = MusClientTestApi::screen();
@@ -470,10 +584,35 @@ TEST_F(DesktopWindowTreeHostMusTest, Accessibility) {
// Widget frame views do not participate in accessibility node hierarchy
// because the frame is provided by the window manager.
views::NonClientView* non_client_view = widget->non_client_view();
- EXPECT_TRUE(non_client_view->GetViewAccessibility().is_ignored());
+ EXPECT_TRUE(non_client_view->GetViewAccessibility().IsIgnored());
EXPECT_TRUE(
- non_client_view->frame_view()->GetViewAccessibility().is_ignored());
- EXPECT_TRUE(widget->client_view()->GetViewAccessibility().is_ignored());
+ non_client_view->frame_view()->GetViewAccessibility().IsIgnored());
+ EXPECT_TRUE(widget->client_view()->GetViewAccessibility().IsIgnored());
+}
+
+TEST_F(DesktopWindowTreeHostMusTest,
+ ClientViewBoundsChangeUpdatesServerClientArea) {
+ std::unique_ptr<Widget> widget = CreateWidget();
+ views::NonClientView* non_client_view = widget->non_client_view();
+ ASSERT_TRUE(non_client_view);
+ ASSERT_TRUE(non_client_view->client_view());
+
+ // Calculate a new bounds. It doesn't matter what the bounds are, just as long
+ // as they differ.
+ gfx::Rect bounds = non_client_view->client_view()->bounds();
+ bounds.set_width(bounds.width() - 1);
+ bounds.set_height(bounds.height() - 1);
+
+ // Swap the WindowTree implementation to verify SetClientArea() is called when
+ // the bounds change.
+ aura::TestWindowTree test_window_tree;
+ aura::WindowTreeClientTestApi window_tree_client_private(
+ MusClient::Get()->window_tree_client());
+ ws::mojom::WindowTree* old_tree =
+ window_tree_client_private.SwapTree(&test_window_tree);
+ non_client_view->client_view()->SetBoundsRect(bounds);
+ EXPECT_FALSE(test_window_tree.last_client_area().IsEmpty());
+ window_tree_client_private.SwapTree(old_tree);
}
// Used to ensure the visibility of the root window is changed before that of
@@ -540,4 +679,237 @@ TEST_F(DesktopWindowTreeHostMusTest,
EXPECT_TRUE(observer.got_root_window_hidden());
}
+TEST_F(DesktopWindowTreeHostMusTest, MinimizeActivate) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+ EXPECT_TRUE(widget->IsActive());
+
+ widget->Minimize();
+ aura::test::WaitForAllChangesToComplete();
+ EXPECT_FALSE(widget->IsActive());
+ EXPECT_FALSE(widget->IsVisible());
+ EXPECT_TRUE(widget->IsMinimized());
+
+ // Activate() should restore the window.
+ widget->Activate();
+ EXPECT_TRUE(widget->IsActive());
+ EXPECT_TRUE(widget->IsVisible());
+ EXPECT_FALSE(widget->IsMinimized());
+}
+
+TEST_F(DesktopWindowTreeHostMusTest, MaximizeMinimizeRestore) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+ EXPECT_TRUE(widget->IsActive());
+
+ widget->Maximize();
+ widget->Minimize();
+ EXPECT_FALSE(widget->IsActive());
+ EXPECT_TRUE(widget->IsMinimized());
+ EXPECT_FALSE(widget->IsMaximized());
+
+ widget->Restore();
+ // Restore() *always* sets the state to normal, not the pre-minimized state.
+ // This mirrors the logic in NativeWidgetAura. See
+ // DesktopWindowTreeHostMus::RestoreToPreminimizedState() for details.
+ EXPECT_FALSE(widget->IsMinimized());
+ EXPECT_FALSE(widget->IsMaximized());
+}
+
+// TransferTouchEventsCounter observes the GestureRecognizer and counts how many
+// times TransferEventsTo() is invoked for testing.
+class TransferTouchEventsCounter : public ui::GestureRecognizerObserver {
+ public:
+ TransferTouchEventsCounter() {
+ aura::Env::GetInstance()->gesture_recognizer()->AddObserver(this);
+ }
+ ~TransferTouchEventsCounter() override {
+ aura::Env::GetInstance()->gesture_recognizer()->RemoveObserver(this);
+ }
+
+ int GetTransferCount(ui::GestureConsumer* source,
+ ui::GestureConsumer* dest) const {
+ return std::count(transfers_.begin(), transfers_.end(),
+ std::make_pair(source, dest));
+ }
+
+ int GetTotalCount() const { return transfers_.size(); }
+
+ private:
+ // ui::GestureRecognizerObserver:
+ void OnActiveTouchesCanceledExcept(
+ ui::GestureConsumer* not_cancelled) override {}
+ void OnEventsTransferred(
+ ui::GestureConsumer* current_consumer,
+ ui::GestureConsumer* new_consumer,
+ ui::TransferTouchesBehavior transfer_touches_behavior) override {
+ transfers_.push_back(std::make_pair(current_consumer, new_consumer));
+ }
+ void OnActiveTouchesCanceled(ui::GestureConsumer* consumer) override {}
+
+ std::vector<std::pair<ui::GestureConsumer*, ui::GestureConsumer*>> transfers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransferTouchEventsCounter);
+};
+
+TEST_F(DesktopWindowTreeHostMusTest, WindowMoveTransfersTouchEvent) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+
+ TransferTouchEventsCounter counter;
+ aura::Window* window = widget->GetNativeWindow();
+ aura::Window* root = window->GetRootWindow();
+
+ auto runner = base::ThreadTaskRunnerHandle::Get();
+ runner->PostTask(FROM_HERE, base::BindLambdaForTesting([&]() {
+ EXPECT_EQ(1, counter.GetTransferCount(window, root));
+ EXPECT_EQ(1, counter.GetTotalCount());
+ }));
+ runner->PostTask(FROM_HERE, base::BindOnce(&Widget::EndMoveLoop,
+ base::Unretained(widget.get())));
+
+ widget->RunMoveLoop(gfx::Vector2d(), Widget::MOVE_LOOP_SOURCE_TOUCH,
+ Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE);
+
+ EXPECT_EQ(1, counter.GetTransferCount(root, window));
+ EXPECT_EQ(2, counter.GetTotalCount());
+}
+
+TEST_F(DesktopWindowTreeHostMusTest, WindowMoveShouldNotTransfersBack) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+ std::unique_ptr<Widget> widget2(CreateWidget());
+ widget2->Show();
+
+ TransferTouchEventsCounter counter;
+ aura::Window* window = widget->GetNativeWindow();
+ aura::Window* root = window->GetRootWindow();
+ aura::Window* window2 = widget2->GetNativeWindow();
+
+ auto runner = base::ThreadTaskRunnerHandle::Get();
+ runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &ui::GestureRecognizer::TransferEventsTo,
+ base::Unretained(aura::Env::GetInstance()->gesture_recognizer()),
+ root, window2, ui::TransferTouchesBehavior::kDontCancel));
+ runner->PostTask(FROM_HERE, base::BindOnce(&Widget::EndMoveLoop,
+ base::Unretained(widget.get())));
+
+ widget->RunMoveLoop(gfx::Vector2d(), Widget::MOVE_LOOP_SOURCE_TOUCH,
+ Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_DONT_HIDE);
+
+ EXPECT_EQ(0, counter.GetTransferCount(root, window));
+ EXPECT_EQ(1, counter.GetTransferCount(root, window2));
+ EXPECT_EQ(2, counter.GetTotalCount());
+}
+
+TEST_F(DesktopWindowTreeHostMusTest, ShowWindowFromServerDoesntActivate) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+
+ // This simulates what happens when a show happens from the server.
+ widget->GetNativeWindow()->GetHost()->Show();
+ EXPECT_TRUE(widget->IsVisible());
+ // The window should not be active yet.
+ EXPECT_FALSE(widget->GetNativeWindow()->HasFocus());
+ EXPECT_FALSE(widget->IsActive());
+}
+
+// Used to track the number of times OnWidgetVisibilityChanged() is called.
+class WidgetVisibilityObserver : public WidgetObserver {
+ public:
+ WidgetVisibilityObserver() = default;
+ ~WidgetVisibilityObserver() override = default;
+
+ int get_and_clear_change_count() {
+ int result = change_count_;
+ change_count_ = 0;
+ return result;
+ }
+
+ // WidgetObserver:
+ void OnWidgetVisibilityChanged(Widget* widget, bool visible) override {
+ change_count_++;
+ }
+
+ private:
+ int change_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(WidgetVisibilityObserver);
+};
+
+TEST_F(DesktopWindowTreeHostMusTest,
+ TogglingVisibilityOfWindowTreeWindowTriggersWidgetNotification) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+
+ WidgetVisibilityObserver observer;
+ widget->AddObserver(&observer);
+
+ widget->Show();
+ EXPECT_EQ(0, observer.get_and_clear_change_count());
+ EXPECT_TRUE(widget->IsVisible());
+ EXPECT_TRUE(widget->GetNativeWindow()->GetHost()->compositor()->IsVisible());
+ EXPECT_TRUE(widget->GetNativeWindow()->GetRootWindow()->IsVisible());
+
+ widget->Hide();
+ EXPECT_EQ(1, observer.get_and_clear_change_count());
+ EXPECT_FALSE(widget->IsVisible());
+ EXPECT_FALSE(widget->GetNativeWindow()->GetHost()->compositor()->IsVisible());
+ EXPECT_FALSE(widget->GetNativeWindow()->GetRootWindow()->IsVisible());
+
+ // Changing the visibility of the WindowTreeHost Window should notify the
+ // observer.
+ widget->GetNativeWindow()->GetHost()->window()->Show();
+ EXPECT_EQ(1, observer.get_and_clear_change_count());
+ EXPECT_TRUE(widget->IsVisible());
+ EXPECT_TRUE(widget->GetNativeWindow()->GetHost()->compositor()->IsVisible());
+ EXPECT_TRUE(widget->GetNativeWindow()->GetRootWindow()->IsVisible());
+
+ widget->GetNativeWindow()->GetHost()->window()->Hide();
+ EXPECT_EQ(1, observer.get_and_clear_change_count());
+ EXPECT_FALSE(widget->IsVisible());
+ EXPECT_FALSE(widget->GetNativeWindow()->GetHost()->compositor()->IsVisible());
+ EXPECT_FALSE(widget->GetNativeWindow()->GetRootWindow()->IsVisible());
+
+ widget->RemoveObserver(&observer);
+}
+
+TEST_F(DesktopWindowTreeHostMusTest, TransientChildMatchesParentVisibility) {
+ std::unique_ptr<Widget> widget(CreateWidget());
+ widget->Show();
+
+ std::unique_ptr<Widget> transient_child =
+ CreateWidget(nullptr, widget->GetNativeWindow());
+ transient_child->Show();
+
+ WidgetVisibilityObserver observer;
+ transient_child->AddObserver(&observer);
+
+ // Hiding the parent should also hide the transient child.
+ widget->Hide();
+ EXPECT_FALSE(transient_child->IsVisible());
+ EXPECT_EQ(1, observer.get_and_clear_change_count());
+ EXPECT_FALSE(
+ transient_child->GetNativeWindow()->GetHost()->compositor()->IsVisible());
+ EXPECT_FALSE(
+ transient_child->GetNativeWindow()->GetRootWindow()->IsVisible());
+
+ // set_parent_controls_visibility(true) makes it so showing the parent also
+ // shows the child.
+ wm::TransientWindowManager::GetOrCreate(
+ transient_child->GetNativeWindow()->GetRootWindow())
+ ->set_parent_controls_visibility(true);
+ // With set_parent_controls_visibility() true, showing the parent should also
+ // show the transient child.
+ widget->Show();
+ EXPECT_TRUE(transient_child->IsVisible());
+ EXPECT_EQ(1, observer.get_and_clear_change_count());
+ EXPECT_TRUE(
+ transient_child->GetNativeWindow()->GetHost()->compositor()->IsVisible());
+ EXPECT_TRUE(transient_child->GetNativeWindow()->GetRootWindow()->IsVisible());
+
+ transient_child->RemoveObserver(&observer);
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc
index 4bed24086c3..447610137b9 100644
--- a/chromium/ui/views/mus/mus_client.cc
+++ b/chromium/ui/views/mus/mus_client.cc
@@ -28,7 +28,6 @@
#include "ui/views/mus/ax_remote_host.h"
#include "ui/views/mus/desktop_window_tree_host_mus.h"
#include "ui/views/mus/mus_property_mirror.h"
-#include "ui/views/mus/pointer_watcher_event_router.h"
#include "ui/views/mus/screen_mus.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -36,10 +35,6 @@
#include "ui/wm/core/shadow_types.h"
#include "ui/wm/core/wm_state.h"
-#if defined(USE_OZONE)
-#include "ui/base/cursor/ozone/cursor_data_factory_ozone.h"
-#endif
-
// Widget::InitParams::Type must match that of ws::mojom::WindowType.
#define WINDOW_TYPES_MATCH(NAME) \
static_assert( \
@@ -73,17 +68,6 @@ MusClient::MusClient(const InitParams& params) : identity_(params.identity) {
DCHECK(aura::Env::GetInstance());
instance_ = this;
-#if defined(USE_OZONE)
- // If we're in a mus client, we aren't going to have all of ozone initialized
- // even though we're in an ozone build. All the hard coded USE_OZONE ifdefs
- // that handle cursor code expect that there will be a CursorFactoryOzone
- // instance. Partially initialize the ozone cursor internals here, like we
- // partially initialize other ozone subsystems in
- // ChromeBrowserMainExtraPartsViews.
- if (params.create_cursor_factory)
- cursor_factory_ozone_ = std::make_unique<ui::CursorDataFactoryOzone>();
-#endif
-
property_converter_ = std::make_unique<aura::PropertyConverter>();
property_converter_->RegisterPrimitiveProperty(
::wm::kShadowElevationKey,
@@ -109,9 +93,6 @@ MusClient::MusClient(const InitParams& params) : identity_(params.identity) {
window_tree_client_ = params.window_tree_client;
}
- pointer_watcher_event_router_ =
- std::make_unique<PointerWatcherEventRouter>(window_tree_client_);
-
if (connector && !params.running_in_ws_process) {
input_device_client_ = std::make_unique<ws::InputDeviceClient>();
ws::mojom::InputDeviceServerPtr input_device_server;
@@ -316,14 +297,12 @@ void MusClient::OnWidgetInitDone(Widget* widget) {
void MusClient::OnCaptureClientSet(
aura::client::CaptureClient* capture_client) {
- pointer_watcher_event_router_->AttachToCaptureClient(capture_client);
window_tree_client_->capture_synchronizer()->AttachToCaptureClient(
capture_client);
}
void MusClient::OnCaptureClientUnset(
aura::client::CaptureClient* capture_client) {
- pointer_watcher_event_router_->DetachFromCaptureClient(capture_client);
window_tree_client_->capture_synchronizer()->DetachFromCaptureClient(
capture_client);
}
@@ -376,13 +355,6 @@ void MusClient::OnEmbedRootDestroyed(
->ServerDestroyedWindow();
}
-void MusClient::OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- aura::Window* target) {
- pointer_watcher_event_router_->OnPointerEventObserved(
- event, location_in_screen, target);
-}
-
void MusClient::OnDisplaysChanged(
std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
diff --git a/chromium/ui/views/mus/mus_client.h b/chromium/ui/views/mus/mus_client.h
index 0cd4f65bc06..143637135ba 100644
--- a/chromium/ui/views/mus/mus_client.h
+++ b/chromium/ui/views/mus/mus_client.h
@@ -33,10 +33,6 @@ namespace service_manager {
class Connector;
}
-namespace ui {
-class CursorDataFactoryOzone;
-}
-
namespace wm {
class WMState;
}
@@ -51,7 +47,6 @@ class AXRemoteHost;
class DesktopNativeWidgetAura;
class MusClientObserver;
class MusPropertyMirror;
-class PointerWatcherEventRouter;
class ScreenMus;
namespace internal {
@@ -80,9 +75,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// have one.
bool create_wm_state = true;
- // Tests may need to control objects owned by MusClient.
- bool create_cursor_factory = true;
-
// If provided, MusClient will not create the WindowTreeClient. Not owned.
// Must outlive MusClient.
aura::WindowTreeClient* window_tree_client = nullptr;
@@ -123,12 +115,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
aura::WindowTreeClient* window_tree_client() { return window_tree_client_; }
- PointerWatcherEventRouter* pointer_watcher_event_router() {
- return pointer_watcher_event_router_.get();
- }
-
- AXRemoteHost* ax_remote_host() { return ax_remote_host_.get(); }
-
// Creates DesktopNativeWidgetAura with DesktopWindowTreeHostMus. This is
// set as the factory function used for creating NativeWidgets when a
// NativeWidget has not been explicitly set.
@@ -136,12 +122,8 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
internal::NativeWidgetDelegate* delegate);
void OnWidgetInitDone(Widget* widget);
- // Called when the capture client has been set for a window to notify
- // PointerWatcherEventRouter and CaptureSynchronizer.
+ // Called when the capture client has been set or unset for a window.
void OnCaptureClientSet(aura::client::CaptureClient* capture_client);
-
- // Called when the capture client will be unset for a window to notify
- // PointerWatcherEventRouter and CaptureSynchronizer.
void OnCaptureClientUnset(aura::client::CaptureClient* capture_client);
void AddObserver(MusClientObserver* observer);
@@ -172,9 +154,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) override;
void OnLostConnection(aura::WindowTreeClient* client) override;
void OnEmbedRootDestroyed(aura::WindowTreeHostMus* window_tree_host) override;
- void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- aura::Window* target) override;
aura::PropertyConverter* GetPropertyConverter() override;
void OnDisplaysChanged(std::vector<ws::mojom::WsDisplayPtr> ws_displays,
int64_t primary_display_id,
@@ -191,10 +170,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
base::ObserverList<MusClientObserver>::Unchecked observer_list_;
-#if defined(USE_OZONE)
- std::unique_ptr<ui::CursorDataFactoryOzone> cursor_factory_ozone_;
-#endif
-
// NOTE: this may be null (creation is based on argument supplied to
// constructor).
std::unique_ptr<wm::WMState> wm_state_;
@@ -210,8 +185,6 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// Never null.
aura::WindowTreeClient* window_tree_client_;
- std::unique_ptr<PointerWatcherEventRouter> pointer_watcher_event_router_;
-
// Gives services transparent remote access the InputDeviceManager.
std::unique_ptr<ws::InputDeviceClient> input_device_client_;
diff --git a/chromium/ui/views/mus/mus_views_delegate.cc b/chromium/ui/views/mus/mus_views_delegate.cc
index 6456b0d31d7..55e5a77fc7f 100644
--- a/chromium/ui/views/mus/mus_views_delegate.cc
+++ b/chromium/ui/views/mus/mus_views_delegate.cc
@@ -4,9 +4,7 @@
#include "ui/views/mus/mus_views_delegate.h"
-#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 {
@@ -14,25 +12,4 @@ MusViewsDelegate::MusViewsDelegate() = default;
MusViewsDelegate::~MusViewsDelegate() = default;
-void MusViewsDelegate::NotifyAccessibilityEvent(View* view,
- ax::mojom::Event event_type) {
- if (MusClient::Get()->ax_remote_host())
- 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 6346df2979b..d74ac42d406 100644
--- a/chromium/ui/views/mus/mus_views_delegate.h
+++ b/chromium/ui/views/mus/mus_views_delegate.h
@@ -12,19 +12,12 @@
namespace views {
+// TODO(jamescook): Move the LayoutProvider and delete this class.
class VIEWS_MUS_EXPORT MusViewsDelegate : public ViewsDelegate {
public:
MusViewsDelegate();
~MusViewsDelegate() override;
- // 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/pointer_watcher_event_router.cc b/chromium/ui/views/mus/pointer_watcher_event_router.cc
deleted file mode 100644
index 07a1a7e7b02..00000000000
--- a/chromium/ui/views/mus/pointer_watcher_event_router.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/mus/pointer_watcher_event_router.h"
-
-#include "ui/aura/client/capture_client.h"
-#include "ui/aura/client/screen_position_client.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/aura/window.h"
-#include "ui/display/screen.h"
-#include "ui/events/base_event_utils.h"
-#include "ui/events/event.h"
-#include "ui/views/pointer_watcher.h"
-#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
-
-namespace views {
-namespace {
-
-bool HasPointerWatcher(
- base::ObserverList<views::PointerWatcher, true>::Unchecked* observer_list) {
- return observer_list->begin() != observer_list->end();
-}
-
-} // namespace
-
-PointerWatcherEventRouter::PointerWatcherEventRouter(
- aura::WindowTreeClient* window_tree_client)
- : window_tree_client_(window_tree_client) {
- window_tree_client->AddObserver(this);
-}
-
-PointerWatcherEventRouter::~PointerWatcherEventRouter() {
- if (window_tree_client_)
- window_tree_client_->RemoveObserver(this);
-}
-
-void PointerWatcherEventRouter::AddPointerWatcher(PointerWatcher* watcher,
- bool wants_moves) {
- // Pointer watchers cannot be added multiple times.
- DCHECK(!move_watchers_.HasObserver(watcher));
- DCHECK(!non_move_watchers_.HasObserver(watcher));
- if (wants_moves) {
- move_watchers_.AddObserver(watcher);
- if (event_types_ != EventTypes::MOVE_EVENTS) {
- event_types_ = EventTypes::MOVE_EVENTS;
- const bool wants_moves = true;
- window_tree_client_->StartPointerWatcher(wants_moves);
- }
- } else {
- non_move_watchers_.AddObserver(watcher);
- if (event_types_ == EventTypes::NONE) {
- event_types_ = EventTypes::NON_MOVE_EVENTS;
- const bool wants_moves = false;
- window_tree_client_->StartPointerWatcher(wants_moves);
- }
- }
-}
-
-void PointerWatcherEventRouter::RemovePointerWatcher(PointerWatcher* watcher) {
- if (non_move_watchers_.HasObserver(watcher)) {
- non_move_watchers_.RemoveObserver(watcher);
- } else {
- DCHECK(move_watchers_.HasObserver(watcher));
- move_watchers_.RemoveObserver(watcher);
- }
- const EventTypes types = DetermineEventTypes();
- if (types == event_types_)
- return;
-
- event_types_ = types;
- switch (types) {
- case EventTypes::NONE:
- window_tree_client_->StopPointerWatcher();
- break;
- case EventTypes::NON_MOVE_EVENTS:
- window_tree_client_->StartPointerWatcher(false);
- break;
- case EventTypes::MOVE_EVENTS:
- // It isn't possible to remove an observer and transition to wanting move
- // events. This could only happen if there is a bug in the add logic.
- NOTREACHED();
- break;
- }
-}
-
-void PointerWatcherEventRouter::OnPointerEventObserved(
- const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- aura::Window* target) {
- Widget* target_widget = nullptr;
- ui::PointerEvent updated_event(event);
- if (target) {
- aura::Window* window = target;
- while (window && !target_widget) {
- target_widget = Widget::GetWidgetForNativeView(window);
- if (!target_widget) {
- // Widget::GetWidgetForNativeView() uses NativeWidgetAura. Views with
- // aura-mus may also create DesktopNativeWidgetAura.
- DesktopNativeWidgetAura* desktop_native_widget_aura =
- DesktopNativeWidgetAura::ForWindow(target);
- if (desktop_native_widget_aura) {
- target_widget = static_cast<internal::NativeWidgetPrivate*>(
- desktop_native_widget_aura)
- ->GetWidget();
- }
- }
- window = window->parent();
- }
- if (target_widget) {
- gfx::Point widget_relative_location(event.location());
- aura::Window::ConvertPointToTarget(target, target_widget->GetNativeView(),
- &widget_relative_location);
- updated_event.set_location(widget_relative_location);
- }
- }
-
- for (PointerWatcher& observer : move_watchers_) {
- observer.OnPointerEventObserved(
- updated_event, location_in_screen,
- target_widget ? target_widget->GetNativeWindow() : target);
- }
- if (event.type() != ui::ET_POINTER_MOVED) {
- for (PointerWatcher& observer : non_move_watchers_) {
- observer.OnPointerEventObserved(
- updated_event, location_in_screen,
- target_widget ? target_widget->GetNativeWindow() : target);
- }
- }
-}
-
-void PointerWatcherEventRouter::AttachToCaptureClient(
- aura::client::CaptureClient* capture_client) {
- capture_client->AddObserver(this);
-}
-
-void PointerWatcherEventRouter::DetachFromCaptureClient(
- aura::client::CaptureClient* capture_client) {
- capture_client->RemoveObserver(this);
-}
-
-PointerWatcherEventRouter::EventTypes
-PointerWatcherEventRouter::DetermineEventTypes() {
- if (HasPointerWatcher(&move_watchers_))
- return EventTypes::MOVE_EVENTS;
-
- if (HasPointerWatcher(&non_move_watchers_))
- return EventTypes::NON_MOVE_EVENTS;
-
- return EventTypes::NONE;
-}
-
-void PointerWatcherEventRouter::OnCaptureChanged(aura::Window* lost_capture,
- aura::Window* gained_capture) {
- const ui::MouseEvent mouse_event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(),
- gfx::Point(), ui::EventTimeForNow(), 0, 0);
- const ui::PointerEvent event(mouse_event);
- gfx::Point location_in_screen =
- display::Screen::GetScreen()->GetCursorScreenPoint();
- for (PointerWatcher& observer : move_watchers_)
- observer.OnPointerEventObserved(event, location_in_screen, nullptr);
- for (PointerWatcher& observer : non_move_watchers_)
- observer.OnPointerEventObserved(event, location_in_screen, nullptr);
-}
-
-void PointerWatcherEventRouter::OnWillDestroyClient(
- aura::WindowTreeClient* client) {
- // We expect that all observers have been removed by this time.
- DCHECK_EQ(event_types_, EventTypes::NONE);
- DCHECK_EQ(client, window_tree_client_);
- window_tree_client_->RemoveObserver(this);
- window_tree_client_ = nullptr;
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router.h b/chromium/ui/views/mus/pointer_watcher_event_router.h
deleted file mode 100644
index 48cfa96930e..00000000000
--- a/chromium/ui/views/mus/pointer_watcher_event_router.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_MUS_POINTER_WATCHER_EVENT_ROUTER_H_
-#define UI_VIEWS_MUS_POINTER_WATCHER_EVENT_ROUTER_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "ui/aura/client/capture_client_observer.h"
-#include "ui/aura/mus/window_tree_client_observer.h"
-#include "ui/views/mus/mus_export.h"
-
-namespace aura {
-class WindowTreeClient;
-
-namespace client {
-class CaptureClient;
-}
-}
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class PointerEvent;
-}
-
-namespace views {
-
-class PointerWatcher;
-class PointerWatcherEventRouterTest;
-
-// PointerWatcherEventRouter is responsible for maintaining the list of
-// PointerWatchers and notifying appropriately. It is expected the owner of
-// PointerWatcherEventRouter is a WindowTreeClientDelegate and calls
-// OnPointerEventObserved().
-class VIEWS_MUS_EXPORT PointerWatcherEventRouter
- : public aura::WindowTreeClientObserver,
- public aura::client::CaptureClientObserver {
- public:
- // Public solely for tests.
- enum EventTypes {
- // No PointerWatchers have been added.
- NONE,
-
- // Used when the only PointerWatchers added do not want moves.
- NON_MOVE_EVENTS,
-
- // Used when at least one PointerWatcher has been added that wants moves.
- MOVE_EVENTS,
- };
-
- explicit PointerWatcherEventRouter(
- aura::WindowTreeClient* window_tree_client);
- ~PointerWatcherEventRouter() override;
-
- void AddPointerWatcher(PointerWatcher* watcher, bool wants_moves);
- void RemovePointerWatcher(PointerWatcher* watcher);
-
- // Called by WindowTreeClientDelegate to notify PointerWatchers appropriately.
- void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- aura::Window* target);
-
- // Called when the |capture_client| has been set or will be unset.
- void AttachToCaptureClient(aura::client::CaptureClient* capture_client);
- void DetachFromCaptureClient(aura::client::CaptureClient* capture_client);
-
- private:
- friend class PointerWatcherEventRouterTest;
-
- // Determines EventTypes based on the number and type of PointerWatchers.
- EventTypes DetermineEventTypes();
-
- // aura::WindowTreeClientObserver:
- void OnWillDestroyClient(aura::WindowTreeClient* client) override;
-
- // aura::client::CaptureClientObserver:
- void OnCaptureChanged(aura::Window* lost_capture,
- aura::Window* gained_capture) override;
-
- aura::WindowTreeClient* window_tree_client_;
- // The true parameter to ObserverList indicates the list must be empty on
- // destruction. Two sets of observers are maintained, one for observers not
- // needing moves |non_move_watchers_| and |move_watchers_| for those
- // observers wanting moves too.
- base::ObserverList<views::PointerWatcher, true>::Unchecked non_move_watchers_;
- base::ObserverList<views::PointerWatcher, true>::Unchecked move_watchers_;
-
- EventTypes event_types_ = EventTypes::NONE;
-
- DISALLOW_COPY_AND_ASSIGN(PointerWatcherEventRouter);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_MUS_POINTER_WATCHER_EVENT_ROUTER_H_
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
deleted file mode 100644
index 0f6143e0c43..00000000000
--- a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/mus/pointer_watcher_event_router.h"
-
-#include <memory>
-
-#include "base/test/scoped_task_environment.h"
-#include "ui/aura/test/mus/window_tree_client_private.h"
-#include "ui/events/event.h"
-#include "ui/views/mus/mus_client.h"
-#include "ui/views/pointer_watcher.h"
-#include "ui/views/test/views_test_base.h"
-
-namespace views {
-namespace {
-
-class TestPointerWatcher : public PointerWatcher {
- public:
- TestPointerWatcher() {}
- ~TestPointerWatcher() override {}
-
- ui::PointerEvent* last_event_observed() { return last_event_observed_.get(); }
- gfx::Point last_location_in_screen() { return last_location_in_screen_; }
-
- void Reset() {
- last_event_observed_.reset();
- last_location_in_screen_ = gfx::Point();
- }
-
- // PointerWatcher:
- void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- gfx::NativeView target) override {
- last_event_observed_ = std::make_unique<ui::PointerEvent>(event);
- last_location_in_screen_ = location_in_screen;
- }
-
- private:
- std::unique_ptr<ui::PointerEvent> last_event_observed_;
- gfx::Point last_location_in_screen_;
-
- DISALLOW_COPY_AND_ASSIGN(TestPointerWatcher);
-};
-
-} // namespace
-
-class PointerWatcherEventRouterTest : public views::ViewsTestBase {
- public:
- PointerWatcherEventRouterTest() = default;
- ~PointerWatcherEventRouterTest() override = default;
-
- void OnPointerEventObserved(const ui::PointerEvent& event) {
- MusClient::Get()->pointer_watcher_event_router()->OnPointerEventObserved(
- event, event.root_location(), nullptr);
- }
-
- PointerWatcherEventRouter::EventTypes event_types() const {
- return MusClient::Get()->pointer_watcher_event_router()->event_types_;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PointerWatcherEventRouterTest);
-};
-
-TEST_F(PointerWatcherEventRouterTest, EventTypes) {
- TestPointerWatcher pointer_watcher1, pointer_watcher2;
- PointerWatcherEventRouter* pointer_watcher_event_router =
- MusClient::Get()->pointer_watcher_event_router();
- aura::WindowTreeClientPrivate test_api(
- MusClient::Get()->window_tree_client());
- EXPECT_FALSE(test_api.HasPointerWatcher());
-
- // Start with no moves.
- pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher1, false);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NON_MOVE_EVENTS,
- event_types());
- EXPECT_TRUE(test_api.HasPointerWatcher());
-
- // Add moves.
- pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher2, true);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
- EXPECT_TRUE(test_api.HasPointerWatcher());
-
- // Remove no-moves.
- pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher1);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
- EXPECT_TRUE(test_api.HasPointerWatcher());
-
- // Remove moves.
- pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher2);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NONE, event_types());
- EXPECT_FALSE(test_api.HasPointerWatcher());
-
- // Add moves.
- pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher2, true);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
- EXPECT_TRUE(test_api.HasPointerWatcher());
-
- // Add no moves.
- pointer_watcher_event_router->AddPointerWatcher(&pointer_watcher1, false);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::MOVE_EVENTS, event_types());
- EXPECT_TRUE(test_api.HasPointerWatcher());
-
- // Remove moves.
- pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher2);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NON_MOVE_EVENTS,
- event_types());
- EXPECT_TRUE(test_api.HasPointerWatcher());
-
- // Remove no-moves.
- pointer_watcher_event_router->RemovePointerWatcher(&pointer_watcher1);
- EXPECT_EQ(PointerWatcherEventRouter::EventTypes::NONE, event_types());
- EXPECT_FALSE(test_api.HasPointerWatcher());
-}
-
-TEST_F(PointerWatcherEventRouterTest, PointerWatcherNoMove) {
- ASSERT_TRUE(MusClient::Get());
- PointerWatcherEventRouter* pointer_watcher_event_router =
- MusClient::Get()->pointer_watcher_event_router();
- ASSERT_TRUE(pointer_watcher_event_router);
-
- ui::PointerEvent pointer_event_down(
- ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks());
- ui::PointerEvent pointer_event_up(
- ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), ui::EF_NONE, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 1),
- base::TimeTicks());
- ui::PointerEvent pointer_event_wheel(
- ui::ET_POINTER_WHEEL_CHANGED, gfx::Point(), gfx::Point(), ui::EF_NONE, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 1),
- base::TimeTicks());
- ui::PointerEvent pointer_event_capture(
- ui::ET_POINTER_CAPTURE_CHANGED, gfx::Point(), gfx::Point(), ui::EF_NONE,
- 0, ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 1),
- base::TimeTicks());
-
- // PointerWatchers receive pointer down events.
- TestPointerWatcher watcher1;
- pointer_watcher_event_router->AddPointerWatcher(&watcher1, false);
- OnPointerEventObserved(pointer_event_down);
- EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type());
- watcher1.Reset();
-
- // PointerWatchers receive pointer up events.
- OnPointerEventObserved(pointer_event_up);
- EXPECT_EQ(ui::ET_POINTER_UP, watcher1.last_event_observed()->type());
- watcher1.Reset();
-
- // PointerWatchers receive pointer wheel changed events.
- OnPointerEventObserved(pointer_event_wheel);
- EXPECT_EQ(ui::ET_POINTER_WHEEL_CHANGED,
- watcher1.last_event_observed()->type());
- watcher1.Reset();
-
- // PointerWatchers receive pointer capture changed events.
- OnPointerEventObserved(pointer_event_capture);
- EXPECT_EQ(ui::ET_POINTER_CAPTURE_CHANGED,
- watcher1.last_event_observed()->type());
- watcher1.Reset();
-
- // Two PointerWatchers can both receive a single observed event.
- TestPointerWatcher watcher2;
- pointer_watcher_event_router->AddPointerWatcher(&watcher2, false);
- OnPointerEventObserved(pointer_event_down);
- EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type());
- EXPECT_EQ(ui::ET_POINTER_DOWN, watcher2.last_event_observed()->type());
- watcher1.Reset();
- watcher2.Reset();
-
- // Removing the first PointerWatcher stops sending events to it.
- pointer_watcher_event_router->RemovePointerWatcher(&watcher1);
- OnPointerEventObserved(pointer_event_down);
- EXPECT_FALSE(watcher1.last_event_observed());
- EXPECT_EQ(ui::ET_POINTER_DOWN, watcher2.last_event_observed()->type());
- watcher1.Reset();
- watcher2.Reset();
-
- // Removing the last PointerWatcher stops sending events to it.
- pointer_watcher_event_router->RemovePointerWatcher(&watcher2);
- OnPointerEventObserved(pointer_event_down);
- EXPECT_FALSE(watcher1.last_event_observed());
- EXPECT_FALSE(watcher2.last_event_observed());
-}
-
-TEST_F(PointerWatcherEventRouterTest, PointerWatcherMove) {
- ASSERT_TRUE(MusClient::Get());
- PointerWatcherEventRouter* pointer_watcher_event_router =
- MusClient::Get()->pointer_watcher_event_router();
- ASSERT_TRUE(pointer_watcher_event_router);
-
- ui::PointerEvent pointer_event_down(
- ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks());
- ui::PointerEvent pointer_event_move(
- ui::ET_POINTER_MOVED, gfx::Point(), gfx::Point(), ui::EF_NONE, 0,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
- base::TimeTicks());
-
- // PointerWatchers receive pointer down events.
- TestPointerWatcher watcher1;
- pointer_watcher_event_router->AddPointerWatcher(&watcher1, true);
- OnPointerEventObserved(pointer_event_down);
- EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type());
- watcher1.Reset();
-
- // PointerWatchers receive pointer move events.
- OnPointerEventObserved(pointer_event_move);
- EXPECT_EQ(ui::ET_POINTER_MOVED, watcher1.last_event_observed()->type());
- watcher1.Reset();
-
- // Two PointerWatchers can both receive a single observed event.
- TestPointerWatcher watcher2;
- pointer_watcher_event_router->AddPointerWatcher(&watcher2, true);
- OnPointerEventObserved(pointer_event_move);
- EXPECT_EQ(ui::ET_POINTER_MOVED, watcher1.last_event_observed()->type());
- EXPECT_EQ(ui::ET_POINTER_MOVED, watcher2.last_event_observed()->type());
- watcher1.Reset();
- watcher2.Reset();
-
- // Removing the first PointerWatcher stops sending events to it.
- pointer_watcher_event_router->RemovePointerWatcher(&watcher1);
- OnPointerEventObserved(pointer_event_move);
- EXPECT_FALSE(watcher1.last_event_observed());
- EXPECT_EQ(ui::ET_POINTER_MOVED, watcher2.last_event_observed()->type());
- watcher1.Reset();
- watcher2.Reset();
-
- // Removing the last PointerWatcher stops sending events to it.
- pointer_watcher_event_router->RemovePointerWatcher(&watcher2);
- OnPointerEventObserved(pointer_event_move);
- EXPECT_FALSE(watcher1.last_event_observed());
- EXPECT_FALSE(watcher2.last_event_observed());
-}
-
-} // namespace views
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
index 1beddbf9de8..d5713e1460a 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ b/chromium/ui/views/mus/views_mus_test_suite.cc
@@ -19,6 +19,7 @@
#include "services/catalog/catalog.h"
#include "services/service_manager/background/background_service_manager.h"
#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/constants.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/ws/common/switches.h"
@@ -126,8 +127,9 @@ class ServiceManagerConnection {
context_ = std::make_unique<service_manager::ServiceContext>(
std::make_unique<DefaultService>(), mojo::MakeRequest(&service));
background_service_manager_->RegisterService(
- service_manager::Identity(
- GetTestName(), service_manager::mojom::kRootUserID),
+ service_manager::Identity(GetTestName(),
+ service_manager::kSystemInstanceGroup,
+ base::Token{}, base::Token::CreateRandom()),
std::move(service), nullptr);
service_manager_connector_ = context_->connector()->Clone();
service_manager_identity_ = context_->identity();
diff --git a/chromium/ui/views/pointer_watcher.h b/chromium/ui/views/pointer_watcher.h
deleted file mode 100644
index 74159af12aa..00000000000
--- a/chromium/ui/views/pointer_watcher.h
+++ /dev/null
@@ -1,65 +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_POINTER_WATCHER_H_
-#define UI_VIEWS_POINTER_WATCHER_H_
-
-#include "base/macros.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/views/views_export.h"
-
-namespace gfx {
-class Point;
-}
-
-namespace ui {
-class PointerEvent;
-}
-
-namespace views {
-
-// When a PointerWatcher is added the types of events desired is specified by
-// way of PointerWatcherEventTypes.
-enum class PointerWatcherEventTypes {
- // The PointerWatcher is interested in press, release, capture and mouse
- // wheel.
- BASIC,
- // The PointerWatcher is interested in BASIC events, as well as move
- // events.
- MOVES,
- // The PointerWatcher is interested in MOVE events, as well as drag
- // events.
- DRAGS
-};
-
-// An interface for read-only observation of pointer events (in particular, the
-// events cannot be marked as handled). Only certain event types are supported.
-// The |target| is the native window that will receive the event, if any.
-// To reduce IPC traffic from the window server, move events are not provided
-// unless the app specifically requests them.
-// NOTE: On mus this allows observation of events outside of windows owned
-// by the current process, in which case the |target| will be null. On mus
-// event.target() is always null.
-// NOTE: Mouse capture change events are sent through OnPointerEventObserved and
-// its |target| is always null.
-// NOTE: |target| may or may not have an associated views::Widget that may not
-// be a top-level Widget.
-class VIEWS_EXPORT PointerWatcher {
- public:
- PointerWatcher() {}
-
- virtual void OnPointerEventObserved(const ui::PointerEvent& event,
- const gfx::Point& location_in_screen,
- gfx::NativeView target) = 0;
-
- protected:
- virtual ~PointerWatcher() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PointerWatcher);
-};
-
-} // namespace views
-
-#endif // UI_VIEWS_POINTER_WATCHER_H_
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom.png
deleted file mode 100644
index aeb7dcb4acd..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused.png
deleted file mode 100644
index 8b5944e2efb..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_hover.png
deleted file mode 100644
index ccb7cd3567f..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_pressed.png
deleted file mode 100644
index 3c74ef7e90d..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_hover.png
deleted file mode 100644
index 0279262fa65..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left.png
deleted file mode 100644
index 66836356a1c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused.png
deleted file mode 100644
index c0f012fc39c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_hover.png
deleted file mode 100644
index 6f86b3b7cd8..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_pressed.png
deleted file mode 100644
index 05d7d75ca06..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_hover.png
deleted file mode 100644
index 3d7f3606837..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_pressed.png
deleted file mode 100644
index ed9595d84f4..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_pressed.png
deleted file mode 100644
index def48730595..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right.png
deleted file mode 100644
index 63dc232d433..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused.png
deleted file mode 100644
index b2b523e86e5..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_hover.png
deleted file mode 100644
index e4ee6a65815..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_pressed.png
deleted file mode 100644
index 3c74ef7e90d..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_hover.png
deleted file mode 100644
index e9f06486f5e..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_pressed.png
deleted file mode 100644
index def48730595..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_bottom_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center.png
deleted file mode 100644
index 14e97622b6b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused.png
deleted file mode 100644
index 14e97622b6b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_hover.png
deleted file mode 100644
index 5b9fb5fcf24..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_pressed.png
deleted file mode 100644
index 8d522222526..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_hover.png
deleted file mode 100644
index 5b9fb5fcf24..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left.png
deleted file mode 100644
index 25e93d31dc0..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused.png
deleted file mode 100644
index 3ab0e25ce5b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_hover.png
deleted file mode 100644
index dfdfe2c86f6..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_pressed.png
deleted file mode 100644
index 621636c122a..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_hover.png
deleted file mode 100644
index e74682ef65d..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_pressed.png
deleted file mode 100644
index 32411a2e492..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_pressed.png
deleted file mode 100644
index 8d522222526..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right.png
deleted file mode 100644
index bd141c48b47..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused.png
deleted file mode 100644
index bd141c48b47..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_hover.png
deleted file mode 100644
index c3141746b0a..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_pressed.png
deleted file mode 100644
index 8d522222526..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_hover.png
deleted file mode 100644
index c3141746b0a..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_pressed.png
deleted file mode 100644
index 8d522222526..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_center_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom.png
deleted file mode 100644
index 34b0b02d89f..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused.png
deleted file mode 100644
index 5eb45a0465f..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_hover.png
deleted file mode 100644
index 69941569fb8..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_pressed.png
deleted file mode 100644
index 4320fecaef5..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_hover.png
deleted file mode 100644
index 821402c310b..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_pressed.png
deleted file mode 100644
index e85e49ae403..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_bottom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center.png
deleted file mode 100644
index b22f3b99f16..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused.png
deleted file mode 100644
index e94f4a6e966..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_hover.png
deleted file mode 100644
index d2fa901b9d2..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_pressed.png
deleted file mode 100644
index e092be5b5b4..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_hover.png
deleted file mode 100644
index 25a09ed1dec..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_pressed.png
deleted file mode 100644
index a73b684e593..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_center_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top.png
deleted file mode 100644
index 40eb1932cfd..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused.png
deleted file mode 100644
index 08053ed8d96..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_hover.png
deleted file mode 100644
index 75c6d20bce7..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_pressed.png
deleted file mode 100644
index 51ada79402e..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_hover.png
deleted file mode 100644
index b85ed7a1c93..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_pressed.png
deleted file mode 100644
index 14ba21db031..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_menu_top_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top.png
deleted file mode 100644
index aeede822d58..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused.png
deleted file mode 100644
index ea1bd674476..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_hover.png
deleted file mode 100644
index 5227e00a109..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_pressed.png
deleted file mode 100644
index b44fa533fe1..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_hover.png
deleted file mode 100644
index 05535aee697..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left.png
deleted file mode 100644
index 7d27ba90f9d..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused.png
deleted file mode 100644
index 776e6dd8e6c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_hover.png
deleted file mode 100644
index 7d2932dc442..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_pressed.png
deleted file mode 100644
index b1daeb61023..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_hover.png
deleted file mode 100644
index 74df462627f..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_pressed.png
deleted file mode 100644
index bc9f437e57c..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_pressed.png
deleted file mode 100644
index a0867f6aa62..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right.png
deleted file mode 100644
index f13445f9077..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused.png
deleted file mode 100644
index 43f7b24021e..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_hover.png
deleted file mode 100644
index 49adefc9ecd..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_pressed.png
deleted file mode 100644
index b44fa533fe1..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_hover.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_hover.png
deleted file mode 100644
index 361068af7f1..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_pressed.png b/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_pressed.png
deleted file mode 100644
index a0867f6aa62..00000000000
--- a/chromium/ui/views/resources/default_100_percent/common/combobox_button_top_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom.png
deleted file mode 100644
index 7092a150a70..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused.png
deleted file mode 100644
index 1c219dfa2f1..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_hover.png
deleted file mode 100644
index 695e8543cd1..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_pressed.png
deleted file mode 100644
index a9208865991..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_hover.png
deleted file mode 100644
index 8d7a2497f90..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left.png
deleted file mode 100644
index f092b6560fc..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused.png
deleted file mode 100644
index 8f3d372522f..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_hover.png
deleted file mode 100644
index f2bd26fe1be..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_pressed.png
deleted file mode 100644
index 860a2744099..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_hover.png
deleted file mode 100644
index 764cb588809..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_pressed.png
deleted file mode 100644
index 4645e11559a..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_pressed.png
deleted file mode 100644
index bb419b32e36..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right.png
deleted file mode 100644
index 350dd633475..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused.png
deleted file mode 100644
index c9c078436ea..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_hover.png
deleted file mode 100644
index a3559de9eaa..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_pressed.png
deleted file mode 100644
index a9208865991..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_hover.png
deleted file mode 100644
index 4d6a63fd39a..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_pressed.png
deleted file mode 100644
index bb419b32e36..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_bottom_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center.png
deleted file mode 100644
index 303031f014d..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused.png
deleted file mode 100644
index 303031f014d..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_hover.png
deleted file mode 100644
index 4e3d77552bf..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_pressed.png
deleted file mode 100644
index 17d9ec3a755..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_hover.png
deleted file mode 100644
index 4e3d77552bf..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left.png
deleted file mode 100644
index 055ce6c1d16..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused.png
deleted file mode 100644
index 974aaabf025..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_hover.png
deleted file mode 100644
index 96d6ef9581c..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_pressed.png
deleted file mode 100644
index 1b69bdebc70..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_hover.png
deleted file mode 100644
index 3870e562059..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_pressed.png
deleted file mode 100644
index 7bb30da2dae..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_pressed.png
deleted file mode 100644
index 17d9ec3a755..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right.png
deleted file mode 100644
index ebba1d4b7a5..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused.png
deleted file mode 100644
index ebba1d4b7a5..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_hover.png
deleted file mode 100644
index f48cfa38774..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_pressed.png
deleted file mode 100644
index 17d9ec3a755..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_hover.png
deleted file mode 100644
index f48cfa38774..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_pressed.png
deleted file mode 100644
index 17d9ec3a755..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_center_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom.png
deleted file mode 100644
index b279ff8e039..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused.png
deleted file mode 100644
index 9ef1e9e1231..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_hover.png
deleted file mode 100644
index 599813921a0..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_pressed.png
deleted file mode 100644
index afaec86a618..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_hover.png
deleted file mode 100644
index 755c582a67f..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_pressed.png
deleted file mode 100644
index 885d008f4ec..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_bottom_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center.png
deleted file mode 100644
index b09a70f237d..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused.png
deleted file mode 100644
index d5d02d2c4c0..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_hover.png
deleted file mode 100644
index ec3fc63deed..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_pressed.png
deleted file mode 100644
index f05b3a1a24a..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_hover.png
deleted file mode 100644
index 06512b64141..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_pressed.png
deleted file mode 100644
index 408af30d647..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_center_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top.png
deleted file mode 100644
index 1703b122794..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused.png
deleted file mode 100644
index 0fa55b8e095..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_hover.png
deleted file mode 100644
index 88a965cea67..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_pressed.png
deleted file mode 100644
index abed0e1ce16..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_hover.png
deleted file mode 100644
index 5928ec7bc29..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_pressed.png
deleted file mode 100644
index 1e3c086d910..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_menu_top_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top.png
deleted file mode 100644
index 8fdb8ea4d7b..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused.png
deleted file mode 100644
index 3c5f5bf4ddd..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_hover.png
deleted file mode 100644
index ac4d094e45f..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_pressed.png
deleted file mode 100644
index 3c82cca45c6..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_hover.png
deleted file mode 100644
index 928418fc867..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left.png
deleted file mode 100644
index 9888825f1bf..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused.png
deleted file mode 100644
index 653418c4ef9..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_hover.png
deleted file mode 100644
index 0b098973c38..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_pressed.png
deleted file mode 100644
index fac760c7e13..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_hover.png
deleted file mode 100644
index 694d0dc9d18..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_pressed.png
deleted file mode 100644
index eda07dacfcd..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_left_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_pressed.png
deleted file mode 100644
index 924ce68207e..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right.png
deleted file mode 100644
index ce5bfe5f271..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused.png
deleted file mode 100644
index e71ec77a543..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_hover.png
deleted file mode 100644
index 7def2490ff2..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_pressed.png
deleted file mode 100644
index 3c82cca45c6..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_focused_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_hover.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_hover.png
deleted file mode 100644
index 7ab4e33106d..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_hover.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_pressed.png b/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_pressed.png
deleted file mode 100644
index 924ce68207e..00000000000
--- a/chromium/ui/views/resources/default_200_percent/common/combobox_button_top_right_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chromium/ui/views/resources/views_resources.grd b/chromium/ui/views/resources/views_resources.grd
index 9b6b99641ba..c8a2a8aedf7 100644
--- a/chromium/ui/views/resources/views_resources.grd
+++ b/chromium/ui/views/resources/views_resources.grd
@@ -22,13 +22,6 @@
<structure type="chrome_scaled_image" name="IDR_BUTTON_HOVER" file="common/button_hover.png" />
<structure type="chrome_scaled_image" name="IDR_BUTTON_NORMAL" file="common/button.png" />
<structure type="chrome_scaled_image" name="IDR_BUTTON_PRESSED" file="common/button_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_DISABLED" file="common/blue_button_inactive.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_HOVER" file="common/blue_button_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_NORMAL" file="common/blue_button_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_FOCUSED_PRESSED" file="common/blue_button_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_HOVER" file="common/blue_button_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_NORMAL" file="common/blue_button.png" />
- <structure type="chrome_scaled_image" name="IDR_BLUE_BUTTON_PRESSED" file="common/blue_button_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_CHECKBOX" file="common/checkbox.png" />
<structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED" file="common/checkbox_checked.png" />
<structure type="chrome_scaled_image" name="IDR_CHECKBOX_CHECKED_DISABLED" file="common/checkbox_checked_inactive.png" />
@@ -53,78 +46,6 @@
<structure type="chrome_scaled_image" name="IDR_CLOSE_H" file="close_hover.png" />
<structure type="chrome_scaled_image" name="IDR_CLOSE_P" file="close_pressed.png" />
</if>
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM" file="common/combobox_button_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM" file="common/combobox_button_bottom_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM" file="common/combobox_button_bottom_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM_LEFT" file="common/combobox_button_bottom_left.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM_LEFT" file="common/combobox_button_bottom_left_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM_LEFT" file="common/combobox_button_bottom_left_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_BOTTOM_RIGHT" file="common/combobox_button_bottom_right.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_CENTER" file="common/combobox_button_center.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_CENTER" file="common/combobox_button_center_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_CENTER" file="common/combobox_button_center_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_LEFT" file="common/combobox_button_center_left.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_LEFT" file="common/combobox_button_center_left_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_LEFT" file="common/combobox_button_center_left_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_RIGHT" file="common/combobox_button_center_right.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_RIGHT" file="common/combobox_button_center_right_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_RIGHT" file="common/combobox_button_center_right_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_BOTTOM" file="common/combobox_button_menu_bottom.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_BOTTOM" file="common/combobox_button_menu_bottom_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_BOTTOM" file="common/combobox_button_menu_bottom_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_CENTER" file="common/combobox_button_menu_center.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_CENTER" file="common/combobox_button_menu_center_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_CENTER" file="common/combobox_button_menu_center_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_MENU_TOP" file="common/combobox_button_menu_top.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_MENU_TOP" file="common/combobox_button_menu_top_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_MENU_TOP" file="common/combobox_button_menu_top_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP" file="common/combobox_button_top.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP" file="common/combobox_button_top_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP" file="common/combobox_button_top_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP_LEFT" file="common/combobox_button_top_left.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP_LEFT" file="common/combobox_button_top_left_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP_LEFT" file="common/combobox_button_top_left_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_TOP_RIGHT" file="common/combobox_button_top_right.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_H_TOP_RIGHT" file="common/combobox_button_top_right_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_P_TOP_RIGHT" file="common/combobox_button_top_right_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM" file="common/combobox_button_bottom_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM" file="common/combobox_button_bottom_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM" file="common/combobox_button_bottom_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM_LEFT" file="common/combobox_button_bottom_left_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_BOTTOM_RIGHT" file="common/combobox_button_bottom_right_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_CENTER" file="common/combobox_button_center_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_CENTER" file="common/combobox_button_center_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_CENTER" file="common/combobox_button_center_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_LEFT" file="common/combobox_button_center_left_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_LEFT" file="common/combobox_button_center_left_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_LEFT" file="common/combobox_button_center_left_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_RIGHT" file="common/combobox_button_center_right_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_RIGHT" file="common/combobox_button_center_right_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_RIGHT" file="common/combobox_button_center_right_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_BOTTOM" file="common/combobox_button_menu_bottom_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_CENTER" file="common/combobox_button_menu_center_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_CENTER" file="common/combobox_button_menu_center_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_CENTER" file="common/combobox_button_menu_center_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_MENU_TOP" file="common/combobox_button_menu_top_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_MENU_TOP" file="common/combobox_button_menu_top_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_MENU_TOP" file="common/combobox_button_menu_top_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP" file="common/combobox_button_top_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP" file="common/combobox_button_top_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP" file="common/combobox_button_top_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP_LEFT" file="common/combobox_button_top_left_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP_LEFT" file="common/combobox_button_top_left_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP_LEFT" file="common/combobox_button_top_left_focused_pressed.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_TOP_RIGHT" file="common/combobox_button_top_right_focused.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_H_TOP_RIGHT" file="common/combobox_button_top_right_focused_hover.png" />
- <structure type="chrome_scaled_image" name="IDR_COMBOBOX_BUTTON_F_P_TOP_RIGHT" file="common/combobox_button_top_right_focused_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_CENTER" file="content_bottom_center.png" />
<structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_LEFT_CORNER" file="content_bottom_left_corner.png" />
<structure type="chrome_scaled_image" name="IDR_CONTENT_BOTTOM_RIGHT_CORNER" file="content_bottom_right_corner.png" />
diff --git a/chromium/ui/views/style/platform_style.cc b/chromium/ui/views/style/platform_style.cc
index 564d6e6440b..da35f106869 100644
--- a/chromium/ui/views/style/platform_style.cc
+++ b/chromium/ui/views/style/platform_style.cc
@@ -5,7 +5,6 @@
#include "ui/views/style/platform_style.h"
#include "build/build_config.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/shadow_value.h"
@@ -61,8 +60,8 @@ const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = false;
const bool PlatformStyle::kUseRipples = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = false;
const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = true;
-const bool PlatformStyle::kShouldElideBookmarksInBookmarksBar = false;
const bool PlatformStyle::kPreferFocusRings = false;
+const bool PlatformStyle::kInactiveWidgetControlsAppearDisabled = false;
// static
std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
diff --git a/chromium/ui/views/style/platform_style.h b/chromium/ui/views/style/platform_style.h
index b8e74bedb0b..36706db23ea 100644
--- a/chromium/ui/views/style/platform_style.h
+++ b/chromium/ui/views/style/platform_style.h
@@ -70,10 +70,6 @@ class VIEWS_EXPORT PlatformStyle {
// dragging but available to do so.
static const bool kTextfieldUsesDragCursorWhenDraggable;
- // Whether bookmarks in the bookmarks bar are elided [and show elipses at the
- // tail] or fade out.
- static const bool kShouldElideBookmarksInBookmarksBar;
-
// The thickness and inset amount of focus ring halos.
static const float kFocusHaloThickness;
static const float kFocusHaloInset;
@@ -83,6 +79,9 @@ class VIEWS_EXPORT PlatformStyle {
// hover state on focus.
static const bool kPreferFocusRings;
+ // Whether controls in inactive widgets appear disabled.
+ static const bool kInactiveWidgetControlsAppearDisabled;
+
// Creates the default scrollbar for the given orientation.
static std::unique_ptr<ScrollBar> CreateScrollBar(bool is_horizontal);
diff --git a/chromium/ui/views/style/platform_style_mac.mm b/chromium/ui/views/style/platform_style_mac.mm
index 945f4b2efcf..be2299823a8 100644
--- a/chromium/ui/views/style/platform_style_mac.mm
+++ b/chromium/ui/views/style/platform_style_mac.mm
@@ -40,9 +40,9 @@ const bool PlatformStyle::kSelectAllOnRightClickWhenUnfocused = true;
const bool PlatformStyle::kTextfieldScrollsToStartOnFocusChange = true;
const bool PlatformStyle::kTextfieldUsesDragCursorWhenDraggable = false;
const bool PlatformStyle::kTreeViewSelectionPaintsEntireRow = true;
-const bool PlatformStyle::kShouldElideBookmarksInBookmarksBar = true;
const bool PlatformStyle::kUseRipples = false;
const bool PlatformStyle::kPreferFocusRings = true;
+const bool PlatformStyle::kInactiveWidgetControlsAppearDisabled = true;
const Button::NotifyAction PlatformStyle::kMenuNotifyActivationAction =
Button::NOTIFY_ON_PRESS;
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.cc b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
index 5264dfe5712..93e0b4b85f3 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.cc
@@ -4,6 +4,9 @@
#include "ui/views/touchui/touch_selection_controller_impl.h"
+#include <set>
+
+#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "ui/aura/client/cursor_client.h"
@@ -116,7 +119,7 @@ gfx::Image* GetRightHandleImage() {
// Return the appropriate handle image based on the bound's type
gfx::Image* GetHandleImage(gfx::SelectionBound::Type bound_type) {
- switch(bound_type) {
+ switch (bound_type) {
case gfx::SelectionBound::LEFT:
return GetLeftHandleImage();
case gfx::SelectionBound::CENTER:
@@ -126,7 +129,7 @@ gfx::Image* GetHandleImage(gfx::SelectionBound::Type bound_type) {
default:
NOTREACHED() << "Invalid touch handle bound type: " << bound_type;
return nullptr;
- };
+ }
}
// Calculates the bounds of the widget containing the selection handle based
@@ -155,7 +158,7 @@ gfx::Rect GetSelectionWidgetBounds(const gfx::SelectionBound& bound) {
default:
NOTREACHED() << "Undefined bound type.";
break;
- };
+ }
return gfx::Rect(
widget_left, bound.edge_top_rounded().y(), widget_width, widget_height);
}
@@ -417,18 +420,19 @@ TouchSelectionControllerImpl::TouchSelectionControllerImpl(
// 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);
+
+ // Observe certain event types sent to any event target, to hide this ui.
+ aura::Env* env = aura::Env::GetInstance();
+ std::set<ui::EventType> types = {ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_MOVED,
+ ui::ET_KEY_PRESSED, ui::ET_MOUSEWHEEL};
+ env->AddEventObserver(this, env, types);
}
TouchSelectionControllerImpl::~TouchSelectionControllerImpl() {
UMA_HISTOGRAM_BOOLEAN("Event.TouchSelection.EndedWithAction",
command_executed_);
HideQuickMenu();
- aura::Env::GetInstance()->RemovePreTargetHandler(this);
- if (ViewsDelegate::GetInstance()->IsPointerWatcherSupported())
- ViewsDelegate::GetInstance()->RemovePointerWatcher(this);
+ aura::Env::GetInstance()->RemoveEventObserver(this);
if (client_widget_)
client_widget_->RemoveObserver(this);
}
@@ -613,6 +617,16 @@ void TouchSelectionControllerImpl::RunContextMenu() {
client_view_->OpenContextMenu(anchor);
}
+bool TouchSelectionControllerImpl::ShouldShowQuickMenu() {
+ NOTREACHED();
+ return false;
+}
+
+base::string16 TouchSelectionControllerImpl::GetSelectedText() {
+ NOTREACHED();
+ return base::string16();
+}
+
void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) {
DCHECK_EQ(client_widget_, widget);
client_widget_->RemoveObserver(this);
@@ -626,39 +640,27 @@ 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();
-}
-
-void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
- aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
- client_view_->GetNativeView()->GetRootWindow());
- if (cursor_client && !cursor_client->IsMouseEventsEnabled())
- return;
-
- // Do not hide handles on mouse-capture-changed event which might occur when a
- // selection handle is released. Normally, cursor client should report mouse
- // events as disabled (the above check), but there are crashes on Windows
- // devices suggesting it is not always the case (see crbug.com/459423).
- if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
- return;
+void TouchSelectionControllerImpl::OnEvent(const ui::Event& event) {
+ if (event.IsMouseEvent()) {
+ // Check IsMouseEventsEnabled, except on Mus, where it's disabled on touch
+ // events in this client, but not re-enabled on mouse events elsewhere.
+ auto* cursor = aura::client::GetCursorClient(
+ client_view_->GetNativeView()->GetRootWindow());
+ if (cursor && !cursor->IsMouseEventsEnabled() &&
+ aura::Env::GetInstance()->mode() != aura::Env::Mode::MUS) {
+ return;
+ }
- client_view_->DestroyTouchSelection();
-}
+ // Windows OS unhandled WM_POINTER* may be redispatched as WM_MOUSE*.
+ // Avoid adjusting the handles on synthesized events or events generated
+ // from touch as this can clear an active selection generated by the pen.
+ if ((event.flags() & (ui::EF_IS_SYNTHESIZED | ui::EF_FROM_TOUCH)) ||
+ event.AsMouseEvent()->pointer_details().pointer_type ==
+ ui::EventPointerType::POINTER_TYPE_PEN) {
+ return;
+ }
+ }
-void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
client_view_->DestroyTouchSelection();
}
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl.h b/chromium/ui/views/touchui/touch_selection_controller_impl.h
index 7e231e126e1..e748afcdbdd 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl.h
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl.h
@@ -5,13 +5,15 @@
#ifndef UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
#define UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_
+#include <memory>
+
#include "base/macros.h"
#include "base/timer/timer.h"
-#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/base/pointer/touch_editing_controller.h"
+#include "ui/events/event_observer.h"
#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"
@@ -30,8 +32,7 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
: public ui::TouchEditingControllerDeprecated,
public ui::TouchSelectionMenuClient,
public WidgetObserver,
- public PointerWatcher,
- public ui::EventHandler {
+ public ui::EventObserver {
public:
class EditingHandleView;
@@ -74,21 +75,16 @@ class VIEWS_EXPORT TouchSelectionControllerImpl
bool IsCommandIdEnabled(int command_id) const override;
void ExecuteCommand(int command_id, int event_flags) override;
void RunContextMenu() override;
+ bool ShouldShowQuickMenu() override;
+ base::string16 GetSelectedText() override;
// WidgetObserver:
void OnWidgetClosing(Widget* widget) override;
void OnWidgetBoundsChanged(Widget* widget,
const gfx::Rect& new_bounds) override;
- // 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;
+ // ui::EventObserver:
+ void OnEvent(const ui::Event& event) override;
// Time to show quick menu.
void QuickMenuTimerFired();
diff --git a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
index c3385f66992..cd66a6ddc9d 100644
--- a/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
+++ b/chromium/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -12,8 +12,8 @@
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/base/pointer/touch_editing_controller.h"
#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/touch/touch_editing_controller.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
@@ -842,7 +842,7 @@ TEST_F(TouchSelectionControllerImplTest, MouseEventDeactivatesTouchSelection) {
ui::test::EventGenerator generator(
textfield_widget_->GetNativeView()->GetRootWindow());
- generator.set_current_location(gfx::Point(5, 5));
+ generator.set_current_screen_location(gfx::Point(5, 5));
RunPendingMessages();
// Start touch editing; then move mouse over the textfield and ensure it
diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
index 7a99a8f697c..7d4991dbbf7 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
+++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.cc
@@ -6,229 +6,13 @@
#include <stddef.h>
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
#include "ui/aura/window.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/text_utils.h"
-#include "ui/strings/grit/ui_strings.h"
-#include "ui/views/bubble/bubble_dialog_delegate_view.h"
-#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/style/typography.h"
+#include "ui/views/touchui/touch_selection_menu_views.h"
namespace views {
-namespace {
-
-const int kMenuCommands[] = {IDS_APP_CUT, IDS_APP_COPY, IDS_APP_PASTE};
-const int kSpacingBetweenButtons = 2;
-const int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0);
-const int kMenuButtonMinHeight = 38;
-const int kMenuButtonMinWidth = 63;
-const int kMenuMargin = 1;
-
-const char kEllipsesButtonText[] = "...";
-const int kEllipsesButtonTag = -1;
-
-} // namespace
-
-// A bubble that contains actions available for the selected text. An object of
-// this type, as a BubbleDialogDelegateView, manages its own lifetime.
-class TouchSelectionMenuRunnerViews::Menu : public BubbleDialogDelegateView,
- public ButtonListener {
- public:
- Menu(TouchSelectionMenuRunnerViews* owner,
- ui::TouchSelectionMenuClient* client,
- const gfx::Rect& anchor_rect,
- const gfx::Size& handle_image_size,
- aura::Window* context);
-
- // Checks whether there is any command available to show in the menu.
- static bool IsMenuAvailable(const ui::TouchSelectionMenuClient* client);
-
- // Closes the menu. This will eventually self-destroy the object.
- void CloseMenu();
-
- private:
- friend class TouchSelectionMenuRunnerViews::TestApi;
-
- ~Menu() override;
-
- // Queries the |client_| for what commands to show in the menu and sizes the
- // menu appropriately.
- void CreateButtons();
-
- // Helper method to create a single button.
- Button* CreateButton(const base::string16& title, int tag);
-
- // Helper to disconnect this menu object from its owning menu runner.
- void DisconnectOwner();
-
- // BubbleDialogDelegateView:
- void OnPaint(gfx::Canvas* canvas) override;
- void WindowClosing() override;
- int GetDialogButtons() const override;
-
- // ButtonListener:
- void ButtonPressed(Button* sender, const ui::Event& event) override;
-
- TouchSelectionMenuRunnerViews* owner_;
- ui::TouchSelectionMenuClient* const client_;
-
- DISALLOW_COPY_AND_ASSIGN(Menu);
-};
-
-TouchSelectionMenuRunnerViews::Menu::Menu(TouchSelectionMenuRunnerViews* owner,
- ui::TouchSelectionMenuClient* client,
- const gfx::Rect& anchor_rect,
- const gfx::Size& handle_image_size,
- aura::Window* context)
- : BubbleDialogDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER),
- owner_(owner),
- client_(client) {
- DCHECK(owner_);
- DCHECK(client_);
-
- set_shadow(BubbleBorder::SMALL_SHADOW);
- set_parent_window(context);
- set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin));
- set_can_activate(false);
- set_adjust_if_offscreen(true);
- EnableCanvasFlippingForRTLUI(true);
-
- SetLayoutManager(std::make_unique<BoxLayout>(
- BoxLayout::kHorizontal, gfx::Insets(), kSpacingBetweenButtons));
- CreateButtons();
-
- // After buttons are created, check if there is enough room between handles to
- // show the menu and adjust anchor rect properly if needed, just in case the
- // menu is needed to be shown under the selection.
- gfx::Rect adjusted_anchor_rect(anchor_rect);
- int menu_width = GetPreferredSize().width();
- // TODO(mfomitchev): This assumes that the handles are center-aligned to the
- // |achor_rect| edges, which is not true. We should fix this, perhaps by
- // passing down the cumulative width occupied by the handles within
- // |anchor_rect| plus the handle image height instead of |handle_image_size|.
- // Perhaps we should also allow for some minimum padding.
- if (menu_width > anchor_rect.width() - handle_image_size.width())
- adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height());
- SetAnchorRect(adjusted_anchor_rect);
-
- BubbleDialogDelegateView::CreateBubble(this);
- Widget* widget = GetWidget();
- gfx::Rect bounds = widget->GetWindowBoundsInScreen();
- gfx::Rect work_area = display::Screen::GetScreen()
- ->GetDisplayNearestPoint(bounds.origin())
- .work_area();
- if (!work_area.IsEmpty()) {
- bounds.AdjustToFit(work_area);
- widget->SetBounds(bounds);
- }
- // Using BubbleDialogDelegateView engages its CreateBubbleWidget() which
- // invokes widget->StackAbove(context). That causes the bubble to stack
- // _immediately_ above |context|; below any already-existing bubbles. That
- // doesn't make sense for a menu, so put it back on top.
- widget->StackAtTop();
- widget->Show();
-}
-
-bool TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable(
- const ui::TouchSelectionMenuClient* client) {
- DCHECK(client);
-
- for (size_t i = 0; i < arraysize(kMenuCommands); i++) {
- if (client->IsCommandIdEnabled(kMenuCommands[i]))
- return true;
- }
- return false;
-}
-
-TouchSelectionMenuRunnerViews::Menu::~Menu() {
-}
-
-void TouchSelectionMenuRunnerViews::Menu::CreateButtons() {
- for (size_t i = 0; i < arraysize(kMenuCommands); i++) {
- int command_id = kMenuCommands[i];
- if (!client_->IsCommandIdEnabled(command_id))
- continue;
-
- Button* button =
- CreateButton(l10n_util::GetStringUTF16(command_id), command_id);
- AddChildView(button);
- }
-
- // Finally, add ellipses button.
- AddChildView(
- CreateButton(base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
- Layout();
-}
-
-Button* TouchSelectionMenuRunnerViews::Menu::CreateButton(
- const base::string16& title,
- int tag) {
- base::string16 label =
- gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr);
- LabelButton* button = new LabelButton(this, label, style::CONTEXT_TOUCH_MENU);
- button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight));
- button->SetFocusForPlatform();
- button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
- button->set_tag(tag);
- return button;
-}
-
-void TouchSelectionMenuRunnerViews::Menu::CloseMenu() {
- DisconnectOwner();
- // Closing the widget will self-destroy this object.
- Widget* widget = GetWidget();
- if (widget && !widget->IsClosed())
- widget->Close();
-}
-
-void TouchSelectionMenuRunnerViews::Menu::DisconnectOwner() {
- DCHECK(owner_);
- owner_->menu_ = nullptr;
- owner_ = nullptr;
-}
-
-void TouchSelectionMenuRunnerViews::Menu::OnPaint(gfx::Canvas* canvas) {
- BubbleDialogDelegateView::OnPaint(canvas);
-
- // Draw separator bars.
- for (int i = 0; i < child_count() - 1; ++i) {
- View* child = child_at(i);
- int x = child->bounds().right() + kSpacingBetweenButtons / 2;
- canvas->FillRect(gfx::Rect(x, 0, 1, child->height()),
- kButtonSeparatorColor);
- }
-}
-
-void TouchSelectionMenuRunnerViews::Menu::WindowClosing() {
- DCHECK(!owner_ || owner_->menu_ == this);
- BubbleDialogDelegateView::WindowClosing();
- if (owner_)
- DisconnectOwner();
-}
-
-int TouchSelectionMenuRunnerViews::Menu::GetDialogButtons() const {
- return ui::DIALOG_BUTTON_NONE;
-}
-
-void TouchSelectionMenuRunnerViews::Menu::ButtonPressed(
- Button* sender,
- const ui::Event& event) {
- CloseMenu();
- if (sender->tag() != kEllipsesButtonTag)
- client_->ExecuteCommand(sender->tag(), event.flags());
- else
- client_->RunContextMenu();
-}
TouchSelectionMenuRunnerViews::TestApi::TestApi(
TouchSelectionMenuRunnerViews* menu_runner)
@@ -239,17 +23,17 @@ TouchSelectionMenuRunnerViews::TestApi::TestApi(
TouchSelectionMenuRunnerViews::TestApi::~TestApi() {}
gfx::Rect TouchSelectionMenuRunnerViews::TestApi::GetAnchorRect() const {
- TouchSelectionMenuRunnerViews::Menu* menu = menu_runner_->menu_;
+ TouchSelectionMenuViews* menu = menu_runner_->menu_;
return menu ? menu->GetAnchorRect() : gfx::Rect();
}
-Button* TouchSelectionMenuRunnerViews::TestApi::GetFirstButton() const {
- TouchSelectionMenuRunnerViews::Menu* menu = menu_runner_->menu_;
- return menu ? static_cast<Button*>(menu->child_at(0)) : nullptr;
+LabelButton* TouchSelectionMenuRunnerViews::TestApi::GetFirstButton() const {
+ TouchSelectionMenuViews* menu = menu_runner_->menu_;
+ return menu ? static_cast<LabelButton*>(menu->child_at(0)) : nullptr;
}
Widget* TouchSelectionMenuRunnerViews::TestApi::GetWidget() const {
- TouchSelectionMenuRunnerViews::Menu* menu = menu_runner_->menu_;
+ TouchSelectionMenuViews* menu = menu_runner_->menu_;
return menu ? menu->GetWidget() : nullptr;
}
TouchSelectionMenuRunnerViews::TouchSelectionMenuRunnerViews()
@@ -260,9 +44,17 @@ TouchSelectionMenuRunnerViews::~TouchSelectionMenuRunnerViews() {
CloseMenu();
}
+void TouchSelectionMenuRunnerViews::ShowMenu(
+ TouchSelectionMenuViews* menu,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size) {
+ menu_ = menu;
+ menu_->ShowMenu(anchor_rect, handle_image_size);
+}
+
bool TouchSelectionMenuRunnerViews::IsMenuAvailable(
const ui::TouchSelectionMenuClient* client) const {
- return TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable(client);
+ return TouchSelectionMenuViews::IsMenuAvailable(client);
}
void TouchSelectionMenuRunnerViews::OpenMenu(
@@ -272,8 +64,11 @@ void TouchSelectionMenuRunnerViews::OpenMenu(
aura::Window* context) {
CloseMenu();
- if (TouchSelectionMenuRunnerViews::Menu::IsMenuAvailable(client))
- menu_ = new Menu(this, client, anchor_rect, handle_image_size, context);
+ if (!TouchSelectionMenuViews::IsMenuAvailable(client))
+ return;
+
+ menu_ = new TouchSelectionMenuViews(this, client, context);
+ menu_->ShowMenu(anchor_rect, handle_image_size);
}
void TouchSelectionMenuRunnerViews::CloseMenu() {
diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views.h b/chromium/ui/views/touchui/touch_selection_menu_runner_views.h
index 0ce40600a99..0761e249b8b 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_runner_views.h
+++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views.h
@@ -9,10 +9,12 @@
#include "base/macros.h"
#include "ui/touch_selection/touch_selection_menu_runner.h"
+#include "ui/views/controls/button/button.h"
#include "ui/views/views_export.h"
namespace views {
-class Button;
+class LabelButton;
+class TouchSelectionMenuViews;
class Widget;
// Views implementation for TouchSelectionMenuRunner.
@@ -26,7 +28,7 @@ class VIEWS_EXPORT TouchSelectionMenuRunnerViews
~TestApi();
gfx::Rect GetAnchorRect() const;
- Button* GetFirstButton() const;
+ LabelButton* GetFirstButton() const;
Widget* GetWidget() const;
private:
@@ -38,23 +40,28 @@ class VIEWS_EXPORT TouchSelectionMenuRunnerViews
TouchSelectionMenuRunnerViews();
~TouchSelectionMenuRunnerViews() override;
- private:
- friend class TouchSelectionMenuRunnerViewsTestApi;
- class Menu;
+ protected:
+ // Sets the menu as the currently runner menu and shows it.
+ void ShowMenu(TouchSelectionMenuViews* menu,
+ const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size);
// ui::TouchSelectionMenuRunner:
bool IsMenuAvailable(
const ui::TouchSelectionMenuClient* client) const override;
+ void CloseMenu() override;
void OpenMenu(ui::TouchSelectionMenuClient* client,
const gfx::Rect& anchor_rect,
const gfx::Size& handle_image_size,
aura::Window* context) override;
- void CloseMenu() override;
bool IsRunning() const override;
+ private:
+ friend class TouchSelectionMenuViews;
+
// A pointer to the currently running menu, or |nullptr| if no menu is
// running. The menu manages its own lifetime and deletes itself when closed.
- Menu* menu_;
+ TouchSelectionMenuViews* menu_;
DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuRunnerViews);
};
diff --git a/chromium/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc b/chromium/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc
index 281ebd72452..cf555e3f7af 100644
--- a/chromium/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc
+++ b/chromium/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc
@@ -2,12 +2,13 @@
// 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_menu_runner_views.h"
+
#include "base/macros.h"
#include "ui/events/event_utils.h"
#include "ui/touch_selection/touch_selection_menu_runner.h"
-#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/label_button.h"
#include "ui/views/test/views_test_base.h"
-#include "ui/views/touchui/touch_selection_menu_runner_views.h"
namespace views {
namespace {
@@ -53,6 +54,10 @@ class TouchSelectionMenuRunnerViewsTest : public ViewsTestBase,
void RunContextMenu() override {}
+ base::string16 GetSelectedText() override { return base::string16(); }
+
+ bool ShouldShowQuickMenu() override { return false; }
+
// When set to true, no command would be available and menu should not be
// shown.
bool no_command_available_;
@@ -152,7 +157,7 @@ TEST_F(TouchSelectionMenuRunnerViewsTest, RunningActionClosesProperly) {
// Tap the first action on the menu and check taht the menu is closed
// properly.
- Button* button = test_api.GetFirstButton();
+ LabelButton* button = test_api.GetFirstButton();
DCHECK(button);
gfx::Point button_center = button->bounds().CenterPoint();
ui::GestureEventDetails details(ui::ET_GESTURE_TAP);
diff --git a/chromium/ui/views/touchui/touch_selection_menu_views.cc b/chromium/ui/views/touchui/touch_selection_menu_views.cc
new file mode 100644
index 00000000000..0c339bfe380
--- /dev/null
+++ b/chromium/ui/views/touchui/touch_selection_menu_views.cc
@@ -0,0 +1,185 @@
+// 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_menu_views.h"
+
+#include <memory>
+
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/text_utils.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/touch_selection/touch_selection_menu_runner.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace views {
+namespace {
+
+constexpr int kMenuCommands[] = {IDS_APP_CUT, IDS_APP_COPY, IDS_APP_PASTE};
+constexpr int kSpacingBetweenButtons = 2;
+constexpr int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0);
+constexpr int kMenuButtonMinHeight = 38;
+constexpr int kMenuButtonMinWidth = 63;
+constexpr int kMenuMargin = 1;
+
+constexpr char kEllipsesButtonText[] = "...";
+constexpr int kEllipsesButtonTag = -1;
+
+} // namespace
+
+TouchSelectionMenuViews::TouchSelectionMenuViews(
+ TouchSelectionMenuRunnerViews* owner,
+ ui::TouchSelectionMenuClient* client,
+ aura::Window* context)
+ : BubbleDialogDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER),
+ owner_(owner),
+ client_(client) {
+ DCHECK(owner_);
+ DCHECK(client_);
+
+ set_shadow(BubbleBorder::SMALL_SHADOW);
+ set_parent_window(context);
+ set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin));
+ set_can_activate(false);
+ set_adjust_if_offscreen(true);
+ EnableCanvasFlippingForRTLUI(true);
+
+ SetLayoutManager(std::make_unique<BoxLayout>(
+ BoxLayout::kHorizontal, gfx::Insets(), kSpacingBetweenButtons));
+}
+
+void TouchSelectionMenuViews::ShowMenu(const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size) {
+ CreateButtons();
+
+ // After buttons are created, check if there is enough room between handles to
+ // show the menu and adjust anchor rect properly if needed, just in case the
+ // menu is needed to be shown under the selection.
+ gfx::Rect adjusted_anchor_rect(anchor_rect);
+ int menu_width = GetPreferredSize().width();
+ // TODO(mfomitchev): This assumes that the handles are center-aligned to the
+ // |achor_rect| edges, which is not true. We should fix this, perhaps by
+ // passing down the cumulative width occupied by the handles within
+ // |anchor_rect| plus the handle image height instead of |handle_image_size|.
+ // Perhaps we should also allow for some minimum padding.
+ if (menu_width > anchor_rect.width() - handle_image_size.width())
+ adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height());
+ SetAnchorRect(adjusted_anchor_rect);
+
+ BubbleDialogDelegateView::CreateBubble(this);
+ Widget* widget = GetWidget();
+ gfx::Rect bounds = widget->GetWindowBoundsInScreen();
+ gfx::Rect work_area = display::Screen::GetScreen()
+ ->GetDisplayNearestPoint(bounds.origin())
+ .work_area();
+ if (!work_area.IsEmpty()) {
+ bounds.AdjustToFit(work_area);
+ widget->SetBounds(bounds);
+ }
+ // Using BubbleDialogDelegateView engages its CreateBubbleWidget() which
+ // invokes widget->StackAbove(context). That causes the bubble to stack
+ // _immediately_ above |context|; below any already-existing bubbles. That
+ // doesn't make sense for a menu, so put it back on top.
+ widget->StackAtTop();
+ widget->Show();
+}
+
+bool TouchSelectionMenuViews::IsMenuAvailable(
+ const ui::TouchSelectionMenuClient* client) {
+ DCHECK(client);
+
+ for (size_t i = 0; i < base::size(kMenuCommands); i++) {
+ if (client->IsCommandIdEnabled(kMenuCommands[i]))
+ return true;
+ }
+ return false;
+}
+
+void TouchSelectionMenuViews::CloseMenu() {
+ DisconnectOwner();
+ // Closing the widget will self-destroy this object.
+ Widget* widget = GetWidget();
+ if (widget && !widget->IsClosed())
+ widget->Close();
+}
+
+TouchSelectionMenuViews::~TouchSelectionMenuViews() = default;
+
+void TouchSelectionMenuViews::CreateButtons() {
+ for (size_t i = 0; i < base::size(kMenuCommands); i++) {
+ int command_id = kMenuCommands[i];
+ if (!client_->IsCommandIdEnabled(command_id))
+ continue;
+
+ Button* button =
+ CreateButton(l10n_util::GetStringUTF16(command_id), command_id);
+ AddChildView(button);
+ }
+
+ // Finally, add ellipses button.
+ AddChildView(
+ CreateButton(base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag));
+ Layout();
+}
+
+LabelButton* TouchSelectionMenuViews::CreateButton(const base::string16& title,
+ int tag) {
+ base::string16 label =
+ gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr);
+ LabelButton* button = new LabelButton(this, label, style::CONTEXT_TOUCH_MENU);
+ button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight));
+ button->SetFocusForPlatform();
+ button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
+ button->set_tag(tag);
+ return button;
+}
+
+void TouchSelectionMenuViews::DisconnectOwner() {
+ DCHECK(owner_);
+ owner_->menu_ = nullptr;
+ owner_ = nullptr;
+}
+
+void TouchSelectionMenuViews::OnPaint(gfx::Canvas* canvas) {
+ BubbleDialogDelegateView::OnPaint(canvas);
+
+ // Draw separator bars.
+ for (int i = 0; i < child_count() - 1; ++i) {
+ View* child = child_at(i);
+ int x = child->bounds().right() + kSpacingBetweenButtons / 2;
+ canvas->FillRect(gfx::Rect(x, 0, 1, child->height()),
+ kButtonSeparatorColor);
+ }
+}
+
+void TouchSelectionMenuViews::WindowClosing() {
+ DCHECK(!owner_ || owner_->menu_ == this);
+ BubbleDialogDelegateView::WindowClosing();
+ if (owner_)
+ DisconnectOwner();
+}
+
+int TouchSelectionMenuViews::GetDialogButtons() const {
+ return ui::DIALOG_BUTTON_NONE;
+}
+
+void TouchSelectionMenuViews::ButtonPressed(Button* sender,
+ const ui::Event& event) {
+ CloseMenu();
+ if (sender->tag() != kEllipsesButtonTag)
+ client_->ExecuteCommand(sender->tag(), event.flags());
+ else
+ client_->RunContextMenu();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/touchui/touch_selection_menu_views.h b/chromium/ui/views/touchui/touch_selection_menu_views.h
new file mode 100644
index 00000000000..a9882f269a0
--- /dev/null
+++ b/chromium/ui/views/touchui/touch_selection_menu_views.h
@@ -0,0 +1,70 @@
+// 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_TOUCHUI_TOUCH_SELECTION_MENU_VIEWS_H_
+#define UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_VIEWS_H_
+
+#include "base/macros.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/touchui/touch_selection_menu_runner_views.h"
+
+namespace ui {
+class TouchSelectionMenuClient;
+} // namespace ui
+
+namespace views {
+class LabelButton;
+
+// A bubble that contains actions available for the selected text. An object of
+// this type, as a BubbleDialogDelegateView, manages its own lifetime.
+class VIEWS_EXPORT TouchSelectionMenuViews : public BubbleDialogDelegateView,
+ public ButtonListener {
+ public:
+ TouchSelectionMenuViews(TouchSelectionMenuRunnerViews* owner,
+ ui::TouchSelectionMenuClient* client,
+ aura::Window* context);
+
+ void ShowMenu(const gfx::Rect& anchor_rect,
+ const gfx::Size& handle_image_size);
+
+ // Checks whether there is any command available to show in the menu.
+ static bool IsMenuAvailable(const ui::TouchSelectionMenuClient* client);
+
+ // Closes the menu. This will eventually self-destroy the object.
+ void CloseMenu();
+
+ protected:
+ ~TouchSelectionMenuViews() override;
+
+ // Queries the |client_| for what commands to show in the menu and sizes the
+ // menu appropriately.
+ virtual void CreateButtons();
+
+ // Helper method to create a single button.
+ LabelButton* CreateButton(const base::string16& title, int tag);
+
+ // ButtonListener:
+ void ButtonPressed(Button* sender, const ui::Event& event) override;
+
+ private:
+ friend class TouchSelectionMenuRunnerViews::TestApi;
+
+ // Helper to disconnect this menu object from its owning menu runner.
+ void DisconnectOwner();
+
+ // BubbleDialogDelegateView:
+ void OnPaint(gfx::Canvas* canvas) override;
+ void WindowClosing() override;
+ int GetDialogButtons() const override;
+
+ TouchSelectionMenuRunnerViews* owner_;
+ ui::TouchSelectionMenuClient* const client_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuViews);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_VIEWS_H_
diff --git a/chromium/ui/views/view.cc b/chromium/ui/views/view.cc
index d0aba92898f..b2429b98c42 100644
--- a/chromium/ui/views/view.cc
+++ b/chromium/ui/views/view.cc
@@ -44,6 +44,7 @@
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
#include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/ax_event_manager.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
@@ -52,7 +53,6 @@
#include "ui/views/layout/layout_manager.h"
#include "ui/views/view_observer.h"
#include "ui/views/view_tracker.h"
-#include "ui/views/views_delegate.h"
#include "ui/views/views_switches.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/root_view.h"
@@ -123,30 +123,7 @@ const char View::kViewClassName[] = "View";
// Creation and lifetime -------------------------------------------------------
-View::View()
- : owned_by_client_(false),
- id_(0),
- group_(-1),
- parent_(nullptr),
-#if DCHECK_IS_ON()
- iterating_(false),
-#endif
- can_process_events_within_subtree_(true),
- visible_(true),
- enabled_(true),
- notify_enter_exit_on_child_(false),
- registered_for_visible_bounds_notification_(false),
- needs_layout_(true),
- snap_layer_to_pixel_boundary_(false),
- flip_canvas_on_paint_for_rtl_ui_(false),
- paint_to_layer_(false),
- accelerator_focus_manager_(nullptr),
- registered_accelerator_count_(0),
- next_focusable_view_(nullptr),
- previous_focusable_view_(nullptr),
- focus_behavior_(FocusBehavior::NEVER),
- context_menu_controller_(nullptr),
- drag_controller_(nullptr) {
+View::View() {
SetTargetHandler(this);
}
@@ -446,6 +423,9 @@ void View::SizeToPreferredSize() {
}
gfx::Size View::GetMinimumSize() const {
+ if (layout_manager_)
+ return layout_manager_->GetMinimumSize(this);
+
return GetPreferredSize();
}
@@ -454,7 +434,7 @@ gfx::Size View::GetMaximumSize() const {
}
int View::GetHeightForWidth(int w) const {
- if (layout_manager_.get())
+ if (layout_manager_)
return layout_manager_->GetPreferredHeightForWidth(this, w);
return GetPreferredSize().height();
}
@@ -609,7 +589,7 @@ void View::Layout() {
needs_layout_ = false;
// If we have a layout manager, let it handle the layout for us.
- if (layout_manager_.get())
+ if (layout_manager_)
layout_manager_->Layout(this);
// Make sure to propagate the Layout() call to any children that haven't
@@ -632,6 +612,9 @@ void View::InvalidateLayout() {
// Always invalidate up. This is needed to handle the case of us already being
// valid, but not our parent.
needs_layout_ = true;
+ if (layout_manager_)
+ layout_manager_->InvalidateLayout();
+
if (parent_)
parent_->InvalidateLayout();
}
@@ -1468,8 +1451,7 @@ gfx::NativeViewAccessible View::GetNativeViewAccessible() {
void View::NotifyAccessibilityEvent(ax::mojom::Event event_type,
bool send_native_event) {
- if (ViewsDelegate::GetInstance())
- ViewsDelegate::GetInstance()->NotifyAccessibilityEvent(this, event_type);
+ AXEventManager::Get()->NotifyViewEvent(this, event_type);
if (send_native_event && GetWidget())
GetViewAccessibility().NotifyAccessibilityEvent(event_type);
@@ -1519,7 +1501,7 @@ bool View::HasObserver(const ViewObserver* observer) const {
// Size and disposition --------------------------------------------------------
gfx::Size View::CalculatePreferredSize() const {
- if (layout_manager_.get())
+ if (layout_manager_)
return layout_manager_->GetPreferredSize(this);
return gfx::Size();
}
diff --git a/chromium/ui/views/view.h b/chromium/ui/views/view.h
index 161e015c044..998c87a3d6f 100644
--- a/chromium/ui/views/view.h
+++ b/chromium/ui/views/view.h
@@ -1681,22 +1681,22 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// False if this View is owned by its parent - i.e. it will be deleted by its
// parent during its parents destruction. False is the default.
- bool owned_by_client_;
+ bool owned_by_client_ = false;
// Attributes ----------------------------------------------------------------
// The id of this View. Used to find this View.
- int id_;
+ int id_ = 0;
// The group of this view. Some view subclasses use this id to find other
// views of the same group. For example radio button uses this information
// to find other radio buttons.
- int group_;
+ int group_ = -1;
// Tree operations -----------------------------------------------------------
// This view's parent.
- View* parent_;
+ View* parent_ = nullptr;
// This view's children.
Views children_;
@@ -1704,10 +1704,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
#if DCHECK_IS_ON()
// True while iterating over |children_|. Used to detect and DCHECK when
// |children_| is mutated during iteration.
- mutable bool iterating_;
+ mutable bool iterating_ = false;
#endif
- bool can_process_events_within_subtree_;
+ bool can_process_events_within_subtree_ = true;
// Size and disposition ------------------------------------------------------
@@ -1717,10 +1717,10 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
gfx::Rect bounds_;
// Whether this view is visible.
- bool visible_;
+ bool visible_ = true;
// Whether this view is enabled.
- bool enabled_;
+ bool enabled_ = true;
// When this flag is on, a View receives a mouse-enter and mouse-leave event
// even if a descendant View is the event-recipient for the real mouse
@@ -1735,11 +1735,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// still into this view, this view receives a mouse-enter event if this flag
// is turned off, but doesn't if this flag is turned on.
// This flag is initialized to false.
- bool notify_enter_exit_on_child_;
+ bool notify_enter_exit_on_child_ = false;
// Whether or not RegisterViewForVisibleBoundsNotification on the RootView
// has been invoked.
- bool registered_for_visible_bounds_notification_;
+ bool registered_for_visible_bounds_notification_ = false;
// List of descendants wanting notification when their visible bounds change.
std::unique_ptr<Views> descendants_to_notify_;
@@ -1753,14 +1753,14 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Layout --------------------------------------------------------------------
// Whether the view needs to be laid out.
- bool needs_layout_;
+ bool needs_layout_ = true;
// The View's LayoutManager defines the sizing heuristics applied to child
// Views. The default is absolute positioning according to bounds_.
std::unique_ptr<LayoutManager> layout_manager_;
// Whether this View's layer should be snapped to the pixel boundary.
- bool snap_layer_to_pixel_boundary_;
+ bool snap_layer_to_pixel_boundary_ = false;
// Painting ------------------------------------------------------------------
@@ -1785,42 +1785,42 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// Indicates whether or not the gfx::Canvas object passed to View::Paint()
// is going to be flipped horizontally (using the appropriate transform) on
// right-to-left locales for this View.
- bool flip_canvas_on_paint_for_rtl_ui_;
+ bool flip_canvas_on_paint_for_rtl_ui_ = false;
// Accelerated painting ------------------------------------------------------
- bool paint_to_layer_;
+ bool paint_to_layer_ = false;
// Accelerators --------------------------------------------------------------
// Focus manager accelerators registered on.
- FocusManager* accelerator_focus_manager_;
+ FocusManager* accelerator_focus_manager_ = nullptr;
// The list of accelerators. List elements in the range
// [0, registered_accelerator_count_) are already registered to FocusManager,
// and the rest are not yet.
std::unique_ptr<std::vector<ui::Accelerator>> accelerators_;
- size_t registered_accelerator_count_;
+ size_t registered_accelerator_count_ = 0;
// Focus ---------------------------------------------------------------------
// Next view to be focused when the Tab key is pressed.
- View* next_focusable_view_;
+ View* next_focusable_view_ = nullptr;
// Next view to be focused when the Shift-Tab key combination is pressed.
- View* previous_focusable_view_;
+ View* previous_focusable_view_ = nullptr;
// The focus behavior of the view in regular and accessibility mode.
- FocusBehavior focus_behavior_;
+ FocusBehavior focus_behavior_ = FocusBehavior::NEVER;
// Context menus -------------------------------------------------------------
// The menu controller.
- ContextMenuController* context_menu_controller_;
+ ContextMenuController* context_menu_controller_ = nullptr;
// Drag and drop -------------------------------------------------------------
- DragController* drag_controller_;
+ DragController* drag_controller_ = nullptr;
// Input --------------------------------------------------------------------
diff --git a/chromium/ui/views/view_properties.cc b/chromium/ui/views/view_properties.cc
index 2f4f54e35ff..1b19cb4f490 100644
--- a/chromium/ui/views/view_properties.cc
+++ b/chromium/ui/views/view_properties.cc
@@ -20,7 +20,7 @@ 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*);
+DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, SkPath*);
namespace views {
@@ -29,6 +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);
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(SkPath, kHighlightPathKey, nullptr);
} // namespace views
diff --git a/chromium/ui/views/view_properties.h b/chromium/ui/views/view_properties.h
index 5f63c1b902d..a706ce8d713 100644
--- a/chromium/ui/views/view_properties.h
+++ b/chromium/ui/views/view_properties.h
@@ -8,9 +8,10 @@
#include "ui/base/class_property.h"
#include "ui/views/views_export.h"
+class SkPath;
+
namespace gfx {
class Insets;
-class Path;
} // namespace gfx
namespace views {
@@ -34,8 +35,7 @@ VIEWS_EXPORT extern const ui::ClassProperty<BubbleDialogDelegateView*>* const
// 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;
+VIEWS_EXPORT extern const ui::ClassProperty<SkPath*>* const kHighlightPathKey;
} // namespace views
@@ -47,5 +47,5 @@ VIEWS_EXPORT extern const ui::ClassProperty<gfx::Path*>* 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*);
+DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT, SkPath*);
#endif // UI_VIEWS_VIEW_PROPERTIES_H_
diff --git a/chromium/ui/views/view_unittest.cc b/chromium/ui/views/view_unittest.cc
index a294b7f2be1..e34bf29ac18 100644
--- a/chromium/ui/views/view_unittest.cc
+++ b/chromium/ui/views/view_unittest.cc
@@ -14,11 +14,13 @@
#include "base/macros.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
#include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/paint/display_item_list.h"
#include "ui/base/accelerators/accelerator.h"
@@ -3664,8 +3666,8 @@ TEST_F(ViewTest, GetViewByID) {
View::Views views;
v1.GetViewsInGroup(kGroup, &views);
EXPECT_EQ(2U, views.size());
- EXPECT_NE(views.cend(), std::find(views.cbegin(), views.cend(), &v3));
- EXPECT_NE(views.cend(), std::find(views.cbegin(), views.cend(), &v4));
+ EXPECT_TRUE(base::ContainsValue(views, &v3));
+ EXPECT_TRUE(base::ContainsValue(views, &v4));
}
TEST_F(ViewTest, AddExistingChild) {
@@ -4491,8 +4493,8 @@ TEST_F(ViewLayerTest, SnapLayerToPixel) {
widget()->SetContentsView(v1);
const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
- GetRootLayer()->GetCompositor()->SetScaleAndSize(1.25f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 1.25f, size, viz::LocalSurfaceIdAllocation());
v11->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
v1->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
@@ -4506,8 +4508,8 @@ TEST_F(ViewLayerTest, SnapLayerToPixel) {
EXPECT_EQ("-0.20 -0.20", ToString(v11->layer()->subpixel_position_offset()));
// DSF change should get propagated and update offsets.
- GetRootLayer()->GetCompositor()->SetScaleAndSize(1.5f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 1.5f, size, viz::LocalSurfaceIdAllocation());
EXPECT_EQ("0.33 0.33", ToString(v1->layer()->subpixel_position_offset()));
EXPECT_EQ("0.33 0.33", ToString(v11->layer()->subpixel_position_offset()));
@@ -4520,8 +4522,8 @@ TEST_F(ViewLayerTest, SnapLayerToPixel) {
EXPECT_EQ("0.33 0.33", ToString(v11->layer()->subpixel_position_offset()));
// Setting integral DSF should reset the offset.
- GetRootLayer()->GetCompositor()->SetScaleAndSize(2.0f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 2.0f, size, viz::LocalSurfaceIdAllocation());
EXPECT_EQ("0.00 0.00", ToString(v11->layer()->subpixel_position_offset()));
}
@@ -4590,8 +4592,8 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
widget()->SetContentsView(v1);
const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
- GetRootLayer()->GetCompositor()->SetScaleAndSize(1.6f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 1.6f, size, viz::LocalSurfaceIdAllocation());
v3->SetBoundsRect(gfx::Rect(14, 13, 13, 5));
v2->SetBoundsRect(gfx::Rect(7, 7, 50, 50));
@@ -4606,8 +4608,8 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
EXPECT_EQ("-0.37 -0.00", ToString(v3->layer()->subpixel_position_offset()));
// DSF change should get propagated and update offsets.
- GetRootLayer()->GetCompositor()->SetScaleAndSize(1.5f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 1.5f, size, viz::LocalSurfaceIdAllocation());
EXPECT_EQ("0.33 0.33", ToString(v1->layer()->subpixel_position_offset()));
EXPECT_EQ("0.33 0.67", ToString(v3->layer()->subpixel_position_offset()));
@@ -4616,8 +4618,8 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
PaintRecordingSizeTest(v3, gfx::Size(20, 7)); // Enclosing Rect = (20, 8)
v1->SetPaintToLayer();
- GetRootLayer()->GetCompositor()->SetScaleAndSize(1.33f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 1.33f, size, viz::LocalSurfaceIdAllocation());
EXPECT_EQ("0.02 0.02", ToString(v1->layer()->subpixel_position_offset()));
EXPECT_EQ("0.05 -0.45", ToString(v3->layer()->subpixel_position_offset()));
@@ -4633,8 +4635,8 @@ TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
EXPECT_EQ("0.06 -0.44", ToString(v3->layer()->subpixel_position_offset()));
// Setting integral DSF should reset the offset.
- GetRootLayer()->GetCompositor()->SetScaleAndSize(2.0f, size,
- viz::LocalSurfaceId());
+ GetRootLayer()->GetCompositor()->SetScaleAndSize(
+ 2.0f, size, viz::LocalSurfaceIdAllocation());
EXPECT_EQ("0.00 0.00", ToString(v3->layer()->subpixel_position_offset()));
}
@@ -4814,6 +4816,7 @@ class TestNativeTheme : public ui::NativeTheme {
return gfx::Rect();
}
bool UsesHighContrastColors() const override { return false; }
+ bool SystemDarkModeEnabled() const override { return false; }
private:
DISALLOW_COPY_AND_ASSIGN(TestNativeTheme);
diff --git a/chromium/ui/views/view_unittest_mac.mm b/chromium/ui/views/view_unittest_mac.mm
index f85ed6d4b94..85fa79f9061 100644
--- a/chromium/ui/views/view_unittest_mac.mm
+++ b/chromium/ui/views/view_unittest_mac.mm
@@ -96,13 +96,14 @@ class ViewMacTest : public test::WidgetTest {
[[FakeSwipeEvent alloc] init]);
[swipe_event setDeltaX:dx];
[swipe_event setDeltaY:dy];
- [swipe_event setWindow:widget_->GetNativeWindow()];
+ [swipe_event setWindow:widget_->GetNativeWindow().GetNativeNSWindow()];
[swipe_event setLocationInWindow:NSMakePoint(50, 50)];
[swipe_event setTimestamp:[[NSProcessInfo processInfo] systemUptime]];
// BridgedContentView should create an appropriate ui::GestureEvent and pass
// it to the Widget.
- [[widget_->GetNativeWindow() contentView] swipeWithEvent:swipe_event];
+ [[widget_->GetNativeWindow().GetNativeNSWindow() contentView]
+ swipeWithEvent:swipe_event];
return view_->last_swipe_gesture();
}
diff --git a/chromium/ui/views/views_delegate.cc b/chromium/ui/views/views_delegate.cc
index d580fde1f8b..7252607e6ee 100644
--- a/chromium/ui/views/views_delegate.cc
+++ b/chromium/ui/views/views_delegate.cc
@@ -4,6 +4,8 @@
#include "ui/views/views_delegate.h"
+#include <utility>
+
#include "base/command_line.h"
#include "build/build_config.h"
#include "ui/views/views_touch_selection_controller_factory.h"
@@ -14,11 +16,12 @@
#endif
namespace views {
+
namespace {
ViewsDelegate* views_delegate = nullptr;
-}
+} // namespace
ViewsDelegate::ViewsDelegate()
: editing_controller_factory_(new ViewsTouchEditingControllerFactory) {
@@ -58,9 +61,6 @@ bool ViewsDelegate::GetSavedWindowPlacement(
return false;
}
-void ViewsDelegate::NotifyAccessibilityEvent(View* view,
- ax::mojom::Event event_type) {}
-
void ViewsDelegate::NotifyMenuItemFocused(const base::string16& menu_name,
const base::string16& menu_item_name,
int item_index,
@@ -128,20 +128,11 @@ int ViewsDelegate::GetAppbarAutohideEdges(HMONITOR monitor,
}
#endif
-bool ViewsDelegate::ShouldMirrorArrowsInRTL() const {
- return true;
-}
-
-void ViewsDelegate::AddPointerWatcher(PointerWatcher*, bool) {
- NOTREACHED();
-}
-
-void ViewsDelegate::RemovePointerWatcher(PointerWatcher*) {
- NOTREACHED();
-}
-
-bool ViewsDelegate::IsPointerWatcherSupported() const {
- return false;
+#if defined(USE_AURA)
+void ViewsDelegate::SetTouchSelectionMenuRunner(
+ std::unique_ptr<TouchSelectionMenuRunnerViews> menu_runner) {
+ touch_selection_menu_runner_ = std::move(menu_runner);
}
+#endif
} // namespace views
diff --git a/chromium/ui/views/views_delegate.h b/chromium/ui/views/views_delegate.h
index b5237c3f20f..1a66e7d029d 100644
--- a/chromium/ui/views/views_delegate.h
+++ b/chromium/ui/views/views_delegate.h
@@ -17,7 +17,6 @@
#include "base/macros.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
-#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/views_export.h"
@@ -37,8 +36,6 @@ namespace views {
class NativeWidget;
class NonClientFrameView;
-class PointerWatcher;
-class View;
class Widget;
#if defined(USE_AURA)
@@ -126,9 +123,6 @@ class VIEWS_EXPORT ViewsDelegate {
gfx::Rect* bounds,
ui::WindowShowState* show_state) const;
- virtual void NotifyAccessibilityEvent(View* view,
- ax::mojom::Event event_type);
-
// For accessibility, notify the delegate that a menu item was focused
// so that alternate feedback (speech / magnified text) can be provided.
virtual void NotifyMenuItemFocused(const base::string16& menu_name,
@@ -196,20 +190,14 @@ class VIEWS_EXPORT ViewsDelegate {
const base::Closure& callback);
#endif
- // Whether to mirror the arrow of bubble dialogs in RTL, such that the bubble
- // 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();
+#if defined(USE_AURA)
+ void SetTouchSelectionMenuRunner(
+ std::unique_ptr<TouchSelectionMenuRunnerViews> menu_runner);
+#endif
+
private:
std::unique_ptr<ui::TouchEditingControllerFactory>
editing_controller_factory_;
diff --git a/chromium/ui/views/views_touch_selection_controller_factory.h b/chromium/ui/views/views_touch_selection_controller_factory.h
index 7f37398b631..113e19bab21 100644
--- a/chromium/ui/views/views_touch_selection_controller_factory.h
+++ b/chromium/ui/views/views_touch_selection_controller_factory.h
@@ -5,7 +5,7 @@
#ifndef UI_UI_VIEWS_VIEWS_TOUCH_SELECTION_CONTROLLER_FACTORY_H_
#define UI_UI_VIEWS_VIEWS_TOUCH_SELECTION_CONTROLLER_FACTORY_H_
-#include "ui/base/touch/touch_editing_controller.h"
+#include "ui/base/pointer/touch_editing_controller.h"
#include "ui/views/views_export.h"
namespace views {
diff --git a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
index aceec981589..45e70d362e2 100644
--- a/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/ax_native_widget_mac_unittest.mm
@@ -16,6 +16,7 @@
#include "ui/accessibility/ax_node_data.h"
#import "ui/accessibility/platform/ax_platform_node_mac.h"
#include "ui/base/ime/text_input_type.h"
+#include "ui/base/models/combobox_model.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/combobox/combobox.h"
@@ -115,8 +116,8 @@ class AXNativeWidgetMacTest : public test::WidgetTest {
// Accessibility hit tests come in Cocoa screen coordinates.
NSPoint midpoint_in_screen_ = gfx::ScreenPointToNSPoint(
widget()->GetWindowBoundsInScreen().CenterPoint());
- return
- [widget()->GetNativeWindow() accessibilityHitTest:midpoint_in_screen_];
+ return [widget()->GetNativeWindow().GetNativeNSWindow()
+ accessibilityHitTest:midpoint_in_screen_];
}
id AttributeValueAtMidpoint(NSString* attribute) {
@@ -304,10 +305,10 @@ TEST_F(AXNativeWidgetMacTest, FocusableElementsAreLeafNodes) {
1u,
[[button->GetNativeViewAccessible()
accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count]);
- EXPECT_EQ(button->label()->GetNativeViewAccessible(),
- [[button->GetNativeViewAccessible()
- accessibilityAttributeValue:NSAccessibilityChildrenAttribute]
- objectAtIndex:0]);
+ EXPECT_EQ(
+ button->label()->GetNativeViewAccessible(),
+ [button->GetNativeViewAccessible()
+ accessibilityAttributeValue:NSAccessibilityChildrenAttribute][0]);
// If the child is disabled, it should still be traversable.
button->label()->SetEnabled(false);
@@ -315,10 +316,10 @@ TEST_F(AXNativeWidgetMacTest, FocusableElementsAreLeafNodes) {
1u,
[[button->GetNativeViewAccessible()
accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count]);
- EXPECT_EQ(button->label()->GetNativeViewAccessible(),
- [[button->GetNativeViewAccessible()
- accessibilityAttributeValue:NSAccessibilityChildrenAttribute]
- objectAtIndex:0]);
+ EXPECT_EQ(
+ button->label()->GetNativeViewAccessible(),
+ [button->GetNativeViewAccessible()
+ accessibilityAttributeValue:NSAccessibilityChildrenAttribute][0]);
}
// Test for NSAccessibilityChildrenAttribute, and ensure it excludes ignored
@@ -411,7 +412,7 @@ TEST_F(AXNativeWidgetMacTest, NativeWindowProperties) {
// Make sure it's |view| in the hit test by checking its accessibility role.
EXPECT_EQ(NSAccessibilityGroupRole, AXRoleString());
- NSWindow* window = widget()->GetNativeWindow();
+ NSWindow* window = widget()->GetNativeWindow().GetNativeNSWindow();
EXPECT_NSEQ(window, AttributeValueAtMidpoint(NSAccessibilityWindowAttribute));
EXPECT_NSEQ(window, AttributeValueAtMidpoint(
NSAccessibilityTopLevelUIElementAttribute));
@@ -558,7 +559,7 @@ TEST_F(AXNativeWidgetMacTest, ViewWritableAttributes) {
[AttributeValueAtMidpoint(NSAccessibilityFocusedAttribute) boolValue]);
EXPECT_TRUE([ax_node
accessibilityIsAttributeSettable:NSAccessibilityFocusedAttribute]);
- [ax_node accessibilitySetValue:[NSNumber numberWithBool:YES]
+ [ax_node accessibilitySetValue:@YES
forAttribute:NSAccessibilityFocusedAttribute];
EXPECT_TRUE(
[AttributeValueAtMidpoint(NSAccessibilityFocusedAttribute) boolValue]);
@@ -747,7 +748,8 @@ TEST_F(AXNativeWidgetMacTest, ProtectedTextfields) {
// Get the Textfield accessibility object.
NSPoint midpoint = gfx::ScreenPointToNSPoint(GetWidgetBounds().CenterPoint());
- id ax_node = [widget()->GetNativeWindow() accessibilityHitTest:midpoint];
+ id ax_node = [widget()->GetNativeWindow().GetNativeNSWindow()
+ accessibilityHitTest:midpoint];
EXPECT_TRUE(ax_node);
// Create a native Cocoa NSSecureTextField to compare against.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
new file mode 100644
index 00000000000..a5bf57fce89
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -0,0 +1,110 @@
+// 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_drag_drop_client_ozone.h"
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/dragdrop/os_exchange_data_provider_aura.h"
+#include "ui/platform_window/platform_window_delegate.h"
+#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+
+namespace views {
+
+DesktopDragDropClientOzone::DesktopDragDropClientOzone(
+ aura::Window* root_window,
+ views::DesktopNativeCursorManager* cursor_manager,
+ ui::WmDragHandler* drag_handler)
+ : root_window_(root_window),
+ cursor_manager_(cursor_manager),
+ drag_handler_(drag_handler) {}
+
+DesktopDragDropClientOzone::~DesktopDragDropClientOzone() {
+ if (in_move_loop_)
+ DragCancel();
+}
+
+int DesktopDragDropClientOzone::StartDragAndDrop(
+ const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) {
+ if (!drag_handler_)
+ return ui::DragDropTypes::DragOperation::DRAG_NONE;
+
+ DCHECK(!in_move_loop_);
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ quit_closure_ = run_loop.QuitClosure();
+
+ // Chrome expects starting drag and drop to release capture.
+ aura::Window* capture_window =
+ aura::client::GetCaptureClient(root_window)->GetGlobalCaptureWindow();
+ if (capture_window)
+ capture_window->ReleaseCapture();
+
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(root_window);
+
+ initial_cursor_ = source_window->GetHost()->last_cursor();
+ drag_operation_ = operation;
+ cursor_client->SetCursor(
+ cursor_manager_->GetInitializedCursor(ui::CursorType::kGrabbing));
+
+ drag_handler_->StartDrag(
+ data, operation, cursor_client->GetCursor(),
+ base::BindOnce(&DesktopDragDropClientOzone::OnDragSessionClosed,
+ base::Unretained(this)));
+ in_move_loop_ = true;
+ run_loop.Run();
+ DragDropSessionCompleted();
+ return drag_operation_;
+}
+
+void DesktopDragDropClientOzone::DragCancel() {
+ QuitRunLoop();
+}
+
+bool DesktopDragDropClientOzone::IsDragDropInProgress() {
+ return in_move_loop_;
+}
+
+void DesktopDragDropClientOzone::AddObserver(
+ aura::client::DragDropClientObserver* observer) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopDragDropClientOzone::RemoveObserver(
+ aura::client::DragDropClientObserver* observer) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void DesktopDragDropClientOzone::OnDragSessionClosed(int dnd_action) {
+ drag_operation_ = dnd_action;
+ QuitRunLoop();
+}
+
+void DesktopDragDropClientOzone::DragDropSessionCompleted() {
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(root_window_);
+ if (!cursor_client)
+ return;
+
+ cursor_client->SetCursor(initial_cursor_);
+}
+
+void DesktopDragDropClientOzone::QuitRunLoop() {
+ in_move_loop_ = false;
+ if (quit_closure_.is_null())
+ return;
+ std::move(quit_closure_).Run();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
new file mode 100644
index 00000000000..e3632a7a7b0
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_OZONE_H_
+#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_OZONE_H_
+
+#include "base/callback.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+class DesktopNativeCursorManager;
+
+class VIEWS_EXPORT DesktopDragDropClientOzone
+ : public aura::client::DragDropClient {
+ public:
+ DesktopDragDropClientOzone(aura::Window* root_window,
+ views::DesktopNativeCursorManager* cursor_manager,
+ ui::WmDragHandler* drag_handler);
+ ~DesktopDragDropClientOzone() override;
+
+ void OnDragSessionClosed(int operation);
+
+ // Overridden from aura::client::DragDropClient:
+ int StartDragAndDrop(const ui::OSExchangeData& data,
+ aura::Window* root_window,
+ aura::Window* source_window,
+ const gfx::Point& root_location,
+ int operation,
+ ui::DragDropTypes::DragEventSource source) override;
+ void DragCancel() override;
+ bool IsDragDropInProgress() override;
+ void AddObserver(aura::client::DragDropClientObserver* observer) override;
+ void RemoveObserver(aura::client::DragDropClientObserver* observer) override;
+
+ private:
+ void DragDropSessionCompleted();
+ void QuitRunLoop();
+
+ aura::Window* const root_window_;
+
+ DesktopNativeCursorManager* cursor_manager_;
+
+ ui::WmDragHandler* const drag_handler_;
+
+ // Cursor in use prior to the move loop starting. Restored when the move loop
+ // quits.
+ gfx::NativeCursor initial_cursor_;
+
+ base::OnceClosure quit_closure_;
+
+ // The operation bitfield.
+ int drag_operation_ = 0;
+
+ // The flag that controls whether it has a nested run loop.
+ bool in_move_loop_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientOzone);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_DRAG_DROP_CLIENT_OZONE_H_
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
new file mode 100644
index 00000000000..a9b86494fee
--- /dev/null
+++ b/chromium/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone_unittest.cc
@@ -0,0 +1,121 @@
+// 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_drag_drop_client_ozone.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+#include "ui/platform_window/platform_window_handler/wm_drag_handler.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
+
+namespace views {
+
+namespace {
+
+class FakeWmDragHandler;
+
+// A fake handler, which initiates dragging.
+class FakeWmDragHandler : public ui::WmDragHandler {
+ public:
+ FakeWmDragHandler() : weak_ptr_factory_(this) {}
+ ~FakeWmDragHandler() override = default;
+
+ // ui::WmDragHandler
+ void StartDrag(const OSExchangeData& data,
+ const int operation,
+ gfx::NativeCursor cursor,
+ base::OnceCallback<void(int)> callback) override {
+ callback_ = std::move(callback);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(
+ [](base::OnceCallback<void(int)> callback) {
+ std::move(callback).Run(ui::DragDropTypes::DRAG_COPY);
+ },
+ std::move(callback_)));
+ }
+
+ private:
+ base::OnceCallback<void(int)> callback_;
+ base::WeakPtrFactory<FakeWmDragHandler> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeWmDragHandler);
+};
+
+} // namespace
+
+class DesktopDragDropClientOzoneTest : public ViewsTestBase {
+ public:
+ DesktopDragDropClientOzoneTest() = default;
+ ~DesktopDragDropClientOzoneTest() override = default;
+
+ int StartDragAndDrop() {
+ ui::OSExchangeData data;
+ data.SetString(base::ASCIIToUTF16("Test"));
+ SkBitmap drag_bitmap;
+ drag_bitmap.allocN32Pixels(10, 10);
+ drag_bitmap.eraseARGB(0xFF, 0, 0, 0);
+ gfx::ImageSkia drag_image(gfx::ImageSkia::CreateFrom1xBitmap(drag_bitmap));
+ data.provider().SetDragImage(drag_image, gfx::Vector2d());
+
+ return client_->StartDragAndDrop(
+ data, widget_->GetNativeWindow()->GetRootWindow(),
+ widget_->GetNativeWindow(), gfx::Point(),
+ ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE,
+ ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
+ }
+
+ // ViewsTestBase:
+ void SetUp() override {
+ ViewsTestBase::SetUp();
+ test_views_delegate()->set_use_desktop_native_widgets(true);
+
+ // Create widget to initiate the drags.
+ widget_ = std::make_unique<Widget>();
+ Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.native_widget = new DesktopNativeWidgetAura(widget_.get());
+ params.bounds = gfx::Rect(100, 100);
+ widget_->Init(params);
+ widget_->Show();
+
+ aura::Window* window = widget_->GetNativeWindow();
+ cursor_manager_ = std::make_unique<DesktopNativeCursorManager>();
+ drag_handler_ = std::make_unique<FakeWmDragHandler>();
+ client_ = std::make_unique<DesktopDragDropClientOzone>(
+ window, cursor_manager_.get(), drag_handler_.get());
+ }
+
+ void TearDown() override {
+ client_.reset();
+ cursor_manager_.reset();
+ drag_handler_.reset();
+ widget_.reset();
+ ViewsTestBase::TearDown();
+ }
+
+ private:
+ std::unique_ptr<DesktopDragDropClientOzone> client_;
+ std::unique_ptr<DesktopNativeCursorManager> cursor_manager_;
+ std::unique_ptr<FakeWmDragHandler> drag_handler_;
+
+ // The widget used to initiate drags.
+ std::unique_ptr<Widget> widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(DesktopDragDropClientOzoneTest);
+};
+
+TEST_F(DesktopDragDropClientOzoneTest, StartDrag) {
+ int result = StartDragAndDrop();
+ EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, result);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
index 9f4c1bd8f40..a9b0444cf0f 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.cc
@@ -4,8 +4,10 @@
#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
+#include "ui/wm/core/window_util.h"
namespace views {
@@ -15,6 +17,10 @@ DesktopFocusRules::DesktopFocusRules(aura::Window* content_window)
DesktopFocusRules::~DesktopFocusRules() {}
bool DesktopFocusRules::CanActivateWindow(aura::Window* window) const {
+ if (window && content_window_->GetRootWindow()->Contains(window) &&
+ wm::WindowStateIs(window->GetRootWindow(), ui::SHOW_STATE_MINIMIZED)) {
+ return true;
+ }
if (!BaseFocusRules::CanActivateWindow(window))
return false;
// Never activate a window that is not a child of the root window. Transients
@@ -22,6 +28,12 @@ bool DesktopFocusRules::CanActivateWindow(aura::Window* window) const {
return !window || content_window_->GetRootWindow()->Contains(window);
}
+bool DesktopFocusRules::CanFocusWindow(aura::Window* window,
+ const ui::Event* event) const {
+ return BaseFocusRules::CanFocusWindow(window, event) ||
+ wm::WindowStateIs(window->GetRootWindow(), ui::SHOW_STATE_MINIMIZED);
+}
+
bool DesktopFocusRules::SupportsChildActivation(aura::Window* window) const {
// In Desktop-Aura, only the content_window or children of the RootWindow are
// activatable.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
index dd21dc90fe8..96fc7f9b3b8 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_focus_rules.h
@@ -18,6 +18,8 @@ class DesktopFocusRules : public wm::BaseFocusRules {
private:
// Overridden from wm::BaseFocusRules:
bool CanActivateWindow(aura::Window* window) const override;
+ bool CanFocusWindow(aura::Window* window,
+ const ui::Event* event) const override;
bool SupportsChildActivation(aura::Window* window) const override;
bool IsWindowConsideredVisibleForActivation(
aura::Window* window) const override;
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 264858b3a46..252001f8731 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
@@ -315,6 +315,8 @@ void DesktopNativeWidgetAura::OnHostClosed() {
wm::SetActivationClient(host_->window(), NULL);
focus_client_.reset();
+ host_->window()->RemovePreTargetHandler(root_window_event_filter_.get());
+
host_->RemoveObserver(this);
host_.reset();
// WindowEventDispatcher owns |desktop_window_tree_host_|.
@@ -353,6 +355,13 @@ void DesktopNativeWidgetAura::OnDesktopWindowTreeHostDestroyed(
event_client_.reset();
}
+void DesktopNativeWidgetAura::NotifyAccessibilityEvent(
+ ax::mojom::Event event_type) {
+ if (!GetWidget() || !GetWidget()->GetRootView())
+ return;
+ GetWidget()->GetRootView()->NotifyAccessibilityEvent(event_type, true);
+}
+
void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
if (!native_widget_delegate_->OnNativeWidgetActivationChanged(active))
return;
@@ -361,6 +370,11 @@ void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
if (!activation_client)
return;
if (active) {
+ // TODO(nektar): We need to harmonize the firing of accessibility
+ // events between platforms.
+ // https://crbug.com/897177
+ NotifyAccessibilityEvent(ax::mojom::Event::kWindowActivated);
+
if (GetWidget()->HasFocusManager()) {
// This function can be called before the focus manager has had a
// chance to set the focused view. In which case we should get the
@@ -392,6 +406,11 @@ void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
GetInputMethod()->OnFocus();
}
} else {
+ // TODO(nektar): We need to harmonize the firing of accessibility
+ // events between platforms.
+ // https://crbug.com/897177
+ NotifyAccessibilityEvent(ax::mojom::Event::kWindowDeactivated);
+
// If we're not active we need to deactivate the corresponding
// aura::Window. This way if a child widget is active it gets correctly
// deactivated (child widgets don't get native desktop activation changes,
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index be95f3ad684..0189e561625 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -252,6 +252,9 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
void RootWindowDestroyed();
+ // Notify the root view of our widget of a native accessibility event.
+ void NotifyAccessibilityEvent(ax::mojom::Event event_type);
+
std::unique_ptr<aura::WindowTreeHost> host_;
DesktopWindowTreeHost* desktop_window_tree_host_;
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 2514071e8bd..ae3193c3304 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
@@ -14,6 +14,7 @@
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/window_parenting_client.h"
+#include "ui/aura/env.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/window_occlusion_tracker_test_api.h"
#include "ui/aura/window.h"
@@ -335,7 +336,7 @@ TEST_F(DesktopNativeWidgetAuraTest, ReorderDoesntRecomputeOcclusion) {
// Reorder child views. Expect occlusion to only be recomputed once.
aura::test::WindowOcclusionTrackerTestApi window_occlusion_tracker_test_api(
- parent_window->env());
+ parent_window->env()->GetWindowOcclusionTracker());
const int num_times_occlusion_recomputed =
window_occlusion_tracker_test_api.GetNumTimesOcclusionRecomputed();
contents_view->ReorderChildView(host_view3, 0);
@@ -725,8 +726,7 @@ TEST_F(WidgetTest, WindowMouseModalityTest) {
#if defined(OS_WIN)
// Tests whether we can activate the top level widget when a modal dialog is
// active.
-// Flaky: crbug.com/613428
-TEST_F(WidgetTest, DISABLED_WindowModalityActivationTest) {
+TEST_F(WidgetTest, WindowModalityActivationTest) {
TestDesktopWidgetDelegate widget_delegate;
widget_delegate.InitWidget(CreateParams(Widget::InitParams::TYPE_WINDOW));
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 0951d2fb5b9..ae784d5ab75 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -6,7 +6,6 @@
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/memory/protected_memory_cfi.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
@@ -14,17 +13,17 @@
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/layout.h"
+#include "ui/base/x/x11_display_util.h"
+#include "ui/base/x/x11_util.h"
#include "ui/display/display.h"
#include "ui/display/display_finder.h"
#include "ui/display/screen.h"
#include "ui/display/util/display_util.h"
-#include "ui/display/util/x11/edid_parser_x11.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/icc_profile.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/switches.h"
#include "ui/gfx/x/x11.h"
@@ -35,42 +34,11 @@
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
-#include <dlfcn.h>
-
namespace {
-// static
-gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
- gfx::ICCProfile icc_profile;
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
- return icc_profile;
- std::string atom_name;
- if (monitor == 0) {
- atom_name = "_ICC_PROFILE";
- } else {
- atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor);
- }
- Atom property = gfx::GetAtom(atom_name.c_str());
- if (property != x11::None) {
- Atom prop_type = x11::None;
- int prop_format = 0;
- unsigned long nitems = 0;
- unsigned long nbytes = 0;
- char* property_data = NULL;
- if (XGetWindowProperty(
- gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()), property,
- 0, 0x1FFFFFFF /* MAXINT32 / 4 */, x11::False, AnyPropertyType,
- &prop_type, &prop_format, &nitems, &nbytes,
- reinterpret_cast<unsigned char**>(&property_data)) ==
- x11::Success) {
- icc_profile = gfx::ICCProfile::FromData(property_data, nitems);
- XFree(property_data);
- }
- }
- return icc_profile;
-}
+constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3.
-double GetDeviceScaleFactor() {
+float GetDeviceScaleFactor() {
float device_scale_factor = 1.0f;
if (views::LinuxUI::instance()) {
device_scale_factor =
@@ -89,25 +57,6 @@ gfx::Point DIPToPixelPoint(const gfx::Point& dip_point) {
return gfx::ScaleToFlooredPoint(dip_point, GetDeviceScaleFactor());
}
-std::vector<display::Display> GetFallbackDisplayList() {
- ::XDisplay* display = gfx::GetXDisplay();
- ::Screen* screen = DefaultScreenOfDisplay(display);
- int width = WidthOfScreen(screen);
- int height = HeightOfScreen(screen);
- gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
-
- gfx::Rect bounds_in_pixels(0, 0, width, height);
- display::Display gfx_display(0, bounds_in_pixels);
- if (!display::Display::HasForceDeviceScaleFactor() &&
- !display::IsDisplaySizeBlackListed(physical_size)) {
- const float device_scale_factor = GetDeviceScaleFactor();
- DCHECK_LE(1.0f, device_scale_factor);
- gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels);
- }
-
- return std::vector<display::Display>(1, gfx_display);
-}
-
} // namespace
namespace views {
@@ -118,21 +67,13 @@ namespace views {
DesktopScreenX11::DesktopScreenX11()
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
- xrandr_version_(0),
- xrandr_event_base_(0),
- primary_display_index_(0),
+ xrandr_version_(ui::GetXrandrVersion(xdisplay_)),
weak_factory_(this) {
if (views::LinuxUI::instance())
views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
- // We only support 1.3+. There were library changes before this and we should
- // use the new interface instead of the 1.2 one.
- int randr_version_major = 0;
- int randr_version_minor = 0;
- if (XRRQueryVersion(xdisplay_, &randr_version_major, &randr_version_minor)) {
- xrandr_version_ = randr_version_major * 100 + randr_version_minor;
- }
+ float scale = GetDeviceScaleFactor();
// Need at least xrandr version 1.3.
- if (xrandr_version_ >= 103) {
+ if (xrandr_version_ >= kMinVersionXrandr) {
int error_base_ignored = 0;
XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
@@ -144,16 +85,18 @@ DesktopScreenX11::DesktopScreenX11()
RROutputChangeNotifyMask |
RRCrtcChangeNotifyMask);
- SetDisplaysInternal(BuildDisplaysFromXRandRInfo());
+ SetDisplaysInternal(ui::BuildDisplaysFromXRandRInfo(
+ xrandr_version_, scale, &primary_display_index_));
} else {
- SetDisplaysInternal(GetFallbackDisplayList());
+ SetDisplaysInternal(ui::GetFallbackDisplayList(scale));
}
}
DesktopScreenX11::~DesktopScreenX11() {
if (views::LinuxUI::instance())
views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
- if (xrandr_version_ >= 103 && ui::PlatformEventSource::GetInstance())
+ if (xrandr_version_ >= kMinVersionXrandr &&
+ ui::PlatformEventSource::GetInstance())
ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
}
@@ -309,168 +252,13 @@ DesktopScreenX11::DesktopScreenX11(
const std::vector<display::Display>& test_displays)
: xdisplay_(gfx::GetXDisplay()),
x_root_window_(DefaultRootWindow(xdisplay_)),
- xrandr_version_(0),
- xrandr_event_base_(0),
+ xrandr_version_(ui::GetXrandrVersion(xdisplay_)),
displays_(test_displays),
- primary_display_index_(0),
weak_factory_(this) {
if (views::LinuxUI::instance())
views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
}
-typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*);
-typedef void (*XRRFreeMonitors)(XRRMonitorInfo*);
-
-PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRGetMonitors>
- g_XRRGetMonitors_ptr;
-PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRFreeMonitors>
- g_XRRFreeMonitors_ptr;
-
-std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
- DCHECK(xrandr_version_ >= 103);
- std::vector<display::Display> displays;
- gfx::XScopedPtr<
- XRRScreenResources,
- gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
- resources(XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_));
- if (!resources) {
- LOG(ERROR) << "XRandR returned no displays. Falling back to Root Window.";
- return GetFallbackDisplayList();
- }
-
- std::map<RROutput, int> output_to_monitor;
- if (xrandr_version_ >= 105) {
- void* xrandr_lib = dlopen(NULL, RTLD_NOW);
- if (xrandr_lib) {
- static base::ProtectedMemory<XRRGetMonitors>::Initializer get_init(
- &g_XRRGetMonitors_ptr, reinterpret_cast<XRRGetMonitors>(
- dlsym(xrandr_lib, "XRRGetMonitors")));
- static base::ProtectedMemory<XRRFreeMonitors>::Initializer free_init(
- &g_XRRFreeMonitors_ptr, reinterpret_cast<XRRFreeMonitors>(
- dlsym(xrandr_lib, "XRRFreeMonitors")));
- if (*g_XRRGetMonitors_ptr && *g_XRRFreeMonitors_ptr) {
- int nmonitors = 0;
- XRRMonitorInfo* monitors = base::UnsanitizedCfiCall(
- g_XRRGetMonitors_ptr)(xdisplay_, x_root_window_, false, &nmonitors);
- for (int monitor = 0; monitor < nmonitors; monitor++) {
- for (int j = 0; j < monitors[monitor].noutput; j++) {
- output_to_monitor[monitors[monitor].outputs[j]] = monitor;
- }
- }
- base::UnsanitizedCfiCall(g_XRRFreeMonitors_ptr)(monitors);
- }
- }
- }
-
- primary_display_index_ = 0;
- RROutput primary_display_id = XRRGetOutputPrimary(xdisplay_, x_root_window_);
-
- int explicit_primary_display_index = -1;
- int monitor_order_primary_display_index = -1;
-
- bool has_work_area = false;
- gfx::Rect work_area_in_pixels;
- std::vector<int> value;
- if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
- value.size() >= 4) {
- work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
- has_work_area = true;
- }
-
- // As per-display scale factor is not supported right now,
- // the X11 root window's scale factor is always used.
- const float device_scale_factor = GetDeviceScaleFactor();
- for (int i = 0; i < resources->noutput; ++i) {
- RROutput output_id = resources->outputs[i];
- gfx::XScopedPtr<XRROutputInfo,
- gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
- output_info(XRRGetOutputInfo(xdisplay_, resources.get(), output_id));
-
- bool is_connected = (output_info->connection == RR_Connected);
- if (!is_connected)
- continue;
-
- bool is_primary_display = output_id == primary_display_id;
-
- if (output_info->crtc) {
- gfx::XScopedPtr<XRRCrtcInfo,
- gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
- crtc(XRRGetCrtcInfo(xdisplay_, resources.get(), output_info->crtc));
-
- int64_t display_id = -1;
- if (!display::EDIDParserX11(output_id).GetDisplayId(
- static_cast<uint8_t>(i), &display_id)) {
- // It isn't ideal, but if we can't parse the EDID data, fallback on the
- // display number.
- display_id = i;
- }
-
- gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
- display::Display display(display_id, crtc_bounds);
-
- if (!display::Display::HasForceDeviceScaleFactor()) {
- display.SetScaleAndBounds(device_scale_factor, crtc_bounds);
- }
-
- if (has_work_area) {
- gfx::Rect intersection_in_pixels = crtc_bounds;
- if (is_primary_display) {
- intersection_in_pixels.Intersect(work_area_in_pixels);
- }
- // SetScaleAndBounds() above does the conversion from pixels to DIP for
- // us, but set_work_area does not, so we need to do it here.
- display.set_work_area(gfx::Rect(
- gfx::ScaleToFlooredPoint(intersection_in_pixels.origin(),
- 1.0f / display.device_scale_factor()),
- gfx::ScaleToFlooredSize(intersection_in_pixels.size(),
- 1.0f / display.device_scale_factor())));
- }
-
- switch (crtc->rotation) {
- case RR_Rotate_0:
- display.set_rotation(display::Display::ROTATE_0);
- break;
- case RR_Rotate_90:
- display.set_rotation(display::Display::ROTATE_90);
- break;
- case RR_Rotate_180:
- display.set_rotation(display::Display::ROTATE_180);
- break;
- case RR_Rotate_270:
- display.set_rotation(display::Display::ROTATE_270);
- break;
- }
-
- if (is_primary_display)
- explicit_primary_display_index = displays.size();
-
- auto monitor_iter = output_to_monitor.find(output_id);
- if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
- monitor_order_primary_display_index = displays.size();
-
- if (!display::Display::HasForceDisplayColorProfile()) {
- gfx::ICCProfile icc_profile = GetICCProfileForMonitor(
- monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
- icc_profile.HistogramDisplay(display.id());
- display.set_color_space(icc_profile.GetColorSpace());
- }
-
- displays.push_back(display);
- }
- }
-
- if (explicit_primary_display_index != -1) {
- primary_display_index_ = explicit_primary_display_index;
- } else if (monitor_order_primary_display_index != -1) {
- primary_display_index_ = monitor_order_primary_display_index;
- }
-
- if (displays.empty())
- return GetFallbackDisplayList();
-
- return displays;
-}
-
void DesktopScreenX11::RestartDelayedConfigurationTask() {
delayed_configuration_task_.Reset(base::Bind(
&DesktopScreenX11::UpdateDisplays, weak_factory_.GetWeakPtr()));
@@ -480,10 +268,13 @@ void DesktopScreenX11::RestartDelayedConfigurationTask() {
void DesktopScreenX11::UpdateDisplays() {
std::vector<display::Display> old_displays = displays_;
- if (xrandr_version_ > 103)
- SetDisplaysInternal(BuildDisplaysFromXRandRInfo());
- else
- SetDisplaysInternal(GetFallbackDisplayList());
+ float scale = GetDeviceScaleFactor();
+ if (xrandr_version_ > kMinVersionXrandr) {
+ SetDisplaysInternal(ui::BuildDisplaysFromXRandRInfo(
+ xrandr_version_, scale, &primary_display_index_));
+ } else {
+ SetDisplaysInternal(ui::GetFallbackDisplayList(scale));
+ }
change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
index 6b7cb73d7f6..164ad577b41 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -69,10 +69,6 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
// Constructor used in tests.
DesktopScreenX11(const std::vector<display::Display>& test_displays);
- // Builds a list of displays from the current screen information offered by
- // the X server.
- std::vector<display::Display> BuildDisplaysFromXRandRInfo();
-
// Removes |delayed_configuration_task_| from the task queue (if
// it's in the queue) and adds it back at the end of the queue.
void RestartDelayedConfigurationTask();
@@ -88,17 +84,17 @@ class VIEWS_EXPORT DesktopScreenX11 : public display::Screen,
::Window x_root_window_;
// XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present.
- int xrandr_version_;
+ const int xrandr_version_;
// The base of the event numbers used to represent XRandr events used in
// decoding events regarding output add/remove.
- int xrandr_event_base_;
+ int xrandr_event_base_ = 0;
// The display objects we present to chrome.
std::vector<display::Display> displays_;
// The index into displays_ that represents the primary display.
- size_t primary_display_index_;
+ int64_t primary_display_index_ = 0;
// The task to delay configuring outputs. We delay updating the
// display so we can coalesce events.
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
index 08eadbeedc7..86834c46d1b 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_screen_x11_unittest.cc
@@ -322,7 +322,7 @@ TEST_F(DesktopScreenX11Test, DoubleClickHeaderMaximizes) {
DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
GetAcceleratedWidget());
- ui::test::EventGenerator generator(window);
+ ui::test::EventGenerator generator(window->GetRootWindow());
generator.DoubleClickLeftButton();
RunPendingMessages();
EXPECT_TRUE(rwh->IsMaximized());
@@ -348,7 +348,7 @@ TEST_F(DesktopScreenX11Test, DoubleClickTwoDifferentTargetsDoesntMaximizes) {
DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
GetAcceleratedWidget());
- ui::test::EventGenerator generator(window);
+ ui::test::EventGenerator generator(window->GetRootWindow());
native_widget->set_window_component(HTCLIENT);
generator.ClickLeftButton();
native_widget->set_window_component(HTCAPTION);
@@ -378,7 +378,7 @@ TEST_F(DesktopScreenX11Test, RightClickDuringDoubleClickDoesntMaximize) {
DesktopWindowTreeHostX11::GetHostForXID(window->GetHost()->
GetAcceleratedWidget()));
- ui::test::EventGenerator generator(window);
+ ui::test::EventGenerator generator(window->GetRootWindow());
native_widget->set_window_component(HTCLIENT);
generator.ClickLeftButton();
native_widget->set_window_component(HTCAPTION);
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 fbfa8df1f7d..72d04d0595b 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
@@ -4,6 +4,7 @@
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
+#include "base/time/time.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/transient_window_client.h"
#include "ui/base/hit_test.h"
@@ -14,6 +15,7 @@
#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_drag_drop_client_ozone.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"
@@ -75,7 +77,7 @@ void DesktopWindowTreeHostPlatform::SetBoundsInDIP(
DCHECK_NE(0, device_scale_factor());
SetBoundsInPixels(
gfx::ConvertRectToPixel(device_scale_factor(), bounds_in_dip),
- viz::LocalSurfaceId());
+ viz::LocalSurfaceIdAllocation());
}
void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
@@ -95,6 +97,7 @@ void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
const Widget::InitParams& params) {
native_widget_delegate_->OnNativeWidgetCreated(true);
+#if defined(OS_LINUX)
// Setup a non_client_window_event_filter, which handles resize/move, double
// click and other events.
DCHECK(!non_client_window_event_filter_);
@@ -107,6 +110,7 @@ void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
non_client_window_event_filter_ = std::move(window_event_filter);
window()->AddPreTargetHandler(non_client_window_event_filter_.get());
+#endif
}
void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {}
@@ -121,9 +125,9 @@ DesktopWindowTreeHostPlatform::CreateTooltip() {
std::unique_ptr<aura::client::DragDropClient>
DesktopWindowTreeHostPlatform::CreateDragDropClient(
DesktopNativeCursorManager* cursor_manager) {
- // TODO: needs PlatformWindow support.
- NOTIMPLEMENTED_LOG_ONCE();
- return nullptr;
+ ui::WmDragHandler* drag_handler = ui::GetWmDragHandler(*(platform_window()));
+ return std::make_unique<DesktopDragDropClientOzone>(window(), cursor_manager,
+ drag_handler);
}
void DesktopWindowTreeHostPlatform::Close() {
@@ -538,11 +542,13 @@ void DesktopWindowTreeHostPlatform::Relayout() {
}
void DesktopWindowTreeHostPlatform::RemoveNonClientEventFilter() {
+#if defined(OS_LINUX)
if (!non_client_window_event_filter_)
return;
window()->RemovePreTargetHandler(non_client_window_event_filter_.get());
non_client_window_event_filter_.reset();
+#endif
}
Widget* DesktopWindowTreeHostPlatform::GetWidget() {
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 e0b98abdaf0..fa106717dc2 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
@@ -6,6 +6,7 @@
#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_WINDOW_TREE_HOST_PLATFORM_H_
#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
#include "ui/aura/window_tree_host_platform.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
@@ -120,8 +121,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
bool is_active_ = false;
+#if defined(OS_LINUX)
// A handler for events intended for non client area.
std::unique_ptr<WindowEventFilter> non_client_window_event_filter_;
+#endif
base::WeakPtrFactory<DesktopWindowTreeHostPlatform> weak_factory_{this};
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 9ab47c86390..c16d7368315 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -15,6 +15,7 @@
#include "ui/base/class_property.h"
#include "ui/base/cursor/cursor_loader_win.h"
#include "ui/base/ime/input_method.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/win/shell.h"
#include "ui/compositor/paint_context.h"
#include "ui/display/win/dpi.h"
@@ -28,6 +29,7 @@
#include "ui/gfx/path.h"
#include "ui/gfx/path_win.h"
#include "ui/views/corewm/tooltip_win.h"
+#include "ui/views/views_switches.h"
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -175,7 +177,6 @@ DesktopWindowTreeHostWin::CreateDragDropClient(
void DesktopWindowTreeHostWin::Close() {
content_window()->Hide();
-
// TODO(beng): Move this entire branch to DNWA so it can be shared with X11.
if (should_animate_window_close_) {
pending_close_ = true;
@@ -532,11 +533,11 @@ gfx::Rect DesktopWindowTreeHostWin::GetBoundsInPixels() const {
void DesktopWindowTreeHostWin::SetBoundsInPixels(
const gfx::Rect& bounds,
- const viz::LocalSurfaceId& local_surface_id) {
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
// On Windows, the callers of SetBoundsInPixels() shouldn't need to (or be
// able to) allocate LocalSurfaceId for the compositor. Aura itself should
// allocate the new ids as needed, instead.
- DCHECK(!local_surface_id.is_valid());
+ DCHECK(!local_surface_id_allocation.IsValid());
// If the window bounds have to be expanded we need to subtract the
// window_expansion_top_left_delta_ from the origin and add the
@@ -577,7 +578,7 @@ bool DesktopWindowTreeHostWin::CaptureSystemKeyEventsImpl(
// problems with event routing (i.e. which Hook takes precedence) and
// destruction ordering.
DCHECK(!keyboard_hook_);
- keyboard_hook_ = ui::KeyboardHook::Create(
+ keyboard_hook_ = ui::KeyboardHook::CreateModifierKeyboardHook(
std::move(dom_codes), GetAcceleratedWidget(),
base::BindRepeating(&DesktopWindowTreeHostWin::HandleKeyEvent,
base::Unretained(this)));
@@ -733,6 +734,11 @@ bool DesktopWindowTreeHostWin::GetClientAreaInsets(gfx::Insets* insets,
return false;
}
+bool DesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels(
+ gfx::Insets* insets) const {
+ return false;
+}
+
void DesktopWindowTreeHostWin::GetMinMaxSize(gfx::Size* min_size,
gfx::Size* max_size) const {
*min_size = native_widget_delegate_->GetMinimumSize();
@@ -771,8 +777,6 @@ void DesktopWindowTreeHostWin::HandleActivationChanged(bool active) {
if (!dispatcher())
return;
- if (active)
- OnHostActivated();
desktop_native_widget_aura_->HandleActivationChanged(active);
}
@@ -881,11 +885,9 @@ void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
}
bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
- SendEventToSink(event);
- return event->handled();
-}
-
-bool DesktopWindowTreeHostWin::HandlePointerEvent(ui::PointerEvent* event) {
+ // TODO(davidbienvenu): Check for getting mouse events for an occluded window
+ // with either a DCHECK or a stat. Event can cause this object to be deleted
+ // so look at occlusion state before we do anything with the event.
SendEventToSink(event);
return event->handled();
}
@@ -1007,7 +1009,7 @@ void DesktopWindowTreeHostWin::HandleWindowScaleFactorChanged(
if (compositor()) {
compositor()->SetScaleAndSize(
window_scale_factor, message_handler_->GetClientAreaBounds().size(),
- window()->GetLocalSurfaceId());
+ window()->GetLocalSurfaceIdAllocation());
}
}
diff --git a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index 364d6df184c..ecb84e76ae2 100644
--- a/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/chromium/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -128,9 +128,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void ShowImpl() override;
void HideImpl() override;
gfx::Rect GetBoundsInPixels() const override;
- void SetBoundsInPixels(const gfx::Rect& bounds,
- const viz::LocalSurfaceId& local_surface_id =
- viz::LocalSurfaceId()) override;
+ void SetBoundsInPixels(
+ const gfx::Rect& bounds,
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation =
+ viz::LocalSurfaceIdAllocation()) override;
gfx::Point GetLocationOnScreenInPixels() const override;
void SetCapture() override;
void ReleaseCapture() override;
@@ -171,6 +172,7 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void GetWindowMask(const gfx::Size& size, gfx::Path* path) override;
bool GetClientAreaInsets(gfx::Insets* insets,
HMONITOR monitor) const override;
+ bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override;
void GetMinMaxSize(gfx::Size* min_size, gfx::Size* max_size) const override;
gfx::Size GetRootViewSize() const override;
gfx::Size DIPToScreenSize(const gfx::Size& dip_size) const override;
@@ -200,7 +202,6 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
void HandleNativeFocus(HWND last_focused_window) override;
void HandleNativeBlur(HWND focused_window) override;
bool HandleMouseEvent(ui::MouseEvent* event) override;
- bool HandlePointerEvent(ui::PointerEvent* event) override;
void HandleKeyEvent(ui::KeyEvent* event) override;
void HandleTouchEvent(ui::TouchEvent* event) override;
bool HandleIMEMessage(UINT message,
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 0ab1728d69b..5e46a4f6908 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
@@ -17,6 +17,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkPath.h"
+#include "ui/accessibility/platform/atk_util_auralinux.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
@@ -223,7 +224,6 @@ void DesktopWindowTreeHostX11::AfterActivationStateChanged() {
if (!was_active_ && IsActive()) {
FlashFrame(false);
- OnHostActivated();
// TODO(thomasanderson): Remove this window shuffling and use XWindowCache
// instead.
open_windows().remove(xwindow_);
@@ -1209,11 +1209,11 @@ gfx::Rect DesktopWindowTreeHostX11::GetBoundsInPixels() const {
void DesktopWindowTreeHostX11::SetBoundsInPixels(
const gfx::Rect& requested_bounds_in_pixel,
- const viz::LocalSurfaceId& local_surface_id) {
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation) {
// On desktop-x11, the callers of SetBoundsInPixels() shouldn't need to (or be
// able to) allocate LocalSurfaceId for the compositor. Aura itself should
// allocate the new ids as needed, instead.
- DCHECK(!local_surface_id.is_valid());
+ DCHECK(!local_surface_id_allocation.IsValid());
gfx::Rect bounds_in_pixels(requested_bounds_in_pixel.origin(),
AdjustSize(requested_bounds_in_pixel.size()));
@@ -1266,7 +1266,7 @@ void DesktopWindowTreeHostX11::SetBoundsInPixels(
if (origin_changed)
native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
if (size_changed) {
- OnHostResizedInPixels(bounds_in_pixels.size(), local_surface_id);
+ OnHostResizedInPixels(bounds_in_pixels.size(), local_surface_id_allocation);
ResetWindowRegion();
}
}
@@ -1318,7 +1318,7 @@ bool DesktopWindowTreeHostX11::CaptureSystemKeyEventsImpl(
// problems with event routing (i.e. which Hook takes precedence) and
// destruction ordering.
DCHECK(!keyboard_hook_);
- keyboard_hook_ = ui::KeyboardHook::Create(
+ keyboard_hook_ = ui::KeyboardHook::CreateModifierKeyboardHook(
std::move(dom_codes), GetAcceleratedWidget(),
base::BindRepeating(&DesktopWindowTreeHostX11::DispatchKeyEvent,
base::Unretained(this)));
@@ -1819,8 +1819,10 @@ void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
// WindowTreeHost that hosts ash.
if (content_window() && content_window()->delegate()) {
int flags = event->flags();
+ gfx::Point location_in_dip = event->location();
+ GetRootTransform().TransformPointReverse(&location_in_dip);
int hit_test_code =
- content_window()->delegate()->GetNonClientComponent(event->location());
+ content_window()->delegate()->GetNonClientComponent(location_in_dip);
if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
flags |= ui::EF_IS_NON_CLIENT;
event->set_flags(flags);
@@ -2046,8 +2048,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
break;
}
case KeyPress: {
- ui::KeyEvent keydown_event(xev);
- DispatchKeyEvent(&keydown_event);
+ if (ui::AtkUtilAuraLinux::HandleKeyEvent(xev) !=
+ ui::DiscardAtkKeyEvent::Discard) {
+ ui::KeyEvent keydown_event(xev);
+ DispatchKeyEvent(&keydown_event);
+ }
break;
}
case KeyRelease: {
@@ -2056,8 +2061,11 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent(
if (!IsActive() && !HasCapture())
break;
- ui::KeyEvent key_event(xev);
- DispatchKeyEvent(&key_event);
+ if (ui::AtkUtilAuraLinux::HandleKeyEvent(xev) !=
+ ui::DiscardAtkKeyEvent::Discard) {
+ ui::KeyEvent key_event(xev);
+ DispatchKeyEvent(&key_event);
+ }
break;
}
case ButtonPress:
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 2600a0621f3..c547609abf0 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
@@ -165,9 +165,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostX11
void ShowImpl() override;
void HideImpl() override;
gfx::Rect GetBoundsInPixels() const override;
- void SetBoundsInPixels(const gfx::Rect& requested_bounds_in_pixels,
- const viz::LocalSurfaceId& local_surface_id =
- viz::LocalSurfaceId()) override;
+ void SetBoundsInPixels(
+ const gfx::Rect& requested_bounds_in_pixels,
+ const viz::LocalSurfaceIdAllocation& local_surface_id_allocation =
+ viz::LocalSurfaceIdAllocation()) override;
gfx::Point GetLocationOnScreenInPixels() const override;
void SetCapture() override;
void ReleaseCapture() override;
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 2f3f85b16b1..e25fab221ed 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
@@ -79,7 +79,12 @@ class ShapedNonClientFrameView : public NonClientFrameView {
const gfx::Rect& client_bounds) const override {
return client_bounds;
}
- int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
+ int NonClientHitTest(const gfx::Point& point) override {
+ // Fake bottom for non client event test.
+ if (point == gfx::Point(500, 500))
+ return HTBOTTOM;
+ return HTNOWHERE;
+ }
void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {
int right = size.width();
int bottom = size.height();
@@ -168,11 +173,15 @@ void RunAllPendingInMessageLoop() {
class DesktopWindowTreeHostX11Test : public ViewsTestBase {
public:
- DesktopWindowTreeHostX11Test() {
- }
+ DesktopWindowTreeHostX11Test()
+ : event_source_(ui::PlatformEventSource::GetInstance()) {}
~DesktopWindowTreeHostX11Test() override {}
void SetUp() override {
+ std::vector<int> pointer_devices;
+ pointer_devices.push_back(kPointerDeviceId);
+ ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(pointer_devices);
+
ViewsTestBase::SetUp();
// Make X11 synchronous for our display connection. This does not force the
@@ -185,12 +194,23 @@ class DesktopWindowTreeHostX11Test : public ViewsTestBase {
ViewsTestBase::TearDown();
}
+ void DispatchSingleEventToWidget(XEvent* event, Widget* widget) {
+ DCHECK_EQ(GenericEvent, event->type);
+ XIDeviceEvent* device_event =
+ static_cast<XIDeviceEvent*>(event->xcookie.data);
+ device_event->event =
+ widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
+ event_source_.Dispatch(event);
+ }
+
private:
+ ui::test::PlatformEventSourceTestAPI event_source_;
DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11Test);
};
+// https://crbug.com/898742: Test is flaky.
// Tests that the shape is properly set on the x window.
-TEST_F(DesktopWindowTreeHostX11Test, Shape) {
+TEST_F(DesktopWindowTreeHostX11Test, DISABLED_Shape) {
if (!ui::IsShapeExtensionAvailable())
return;
@@ -500,19 +520,9 @@ class MouseEventRecorder : public ui::EventHandler {
class DesktopWindowTreeHostX11HighDPITest
: public DesktopWindowTreeHostX11Test {
public:
- DesktopWindowTreeHostX11HighDPITest()
- : event_source_(ui::PlatformEventSource::GetInstance()) {}
+ DesktopWindowTreeHostX11HighDPITest() {}
~DesktopWindowTreeHostX11HighDPITest() override {}
- void DispatchSingleEventToWidget(XEvent* event, Widget* widget) {
- DCHECK_EQ(GenericEvent, event->type);
- XIDeviceEvent* device_event =
- static_cast<XIDeviceEvent*>(event->xcookie.data);
- device_event->event =
- widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
- event_source_.Dispatch(event);
- }
-
void PretendCapture(views::Widget* capture_widget) {
DesktopWindowTreeHostX11* capture_host = nullptr;
if (capture_widget) {
@@ -528,14 +538,10 @@ class DesktopWindowTreeHostX11HighDPITest
void SetUp() override {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
- std::vector<int> pointer_devices;
- pointer_devices.push_back(kPointerDeviceId);
- ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(pointer_devices);
DesktopWindowTreeHostX11Test::SetUp();
}
- ui::test::PlatformEventSourceTestAPI event_source_;
DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostX11HighDPITest);
};
@@ -596,4 +602,52 @@ TEST_F(DesktopWindowTreeHostX11HighDPITest,
second.GetNativeWindow()->RemovePreTargetHandler(&second_recorder);
}
+TEST_F(DesktopWindowTreeHostX11Test, MouseNCEvents) {
+ std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
+ widget->Show();
+
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ widget->SetBounds(gfx::Rect(100, 100, 501, 501));
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ MouseEventRecorder recorder;
+ widget->GetNativeWindow()->AddPreTargetHandler(&recorder);
+
+ ui::ScopedXI2Event event;
+ event.InitGenericButtonEvent(kPointerDeviceId, ui::ET_MOUSE_PRESSED,
+ gfx::Point(500, 500), ui::EF_LEFT_MOUSE_BUTTON);
+
+ DispatchSingleEventToWidget(event, widget.get());
+ ASSERT_EQ(1u, recorder.mouse_events().size());
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.mouse_events()[0].type());
+ EXPECT_TRUE(recorder.mouse_events()[0].flags() & ui::EF_IS_NON_CLIENT);
+
+ widget->GetNativeWindow()->RemovePreTargetHandler(&recorder);
+}
+
+TEST_F(DesktopWindowTreeHostX11HighDPITest, MouseNCEvents) {
+ std::unique_ptr<Widget> widget = CreateWidget(new ShapedWidgetDelegate());
+ widget->Show();
+
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ widget->SetBounds(gfx::Rect(100, 100, 1000, 1000));
+ ui::X11EventSource::GetInstance()->DispatchXEvents();
+
+ MouseEventRecorder recorder;
+ widget->GetNativeWindow()->AddPreTargetHandler(&recorder);
+
+ ui::ScopedXI2Event event;
+ event.InitGenericButtonEvent(kPointerDeviceId, ui::ET_MOUSE_PRESSED,
+ gfx::Point(1001, 1001),
+ ui::EF_LEFT_MOUSE_BUTTON);
+ DispatchSingleEventToWidget(event, widget.get());
+ ASSERT_EQ(1u, recorder.mouse_events().size());
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, recorder.mouse_events()[0].type());
+ EXPECT_TRUE(recorder.mouse_events()[0].flags() & ui::EF_IS_NON_CLIENT);
+
+ widget->GetNativeWindow()->RemovePreTargetHandler(&recorder);
+}
+
} // namespace views
diff --git a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index d6b086c11f8..e65fba7f97f 100644
--- a/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/chromium/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -73,7 +73,7 @@ bool X11WholeScreenMoveLoop::CanDispatchEvent(const ui::PlatformEvent& event) {
}
uint32_t X11WholeScreenMoveLoop::DispatchEvent(const ui::PlatformEvent& event) {
- DCHECK(base::MessageLoopForUI::IsCurrent());
+ DCHECK(base::MessageLoopCurrentForUI::IsSet());
// This method processes all events while the move loop is active.
if (!in_move_loop_)
diff --git a/chromium/ui/views/widget/native_widget_aura.cc b/chromium/ui/views/widget/native_widget_aura.cc
index 28c63b02b81..63ef7767c60 100644
--- a/chromium/ui/views/widget/native_widget_aura.cc
+++ b/chromium/ui/views/widget/native_widget_aura.cc
@@ -175,7 +175,7 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
window_->Init(params.layer_type);
// Set name after layer init so it propagates to layer.
- window_->SetName(params.name);
+ window_->SetName(params.name.empty() ? "NativeWidgetAura" : params.name);
if (params.type == Widget::InitParams::TYPE_CONTROL)
window_->Show();
@@ -594,9 +594,8 @@ void NativeWidgetAura::Activate() {
// We don't necessarily have a root window yet. This can happen with
// constrained windows.
- if (window_->GetRootWindow()) {
+ if (window_->GetRootWindow())
wm::GetActivationClient(window_->GetRootWindow())->ActivateWindow(window_);
- }
if (window_->GetProperty(aura::client::kDrawAttentionKey))
window_->SetProperty(aura::client::kDrawAttentionKey, false);
}
diff --git a/chromium/ui/views/widget/native_widget_mac.h b/chromium/ui/views/widget/native_widget_mac.h
index e8e387ccd3c..3ba1733df6f 100644
--- a/chromium/ui/views/widget/native_widget_mac.h
+++ b/chromium/ui/views/widget/native_widget_mac.h
@@ -18,6 +18,7 @@ class NativeWidgetMacNSWindow;
namespace views_bridge_mac {
namespace mojom {
class BridgedNativeWidget;
+class CreateWindowParams;
} // namespace mojom
} // namespace views_bridge_mac
@@ -51,9 +52,17 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// from the bottom of the window.
virtual int SheetPositionY();
+ // Returns in |override_titlebar_height| whether or not to override the
+ // titlebar height and in |titlebar_height| the height of the titlebar.
+ virtual void GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
+ float* titlebar_height);
+
// Notifies that the widget starts to enter or exit fullscreen mode.
virtual void OnWindowFullscreenStateChange() {}
+ // Handle "Move focus to the window toolbar" shortcut.
+ virtual void OnFocusWindowToolbar() {}
+
// internal::NativeWidgetPrivate:
void InitNativeWidget(const Widget::InitParams& params) override;
void OnWidgetInitDone() override;
@@ -144,6 +153,10 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
std::string GetName() const override;
protected:
+ virtual void PopulateCreateWindowParams(
+ const Widget::InitParams& widget_params,
+ views_bridge_mac::mojom::CreateWindowParams* params) {}
+
// 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
@@ -151,7 +164,7 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
// are autoreleased, and will crash if the window has a more precise
// lifetime.
virtual NativeWidgetMacNSWindow* CreateNSWindow(
- const Widget::InitParams& params);
+ const views_bridge_mac::mojom::CreateWindowParams* 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
@@ -159,7 +172,11 @@ class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate {
virtual BridgeFactoryHost* GetBridgeFactoryHost();
// Optional hook for subclasses invoked by WindowDestroying().
- virtual void OnWindowDestroying(NSWindow* window) {}
+ virtual void OnWindowDestroying(gfx::NativeWindow window) {}
+
+ // Redispatch a keyboard event using the widget's window's CommandDispatcher.
+ // Return true if the event is handled.
+ bool RedispatchKeyEvent(NSEvent* event);
internal::NativeWidgetDelegate* delegate() { return delegate_; }
views_bridge_mac::mojom::BridgedNativeWidget* bridge() const;
diff --git a/chromium/ui/views/widget/native_widget_mac.mm b/chromium/ui/views/widget/native_widget_mac.mm
index 4f75293c284..9f76453e071 100644
--- a/chromium/ui/views/widget/native_widget_mac.mm
+++ b/chromium/ui/views/widget/native_widget_mac.mm
@@ -97,11 +97,18 @@ void NativeWidgetMac::WindowDestroyed() {
}
int NativeWidgetMac::SheetPositionY() {
- NSView* view = GetNativeView();
+ NSView* view = GetNativeView().GetNativeNSView();
return
[view convertPoint:NSMakePoint(0, NSHeight([view frame])) toView:nil].y;
}
+void NativeWidgetMac::GetWindowFrameTitlebarHeight(
+ bool* override_titlebar_height,
+ float* titlebar_height) {
+ *override_titlebar_height = false;
+ *titlebar_height = 0;
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetMac, internal::NativeWidgetPrivate implementation:
@@ -109,25 +116,28 @@ void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
ownership_ = params.ownership;
name_ = params.name;
BridgedNativeWidgetHostImpl* parent_host =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow([params.parent window]);
+ BridgedNativeWidgetHostImpl::GetFromNativeView(params.parent);
// 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);
+ // Compute the parameters to describe the NSWindow.
+ auto create_window_params =
+ views_bridge_mac::mojom::CreateWindowParams::New();
+ create_window_params->window_class =
+ views_bridge_mac::mojom::WindowClass::kDefault;
+ create_window_params->style_mask = StyleMaskForParams(params);
+ create_window_params->titlebar_appears_transparent = false;
+ create_window_params->window_title_hidden = false;
+ PopulateCreateWindowParams(params, create_window_params.get());
+
+ if (bridge_factory_host) {
bridge_host_->CreateRemoteBridge(bridge_factory_host,
std::move(create_window_params));
} else {
base::scoped_nsobject<NativeWidgetMacNSWindow> window(
- [CreateNSWindow(params) retain]);
+ [CreateNSWindow(create_window_params.get()) retain]);
bridge_host_->CreateLocalBridge(std::move(window));
}
bridge_host_->SetParent(parent_host);
@@ -188,7 +198,7 @@ const Widget* NativeWidgetMac::GetWidget() const {
gfx::NativeView NativeWidgetMac::GetNativeView() const {
// Returns a BridgedContentView, unless there is no views::RootView set.
- return [GetNativeWindow() contentView];
+ return [GetNativeWindow().GetNativeNSWindow() contentView];
}
gfx::NativeWindow NativeWidgetMac::GetNativeWindow() const {
@@ -344,8 +354,9 @@ void NativeWidgetMac::SetSize(const gfx::Size& size) {
}
void NativeWidgetMac::StackAbove(gfx::NativeView native_view) {
- NSInteger view_parent = native_view.window.windowNumber;
- [GetNativeWindow() orderWindow:NSWindowAbove relativeTo:view_parent];
+ NSInteger view_parent = native_view.GetNativeNSView().window.windowNumber;
+ [GetNativeWindow().GetNativeNSWindow() orderWindow:NSWindowAbove
+ relativeTo:view_parent];
}
void NativeWidgetMac::StackAtTop() {
@@ -424,11 +435,12 @@ bool NativeWidgetMac::IsActive() const {
}
void NativeWidgetMac::SetAlwaysOnTop(bool always_on_top) {
- gfx::SetNSWindowAlwaysOnTop(GetNativeWindow(), always_on_top);
+ gfx::SetNSWindowAlwaysOnTop(GetNativeWindow().GetNativeNSWindow(),
+ always_on_top);
}
bool NativeWidgetMac::IsAlwaysOnTop() const {
- return gfx::IsNSWindowAlwaysOnTop(GetNativeWindow());
+ return gfx::IsNSWindowAlwaysOnTop(GetNativeWindow().GetNativeNSWindow());
}
void NativeWidgetMac::SetVisibleOnAllWorkspaces(bool always_visible) {
@@ -507,14 +519,14 @@ void NativeWidgetMac::RunShellDrag(View* view,
void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
// |rect| is relative to client area of the window.
- NSWindow* window = GetNativeWindow();
+ NSWindow* window = GetNativeWindow().GetNativeNSWindow();
NSRect client_rect = [window contentRectForFrameRect:[window frame]];
NSRect target_rect = rect.ToCGRect();
// Convert to Appkit coordinate system (origin at bottom left).
target_rect.origin.y =
NSHeight(client_rect) - target_rect.origin.y - NSHeight(target_rect);
- [GetNativeView() setNeedsDisplayInRect:target_rect];
+ [GetNativeView().GetNativeNSView() setNeedsDisplayInRect:target_rect];
if (bridge_host_ && bridge_host_->layer())
bridge_host_->layer()->SchedulePaint(rect);
}
@@ -556,6 +568,7 @@ Widget::MoveLoopResult NativeWidgetMac::RunMoveLoop(
if (!bridge_impl())
return Widget::MOVE_LOOP_CANCELED;
+ ReleaseCapture();
return bridge_impl()->RunMoveLoop(drag_offset) ? Widget::MOVE_LOOP_SUCCESSFUL
: Widget::MOVE_LOOP_CANCELED;
}
@@ -566,8 +579,8 @@ void NativeWidgetMac::EndMoveLoop() {
}
void NativeWidgetMac::SetVisibilityChangedAnimationsEnabled(bool value) {
- if (bridge_impl())
- bridge_impl()->SetAnimationEnabled(value);
+ if (bridge())
+ bridge()->SetAnimationEnabled(value);
}
void NativeWidgetMac::SetVisibilityAnimationDuration(
@@ -625,18 +638,30 @@ std::string NativeWidgetMac::GetName() const {
// NativeWidgetMac, protected:
NativeWidgetMacNSWindow* NativeWidgetMac::CreateNSWindow(
- const Widget::InitParams& params) {
- return [[[NativeWidgetMacNSWindow alloc]
- initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:StyleMaskForParams(params)
- backing:NSBackingStoreBuffered
- defer:NO] autorelease];
+ const views_bridge_mac::mojom::CreateWindowParams* params) {
+ return BridgedNativeWidgetImpl::CreateNSWindow(params).autorelease();
}
BridgeFactoryHost* NativeWidgetMac::GetBridgeFactoryHost() {
return nullptr;
}
+bool NativeWidgetMac::RedispatchKeyEvent(NSEvent* event) {
+ // If the target window is in-process, then redispatch the event directly,
+ // and give an accurate return value.
+ if (bridge_impl())
+ return bridge_impl()->RedispatchKeyEvent(event);
+
+ // If the target window is out of process then always report the event as
+ // handled (because it should never be handled in this process).
+ bridge()->RedispatchKeyEvent(
+ [event type], [event modifierFlags], [event timestamp],
+ base::SysNSStringToUTF16([event characters]),
+ base::SysNSStringToUTF16([event charactersIgnoringModifiers]),
+ [event keyCode]);
+ return true;
+}
+
views_bridge_mac::mojom::BridgedNativeWidget* NativeWidgetMac::bridge() const {
return bridge_host_ ? bridge_host_->bridge() : nullptr;
}
@@ -694,7 +719,7 @@ NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
// static
NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
gfx::NativeView native_view) {
- return GetNativeWidgetForNativeWindow([native_view window]);
+ return GetNativeWidgetForNativeWindow([native_view.GetNativeNSView() window]);
}
// static
@@ -711,7 +736,7 @@ NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
gfx::NativeView native_view) {
BridgedNativeWidgetHostImpl* bridge_host =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ BridgedNativeWidgetHostImpl::GetFromNativeView(native_view);
if (!bridge_host)
return nullptr;
while (bridge_host->parent())
@@ -723,22 +748,23 @@ NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
Widget::Widgets* children) {
BridgedNativeWidgetHostImpl* bridge_host =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ BridgedNativeWidgetHostImpl::GetFromNativeView(native_view);
if (!bridge_host) {
+ NSView* ns_view = native_view.GetNativeNSView();
// 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.
// - We do not add a Widget for |native_view| to |children| (there is none).
- if ([[native_view window] contentView] != native_view)
+ if ([[ns_view window] contentView] != ns_view)
return;
// Collect -sheets and -childWindows. A window should never appear in both,
// since that causes AppKit to glitch.
- NSArray* sheet_children = [[native_view window] sheets];
+ NSArray* sheet_children = [[ns_view window] sheets];
for (NSWindow* native_child in sheet_children)
GetAllChildWidgets([native_child contentView], children);
- for (NSWindow* native_child in [[native_view window] childWindows]) {
+ for (NSWindow* native_child in [[ns_view window] childWindows]) {
DCHECK(![sheet_children containsObject:native_child]);
GetAllChildWidgets([native_child contentView], children);
}
@@ -770,7 +796,7 @@ void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
Widget::Widgets* owned) {
BridgedNativeWidgetHostImpl* bridge_host =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ BridgedNativeWidgetHostImpl::GetFromNativeView(native_view);
if (!bridge_host) {
GetAllChildWidgets(native_view, owned);
return;
@@ -785,24 +811,28 @@ void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
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) {
+ DCHECK([new_parent.GetNativeNSView() window]);
+ if (!new_parent || [native_view.GetNativeNSView() superview] ==
+ new_parent.GetNativeNSView()) {
NOTREACHED();
return;
}
BridgedNativeWidgetHostImpl* bridge_host =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow([native_view window]);
+ BridgedNativeWidgetHostImpl::GetFromNativeView(native_view);
DCHECK(bridge_host);
- NSView* bridge_view = bridge_host->native_widget_mac()->GetNativeView();
- NSWindow* bridge_window = bridge_host->native_widget_mac()->GetNativeWindow();
+ gfx::NativeView bridge_view =
+ bridge_host->native_widget_mac()->GetNativeView();
+ gfx::NativeWindow 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]);
+ DCHECK([native_view.GetNativeNSView()
+ isDescendantOf:bridge_view.GetNativeNSView()]);
+ DCHECK(bridge_window && ![bridge_window.GetNativeNSWindow() isSheet]);
BridgedNativeWidgetHostImpl* parent_bridge_host =
- BridgedNativeWidgetHostImpl::GetFromNativeWindow([new_parent window]);
+ BridgedNativeWidgetHostImpl::GetFromNativeView(new_parent);
// Early out for no-op changes.
if (native_view == bridge_view && bridge_is_top_level &&
@@ -831,16 +861,16 @@ void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
// 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];
+ [new_parent.GetNativeNSView() addSubview:native_view.GetNativeNSView()];
+ [bridge_window.GetNativeNSWindow() setAlphaValue:0];
+ [bridge_window.GetNativeNSWindow() 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];
+ [new_parent.GetNativeNSView() addSubview:native_view.GetNativeNSView()];
}
// And now, notify them that they have a brand new parent.
diff --git a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
index bb6fe00eaeb..1bb90b81c39 100644
--- a/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_interactive_uitest.mm
@@ -82,7 +82,7 @@ TEST_P(NativeWidgetMacInteractiveUITest, ShowAttainsKeyStatus) {
wait_for_first_active.Wait();
}
EXPECT_TRUE(widget->IsActive());
- EXPECT_TRUE([widget->GetNativeWindow() isKeyWindow]);
+ EXPECT_TRUE([widget->GetNativeWindow().GetNativeNSWindow() isKeyWindow]);
EXPECT_EQ(1, activation_count_);
EXPECT_EQ(0, deactivation_count_);
@@ -101,7 +101,7 @@ TEST_P(NativeWidgetMacInteractiveUITest, ShowAttainsKeyStatus) {
{
WidgetActivationWaiter wait_for_external_activate(widget, true);
- [widget->GetNativeWindow() makeKeyAndOrderFront:nil];
+ [widget->GetNativeWindow().GetNativeNSWindow() makeKeyAndOrderFront:nil];
wait_for_external_activate.Wait();
}
EXPECT_TRUE(widget->IsActive());
@@ -118,27 +118,28 @@ TEST_P(NativeWidgetMacInteractiveUITest, ShowAttainsKeyStatus) {
// Test that ShowInactive does not take keyWindow status.
TEST_P(NativeWidgetMacInteractiveUITest, ShowInactiveIgnoresKeyStatus) {
Widget* widget = MakeWidget();
+ NSWindow* widget_window = widget->GetNativeWindow().GetNativeNSWindow();
base::scoped_nsobject<WindowedNSNotificationObserver> waiter(
[[WindowedNSNotificationObserver alloc]
initForNotification:NSWindowDidBecomeKeyNotification
- object:widget->GetNativeWindow()]);
+ object:widget_window]);
EXPECT_FALSE(widget->IsVisible());
- EXPECT_FALSE([widget->GetNativeWindow() isVisible]);
+ EXPECT_FALSE([widget_window isVisible]);
EXPECT_FALSE(widget->IsActive());
- EXPECT_FALSE([widget->GetNativeWindow() isKeyWindow]);
+ EXPECT_FALSE([widget_window isKeyWindow]);
widget->ShowInactive();
EXPECT_TRUE(widget->IsVisible());
- EXPECT_TRUE([widget->GetNativeWindow() isVisible]);
+ EXPECT_TRUE([widget_window isVisible]);
EXPECT_FALSE(widget->IsActive());
- EXPECT_FALSE([widget->GetNativeWindow() isKeyWindow]);
+ EXPECT_FALSE([widget_window isKeyWindow]);
// If the window were to become active, this would activate it.
RunPendingMessages();
EXPECT_FALSE(widget->IsActive());
- EXPECT_FALSE([widget->GetNativeWindow() isKeyWindow]);
+ EXPECT_FALSE([widget_window isKeyWindow]);
EXPECT_EQ(0, [waiter notificationCount]);
// Activating the inactive widget should make it key, asynchronously.
@@ -146,7 +147,7 @@ TEST_P(NativeWidgetMacInteractiveUITest, ShowInactiveIgnoresKeyStatus) {
[waiter wait];
EXPECT_EQ(1, [waiter notificationCount]);
EXPECT_TRUE(widget->IsActive());
- EXPECT_TRUE([widget->GetNativeWindow() isKeyWindow]);
+ EXPECT_TRUE([widget_window isKeyWindow]);
widget->CloseNow();
}
@@ -155,13 +156,14 @@ namespace {
// Show |widget| and wait for it to become the key window.
void ShowKeyWindow(Widget* widget) {
+ NSWindow* widget_window = widget->GetNativeWindow().GetNativeNSWindow();
base::scoped_nsobject<WindowedNSNotificationObserver> waiter(
[[WindowedNSNotificationObserver alloc]
initForNotification:NSWindowDidBecomeKeyNotification
- object:widget->GetNativeWindow()]);
+ object:widget_window]);
widget->Show();
EXPECT_TRUE([waiter wait]);
- EXPECT_TRUE([widget->GetNativeWindow() isKeyWindow]);
+ EXPECT_TRUE([widget_window isKeyWindow]);
}
NSData* ViewAsTIFF(NSView* view) {
@@ -190,7 +192,7 @@ TEST_F(NativeWidgetMacInteractiveUITest, ParentWindowTrafficLights) {
parent_widget->SetBounds(gfx::Rect(100, 100, 100, 100));
ShowKeyWindow(parent_widget);
- NSWindow* parent = parent_widget->GetNativeWindow();
+ NSWindow* parent = parent_widget->GetNativeWindow().GetNativeNSWindow();
EXPECT_TRUE([parent isMainWindow]);
NSButton* button = [parent standardWindowButton:NSWindowCloseButton];
@@ -244,7 +246,8 @@ TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) {
// First, test with LeftMouseDown in the parent window.
NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
- NSMakePoint(50, 50), parent_widget->GetNativeWindow());
+ NSMakePoint(50, 50),
+ parent_widget->GetNativeWindow().GetNativeNSWindow());
[NSApp sendEvent:mouse_down];
EXPECT_TRUE(bubble_widget->IsClosed());
@@ -254,7 +257,8 @@ TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) {
// Test with RightMouseDown in the parent window.
mouse_down = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
- NSMakePoint(50, 50), parent_widget->GetNativeWindow());
+ NSMakePoint(50, 50),
+ parent_widget->GetNativeWindow().GetNativeNSWindow());
[NSApp sendEvent:mouse_down];
EXPECT_TRUE(bubble_widget->IsClosed());
@@ -264,7 +268,8 @@ TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) {
// Test with RightMouseDown in the bubble (bubble should stay open).
mouse_down = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
- NSMakePoint(50, 50), bubble_widget->GetNativeWindow());
+ NSMakePoint(50, 50),
+ bubble_widget->GetNativeWindow().GetNativeNSWindow());
[NSApp sendEvent:mouse_down];
EXPECT_FALSE(bubble_widget->IsClosed());
bubble_widget->CloseNow();
@@ -276,7 +281,8 @@ TEST_F(NativeWidgetMacInteractiveUITest, BubbleDismiss) {
ShowKeyWindow(bubble_widget);
mouse_down = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
- NSMakePoint(50, 50), parent_widget->GetNativeWindow());
+ NSMakePoint(50, 50),
+ parent_widget->GetNativeWindow().GetNativeNSWindow());
[NSApp sendEvent:mouse_down];
EXPECT_FALSE(bubble_widget->IsClosed());
@@ -298,8 +304,8 @@ TEST_F(NativeWidgetMacInteractiveUITest, GlobalNSTextInputContextUpdates) {
widget->Show();
wait_for_first_active.Wait();
}
- EXPECT_TRUE([widget->GetNativeView() inputContext]);
- EXPECT_EQ([widget->GetNativeView() inputContext],
+ EXPECT_TRUE([widget->GetNativeView().GetNativeNSView() inputContext]);
+ EXPECT_EQ([widget->GetNativeView().GetNativeNSView() inputContext],
[NSTextInputContext currentInputContext]);
widget->GetContentsView()->RemoveChildView(textfield);
@@ -308,7 +314,7 @@ TEST_F(NativeWidgetMacInteractiveUITest, GlobalNSTextInputContextUpdates) {
// iteration. We just tore out the inputContext, so ensure the raw, weak
// global pointer that AppKit likes to keep around has been updated manually.
EXPECT_EQ(nil, [NSTextInputContext currentInputContext]);
- EXPECT_FALSE([widget->GetNativeView() inputContext]);
+ EXPECT_FALSE([widget->GetNativeView().GetNativeNSView() inputContext]);
// RemoveChildView() doesn't delete the view.
delete textfield;
diff --git a/chromium/ui/views/widget/native_widget_mac_unittest.mm b/chromium/ui/views/widget/native_widget_mac_unittest.mm
index 4efaef021c4..74b583c02bc 100644
--- a/chromium/ui/views/widget/native_widget_mac_unittest.mm
+++ b/chromium/ui/views/widget/native_widget_mac_unittest.mm
@@ -28,6 +28,7 @@
#include "ui/events/test/event_generator.h"
#import "ui/gfx/mac/coordinate_conversion.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/native/native_view_host.h"
@@ -93,7 +94,8 @@ namespace test {
class BridgedNativeWidgetTestApi {
public:
explicit BridgedNativeWidgetTestApi(NSWindow* window) {
- bridge_ = BridgedNativeWidgetImpl::GetFromNativeWindow(window);
+ bridge_ =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow(window)->bridge_impl();
}
// Simulate a frame swap from the compositor.
@@ -125,17 +127,21 @@ class TestWindowNativeWidgetMac : public NativeWidgetMac {
protected:
// NativeWidgetMac:
- NativeWidgetMacNSWindow* CreateNSWindow(
- const Widget::InitParams& params) override {
- NSUInteger style_mask = NSBorderlessWindowMask;
- if (params.type == Widget::InitParams::TYPE_WINDOW) {
- style_mask = NSTexturedBackgroundWindowMask | NSTitledWindowMask |
- NSClosableWindowMask | NSMiniaturizableWindowMask |
- NSResizableWindowMask;
+ void PopulateCreateWindowParams(
+ const views::Widget::InitParams& widget_params,
+ views_bridge_mac::mojom::CreateWindowParams* params) override {
+ params->style_mask = NSBorderlessWindowMask;
+ if (widget_params.type == Widget::InitParams::TYPE_WINDOW) {
+ params->style_mask = NSTexturedBackgroundWindowMask | NSTitledWindowMask |
+ NSClosableWindowMask | NSMiniaturizableWindowMask |
+ NSResizableWindowMask;
}
+ }
+ NativeWidgetMacNSWindow* CreateNSWindow(
+ const views_bridge_mac::mojom::CreateWindowParams* params) override {
return [[[NativeWidgetMacTestWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:style_mask
+ styleMask:params->style_mask
backing:NSBackingStoreBuffered
defer:NO] autorelease];
}
@@ -181,7 +187,7 @@ class NativeWidgetMacTest : public WidgetTest {
widget->Init(params);
widget->Show();
*window = base::mac::ObjCCastStrict<NativeWidgetMacTestWindow>(
- widget->GetNativeWindow());
+ widget->GetNativeWindow().GetNativeNSWindow());
EXPECT_TRUE(*window);
return widget;
}
@@ -245,7 +251,7 @@ class NativeHostHolder {
void Detach() { host_->Detach(); }
- gfx::NativeView view() const { return view_.get(); }
+ NSView* view() const { return view_.get(); }
NativeViewHost* host() const { return host_.get(); }
private:
@@ -292,7 +298,7 @@ class CustomTooltipView : public View {
// Test visibility states triggered externally.
TEST_F(NativeWidgetMacTest, HideAndShowExternally) {
Widget* widget = CreateTopLevelPlatformWidget();
- NSWindow* ns_window = widget->GetNativeWindow();
+ NSWindow* ns_window = widget->GetNativeWindow().GetNativeNSWindow();
WidgetChangeObserver observer(widget);
// Should initially be hidden.
@@ -421,10 +427,11 @@ class PaintCountView : public View {
// and state changes that are unavoidably flaky.
TEST_F(NativeWidgetMacTest, DISABLED_OrderFrontAfterMiniaturize) {
Widget* widget = CreateTopLevelPlatformWidget();
- NSWindow* ns_window = widget->GetNativeWindow();
+ NSWindow* ns_window = widget->GetNativeWindow().GetNativeNSWindow();
Widget* child_widget = CreateChildPlatformWidget(widget->GetNativeView());
- NSWindow* child_ns_window = child_widget->GetNativeWindow();
+ NSWindow* child_ns_window =
+ child_widget->GetNativeWindow().GetNativeNSWindow();
// Set parent bounds that overlap child.
widget->SetBounds(gfx::Rect(100, 100, 300, 300));
@@ -511,7 +518,7 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
PaintCountView* view = new PaintCountView();
widget->GetContentsView()->AddChildView(view);
- NSWindow* ns_window = widget->GetNativeWindow();
+ NSWindow* ns_window = widget->GetNativeWindow().GetNativeNSWindow();
WidgetChangeObserver observer(widget);
widget->SetBounds(gfx::Rect(100, 100, 300, 300));
@@ -595,7 +602,7 @@ TEST_F(NativeWidgetMacTest, MiniaturizeExternally) {
// Create a widget without a minimize button.
widget = CreateTopLevelFramelessPlatformWidget();
- ns_window = widget->GetNativeWindow();
+ ns_window = widget->GetNativeWindow().GetNativeNSWindow();
widget->SetBounds(gfx::Rect(100, 100, 300, 300));
widget->Show();
EXPECT_FALSE(widget->IsMinimized());
@@ -644,6 +651,7 @@ TEST_F(NativeWidgetMacTest, SetCursor) {
widget->GetContentsView()->AddChildView(new CursorView(0, hand));
widget->GetContentsView()->AddChildView(new CursorView(100, ibeam));
widget->Show();
+ NSWindow* widget_window = widget->GetNativeWindow().GetNativeNSWindow();
// Events used to simulate tracking rectangle updates. These are not passed to
// toolkit-views, so it only matters whether they are inside or outside the
@@ -662,29 +670,28 @@ TEST_F(NativeWidgetMacTest, SetCursor) {
// Use an event generator to ask views code to set the cursor. However, note
// that this does not cause Cocoa to generate tracking rectangle updates.
- ui::test::EventGenerator event_generator(GetContext(),
- widget->GetNativeWindow());
+ ui::test::EventGenerator event_generator(GetContext(), widget_window);
// Move the mouse over the first view, then simulate a tracking rectangle
// update. Verify that the cursor changed from arrow to hand type.
event_generator.MoveMouseTo(gfx::Point(50, 50));
- [widget->GetNativeWindow() cursorUpdate:event_in_content];
+ [widget_window cursorUpdate:event_in_content];
EXPECT_EQ(hand, [NSCursor currentCursor]);
// A tracking rectangle update not in the content area should forward to
// the native NSWindow implementation, which sets the arrow cursor.
- [widget->GetNativeWindow() cursorUpdate:event_out_of_content];
+ [widget_window cursorUpdate:event_out_of_content];
EXPECT_EQ(arrow, [NSCursor currentCursor]);
// Now move to the second view.
event_generator.MoveMouseTo(gfx::Point(150, 50));
- [widget->GetNativeWindow() cursorUpdate:event_in_content];
+ [widget_window cursorUpdate:event_in_content];
EXPECT_EQ(ibeam, [NSCursor currentCursor]);
// Moving to the third view (but remaining in the content area) should also
// forward to the native NSWindow implementation.
event_generator.MoveMouseTo(gfx::Point(250, 50));
- [widget->GetNativeWindow() cursorUpdate:event_in_content];
+ [widget_window cursorUpdate:event_in_content];
EXPECT_EQ(arrow, [NSCursor currentCursor]);
widget->CloseNow();
@@ -707,7 +714,8 @@ TEST_F(NativeWidgetMacTest, AccessibilityIntegration) {
NSRect nsrect = gfx::ScreenRectToNSRect(screen_rect);
NSPoint midpoint = NSMakePoint(NSMidX(nsrect), NSMidY(nsrect));
- id hit = [widget->GetNativeWindow() accessibilityHitTest:midpoint];
+ id hit = [widget->GetNativeWindow().GetNativeNSWindow()
+ accessibilityHitTest:midpoint];
id title = [hit accessibilityAttributeValue:NSAccessibilityValueAttribute];
EXPECT_NSEQ(title, @"Green");
@@ -726,7 +734,7 @@ Widget* AttachPopupToNativeParent(NSWindow* native_parent) {
// manager.
Widget* child = new Widget;
Widget::InitParams init_params;
- init_params.parent = anchor_view;
+ init_params.parent = anchor_view.get();
init_params.type = Widget::InitParams::TYPE_POPUP;
child->Init(init_params);
return child;
@@ -754,9 +762,13 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
EXPECT_NE(child, top_level_widget->GetWidget());
// To verify the parent, we need to use NativeWidgetMac APIs.
- BridgedNativeWidgetImpl* bridged_native_widget =
- BridgedNativeWidgetImpl::GetFromNativeWindow(child->GetNativeWindow());
- EXPECT_EQ(native_parent, bridged_native_widget->parent()->ns_window());
+ BridgedNativeWidgetHostImpl* bridged_native_widget_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ child->GetNativeWindow());
+ EXPECT_EQ(bridged_native_widget_host->parent()
+ ->native_widget_mac()
+ ->GetNativeWindow(),
+ native_parent);
const gfx::Rect child_bounds(50, 50, 200, 100);
child->SetBounds(child_bounds);
@@ -766,9 +778,9 @@ TEST_F(NativeWidgetMacTest, NonWidgetParent) {
child->Show();
EXPECT_TRUE(child->IsVisible());
EXPECT_EQ(1u, [[native_parent childWindows] count]);
- EXPECT_EQ(child->GetNativeWindow(),
- [[native_parent childWindows] objectAtIndex:0]);
- EXPECT_EQ(native_parent, [child->GetNativeWindow() parentWindow]);
+ EXPECT_EQ(child->GetNativeWindow(), [native_parent childWindows][0]);
+ EXPECT_EQ(native_parent,
+ [child->GetNativeWindow().GetNativeNSWindow() parentWindow]);
Widget::GetAllChildWidgets([native_parent contentView], &children);
ASSERT_EQ(2u, children.size());
@@ -783,7 +795,10 @@ 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()->ns_window());
+ EXPECT_EQ(bridged_native_widget_host->parent()
+ ->native_widget_mac()
+ ->GetNativeWindow(),
+ native_parent);
// Closing the parent should close and destroy the child.
EXPECT_FALSE(child_observer.widget_closed());
@@ -804,7 +819,7 @@ TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) {
Widget* widget = CreateTopLevelPlatformWidget();
widget->Show();
TestWidgetObserver observer(widget);
- last_window = widget->GetNativeWindow();
+ last_window = widget->GetNativeWindow().GetNativeNSWindow();
EXPECT_TRUE([[NSApp windows] containsObject:last_window]);
Widget::CloseAllSecondaryWidgets();
EXPECT_TRUE(observer.widget_closed());
@@ -825,7 +840,7 @@ TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) {
Widget* widget = CreateTopLevelPlatformWidget();
widget->Show();
TestWidgetObserver observer(widget);
- last_window = [widget->GetNativeWindow() retain];
+ last_window = [widget->GetNativeWindow().GetNativeNSWindow() retain];
EXPECT_TRUE([[NSApp windows] containsObject:last_window]);
widget->CloseNow();
EXPECT_TRUE(observer.widget_closed());
@@ -857,8 +872,10 @@ TEST_F(NativeWidgetMacTest, CloseAllSecondaryWidgetsValidState) {
TestWidgetObserver parent_observer(parent);
TestWidgetObserver child_observer(child);
- EXPECT_TRUE([[NSApp windows] containsObject:parent->GetNativeWindow()]);
- EXPECT_TRUE([[NSApp windows] containsObject:child->GetNativeWindow()]);
+ EXPECT_TRUE([[NSApp windows]
+ containsObject:parent->GetNativeWindow().GetNativeNSWindow()]);
+ EXPECT_TRUE([[NSApp windows]
+ containsObject:child->GetNativeWindow().GetNativeNSWindow()]);
Widget::CloseAllSecondaryWidgets();
EXPECT_TRUE(parent_observer.widget_closed());
EXPECT_TRUE(child_observer.widget_closed());
@@ -949,7 +966,7 @@ base::string16 TooltipTextForWidget(Widget* widget) {
// view and it fills the window. This just assumes the window is at least big
// big enough for a constant coordinate to be within it.
NSPoint point = NSMakePoint(30, 30);
- NSView* view = [widget->GetNativeView() hitTest:point];
+ NSView* view = [widget->GetNativeView().GetNativeNSView() hitTest:point];
NSString* text =
[view view:view stringForToolTip:0 point:point userData:nullptr];
return base::SysNSStringToUTF16(text);
@@ -1139,7 +1156,8 @@ Widget* ShowChildModalWidgetAndWait(NSWindow* native_parent) {
EXPECT_FALSE(modal_dialog_widget->IsVisible());
ScopedSwizzleWaiter show_waiter([ConstrainedWindowAnimationShow class]);
- BridgedNativeWidgetTestApi test_api(modal_dialog_widget->GetNativeWindow());
+ BridgedNativeWidgetTestApi test_api(
+ modal_dialog_widget->GetNativeWindow().GetNativeNSWindow());
EXPECT_FALSE(test_api.show_animation());
modal_dialog_widget->Show();
@@ -1235,7 +1253,8 @@ TEST_F(NativeWidgetMacTest, ShowAnimationControl) {
modal_dialog_widget->SetBounds(gfx::Rect(50, 50, 200, 150));
EXPECT_FALSE(modal_dialog_widget->IsVisible());
- BridgedNativeWidgetTestApi test_api(modal_dialog_widget->GetNativeWindow());
+ BridgedNativeWidgetTestApi test_api(
+ modal_dialog_widget->GetNativeWindow().GetNativeNSWindow());
EXPECT_FALSE(test_api.show_animation());
modal_dialog_widget->Show();
@@ -1295,7 +1314,7 @@ TEST_F(NativeWidgetMacTest, WindowModalSheet) {
// Retain, to run checks after the Widget is torn down.
base::scoped_nsobject<NSWindow> sheet_window(
- [sheet_widget->GetNativeWindow() retain]);
+ [sheet_widget->GetNativeWindow().GetNativeNSWindow() retain]);
// Although there is no titlebar displayed, sheets need NSTitledWindowMask in
// order to properly engage window-modal behavior in AppKit.
@@ -1387,7 +1406,8 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
{
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
- EXPECT_TRUE([sheet_widget->GetNativeWindow() isVisible]);
+ EXPECT_TRUE(
+ [sheet_widget->GetNativeWindow().GetNativeNSWindow() isVisible]);
WidgetChangeObserver widget_observer(sheet_widget);
@@ -1405,12 +1425,13 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
// Ensure the sheet wasn't blocked by a previous modal session.
- EXPECT_TRUE([sheet_widget->GetNativeWindow() isVisible]);
+ EXPECT_TRUE(
+ [sheet_widget->GetNativeWindow().GetNativeNSWindow() isVisible]);
WidgetChangeObserver widget_observer(sheet_widget);
// Test native -[NSWindow close] on the sheet. Does not animate.
- [sheet_widget->GetNativeWindow() close];
+ [sheet_widget->GetNativeWindow().GetNativeNSWindow() close];
EXPECT_TRUE(widget_observer.widget_closed());
base::RunLoop().RunUntilIdle();
}
@@ -1423,7 +1444,8 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
{
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
base::scoped_nsobject<NSWindow> sheet_window(
- sheet_widget->GetNativeWindow(), base::scoped_policy::RETAIN);
+ sheet_widget->GetNativeWindow().GetNativeNSWindow(),
+ base::scoped_policy::RETAIN);
EXPECT_TRUE([sheet_window isVisible]);
WidgetChangeObserver widget_observer(sheet_widget);
@@ -1446,7 +1468,8 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
{
base::mac::ScopedNSAutoreleasePool pool;
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
- NSWindow* sheet_window = sheet_widget->GetNativeWindow();
+ NSWindow* sheet_window =
+ sheet_widget->GetNativeWindow().GetNativeNSWindow();
EXPECT_TRUE([sheet_window isVisible]);
WidgetChangeObserver widget_observer(sheet_widget);
@@ -1465,7 +1488,8 @@ TEST_F(NativeWidgetMacTest, CloseWithWindowModalSheet) {
// Test -[NSWindow close] on the parent window.
{
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
- EXPECT_TRUE([sheet_widget->GetNativeWindow() isVisible]);
+ EXPECT_TRUE(
+ [sheet_widget->GetNativeWindow().GetNativeNSWindow() isVisible]);
WidgetChangeObserver widget_observer(sheet_widget);
[native_parent close];
@@ -1481,7 +1505,8 @@ TEST_F(NativeWidgetMacTest, CloseWindowModalSheetWithoutSheetParent) {
{
base::mac::ScopedNSAutoreleasePool pool;
Widget* sheet_widget = ShowWindowModalWidget(native_parent);
- NSWindow* sheet_window = sheet_widget->GetNativeWindow();
+ NSWindow* sheet_window =
+ sheet_widget->GetNativeWindow().GetNativeNSWindow();
EXPECT_TRUE([sheet_window isVisible]);
sheet_widget->Close(); // Asynchronous. Can't be called after -close.
@@ -1525,25 +1550,30 @@ TEST_F(NativeWidgetMacTest, NoopReparentNativeView) {
NSWindow* parent = MakeBorderlessNativeParent();
Widget* dialog = views::DialogDelegate::CreateDialogWidget(
new DialogDelegateView, nullptr, [parent contentView]);
- BridgedNativeWidgetImpl* bridge =
- BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow());
+ BridgedNativeWidgetHostImpl* bridge_host =
+ BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ dialog->GetNativeWindow());
- EXPECT_EQ(bridge->parent()->ns_window(), parent);
+ EXPECT_EQ(bridge_host->parent()->native_widget_mac()->GetNativeWindow(),
+ parent);
Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
- EXPECT_EQ(bridge->parent()->ns_window(), parent);
+ EXPECT_EQ(bridge_host->parent()->native_widget_mac()->GetNativeWindow(),
+ parent);
[parent close];
Widget* parent_widget = CreateNativeDesktopWidget();
- parent = parent_widget->GetNativeWindow();
+ parent = parent_widget->GetNativeWindow().GetNativeNSWindow();
dialog = views::DialogDelegate::CreateDialogWidget(
new DialogDelegateView, nullptr, [parent contentView]);
- bridge =
- BridgedNativeWidgetImpl::GetFromNativeWindow(dialog->GetNativeWindow());
+ bridge_host = BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ dialog->GetNativeWindow());
- EXPECT_EQ(bridge->parent()->ns_window(), parent);
+ EXPECT_EQ(bridge_host->parent()->native_widget_mac()->GetNativeWindow(),
+ parent);
Widget::ReparentNativeView(dialog->GetNativeView(), [parent contentView]);
- EXPECT_EQ(bridge->parent()->ns_window(), parent);
+ EXPECT_EQ(bridge_host->parent()->native_widget_mac()->GetNativeWindow(),
+ parent);
parent_widget->CloseNow();
}
@@ -1567,7 +1597,8 @@ class ParentCloseMonitor : public WidgetObserver {
// NSWindow parent/child relationship should be established on Show() and
// the parent should have a delegate. Retain the parent since it can't be
// retrieved from the child while it is being destroyed.
- parent_nswindow_.reset([[child->GetNativeWindow() parentWindow] retain]);
+ parent_nswindow_.reset(
+ [[child->GetNativeWindow().GetNativeNSWindow() parentWindow] retain]);
EXPECT_TRUE(parent_nswindow_);
EXPECT_TRUE([parent_nswindow_ delegate]);
}
@@ -1581,7 +1612,7 @@ class ParentCloseMonitor : public WidgetObserver {
// (it's removed just after OnWidgetDestroying() returns). The parent should
// still be open (children are always closed first), but not have a delegate
// (since it is being torn down).
- EXPECT_TRUE([child->GetNativeWindow() parentWindow]);
+ EXPECT_TRUE([child->GetNativeWindow().GetNativeNSWindow() parentWindow]);
EXPECT_TRUE([parent_nswindow_ isVisible]);
EXPECT_FALSE([parent_nswindow_ delegate]);
@@ -1589,7 +1620,7 @@ class ParentCloseMonitor : public WidgetObserver {
}
void OnWidgetDestroyed(Widget* child) override {
- EXPECT_FALSE([child->GetNativeWindow() parentWindow]);
+ EXPECT_FALSE([child->GetNativeWindow().GetNativeNSWindow() parentWindow]);
EXPECT_TRUE([parent_nswindow_ isVisible]);
EXPECT_FALSE([parent_nswindow_ delegate]);
@@ -1617,7 +1648,7 @@ TEST_F(NativeWidgetMacTest, NoParentDelegateDuringTeardown) {
parent->SetBounds(gfx::Rect(100, 100, 300, 200));
parent->Show();
ParentCloseMonitor monitor(parent);
- [parent->GetNativeWindow() close];
+ [parent->GetNativeWindow().GetNativeNSWindow() close];
EXPECT_TRUE(monitor.child_closed());
}
@@ -1650,37 +1681,48 @@ TEST_F(NativeWidgetMacTest, NoParentDelegateDuringTeardown) {
TEST_F(NativeWidgetMacTest, NativeProperties) {
// Create a regular widget (TYPE_WINDOW).
Widget* regular_widget = CreateNativeDesktopWidget();
- EXPECT_TRUE([regular_widget->GetNativeWindow() canBecomeKeyWindow]);
- EXPECT_TRUE([regular_widget->GetNativeWindow() canBecomeMainWindow]);
+ EXPECT_TRUE([regular_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeKeyWindow]);
+ EXPECT_TRUE([regular_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeMainWindow]);
// Disabling activation should prevent key and main status.
regular_widget->widget_delegate()->set_can_activate(false);
- EXPECT_FALSE([regular_widget->GetNativeWindow() canBecomeKeyWindow]);
- EXPECT_FALSE([regular_widget->GetNativeWindow() canBecomeMainWindow]);
+ EXPECT_FALSE([regular_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeKeyWindow]);
+ EXPECT_FALSE([regular_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeMainWindow]);
// Create a dialog widget (also TYPE_WINDOW), but with a DialogDelegate.
Widget* dialog_widget = views::DialogDelegate::CreateDialogWidget(
new ModalDialogDelegate(ui::MODAL_TYPE_CHILD), nullptr,
regular_widget->GetNativeView());
- EXPECT_TRUE([dialog_widget->GetNativeWindow() canBecomeKeyWindow]);
+ EXPECT_TRUE([dialog_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeKeyWindow]);
// Dialogs shouldn't take main status away from their parent.
- EXPECT_FALSE([dialog_widget->GetNativeWindow() canBecomeMainWindow]);
+ EXPECT_FALSE([dialog_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeMainWindow]);
// Create a bubble widget with a parent: also shouldn't get main.
BubbleDialogDelegateView* bubble_view = new SimpleBubbleView();
bubble_view->set_parent_window(regular_widget->GetNativeView());
Widget* bubble_widget = BubbleDialogDelegateView::CreateBubble(bubble_view);
- EXPECT_TRUE([bubble_widget->GetNativeWindow() canBecomeKeyWindow]);
- EXPECT_FALSE([bubble_widget->GetNativeWindow() canBecomeMainWindow]);
+ EXPECT_TRUE([bubble_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeKeyWindow]);
+ EXPECT_FALSE([bubble_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeMainWindow]);
EXPECT_EQ(NSWindowCollectionBehaviorTransient,
- [bubble_widget->GetNativeWindow() collectionBehavior] &
+ [bubble_widget->GetNativeWindow().GetNativeNSWindow()
+ collectionBehavior] &
NSWindowCollectionBehaviorTransient);
// But a bubble without a parent should still be able to become main.
Widget* toplevel_bubble_widget =
BubbleDialogDelegateView::CreateBubble(new SimpleBubbleView());
- EXPECT_TRUE([toplevel_bubble_widget->GetNativeWindow() canBecomeKeyWindow]);
- EXPECT_TRUE([toplevel_bubble_widget->GetNativeWindow() canBecomeMainWindow]);
+ EXPECT_TRUE([toplevel_bubble_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeKeyWindow]);
+ EXPECT_TRUE([toplevel_bubble_widget->GetNativeWindow().GetNativeNSWindow()
+ canBecomeMainWindow]);
toplevel_bubble_widget->CloseNow();
regular_widget->CloseNow();
@@ -1744,7 +1786,7 @@ TEST_F(NativeWidgetMacTest, DISABLED_DoesHideTitle) {
widget->Init(params);
widget->Show();
- NSWindow* ns_window = widget->GetNativeWindow();
+ NSWindow* ns_window = widget->GetNativeWindow().GetNativeNSWindow();
// Disable color correction so we can read unmodified values from the bitmap.
[ns_window setColorSpace:[NSColorSpace sRGBColorSpace]];
@@ -1866,7 +1908,7 @@ TEST_F(NativeWidgetMacTest, GetWorkAreaBoundsInScreen) {
EXPECT_FALSE(NSIsEmptyRect(actual));
EXPECT_NSEQ(expected, actual);
- [widget.GetNativeWindow() close];
+ [widget.GetNativeWindow().GetNativeNSWindow() close];
actual = gfx::ScreenRectToNSRect(widget.GetWorkAreaBoundsInScreen());
EXPECT_TRUE(NSIsEmptyRect(actual));
}
@@ -1874,7 +1916,7 @@ TEST_F(NativeWidgetMacTest, GetWorkAreaBoundsInScreen) {
// Test that Widget opacity can be changed.
TEST_F(NativeWidgetMacTest, ChangeOpacity) {
Widget* widget = CreateTopLevelPlatformWidget();
- NSWindow* ns_window = widget->GetNativeWindow();
+ NSWindow* ns_window = widget->GetNativeWindow().GetNativeNSWindow();
CGFloat old_opacity = [ns_window alphaValue];
widget->SetOpacity(.7f);
@@ -1895,7 +1937,7 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Titled) {
// Setup the mock content view for the NSWindow, so that we can intercept
// drawRect.
- NSWindow* window = widget->GetNativeWindow();
+ NSWindow* window = widget->GetNativeWindow().GetNativeNSWindow();
base::scoped_nsobject<MockBridgedView> mock_bridged_view(
[[MockBridgedView alloc] init]);
// Reset drawRect count.
@@ -1941,7 +1983,7 @@ TEST_F(NativeWidgetMacTest, SchedulePaintInRect_Borderless) {
// Setup the mock content view for the NSWindow, so that we can intercept
// drawRect.
- NSWindow* window = widget->GetNativeWindow();
+ NSWindow* window = widget->GetNativeWindow().GetNativeNSWindow();
base::scoped_nsobject<MockBridgedView> mock_bridged_view(
[[MockBridgedView alloc] init]);
// Reset drawRect count.
@@ -1983,8 +2025,8 @@ TEST_F(NativeWidgetMacTest, ChangeFocusOnChangeFirstResponder) {
widget->Show();
base::scoped_nsobject<NSView> child_view([[FocusableTestNSView alloc]
- initWithFrame:[widget->GetNativeView() bounds]]);
- [widget->GetNativeView() addSubview:child_view];
+ initWithFrame:[widget->GetNativeView().GetNativeNSView() bounds]]);
+ [widget->GetNativeView().GetNativeNSView() addSubview:child_view];
EXPECT_TRUE([child_view acceptsFirstResponder]);
EXPECT_TRUE(widget->GetRootView()->IsFocusable());
@@ -1992,10 +2034,11 @@ TEST_F(NativeWidgetMacTest, ChangeFocusOnChangeFirstResponder) {
manager->SetFocusedView(widget->GetRootView());
EXPECT_EQ(manager->GetFocusedView(), widget->GetRootView());
- [widget->GetNativeWindow() makeFirstResponder:child_view];
+ [widget->GetNativeWindow().GetNativeNSWindow() makeFirstResponder:child_view];
EXPECT_FALSE(manager->GetFocusedView());
- [widget->GetNativeWindow() makeFirstResponder:widget->GetNativeView()];
+ [widget->GetNativeWindow().GetNativeNSWindow()
+ makeFirstResponder:widget->GetNativeView().GetNativeNSView()];
EXPECT_EQ(manager->GetFocusedView(), widget->GetRootView());
widget->CloseNow();
@@ -2013,7 +2056,7 @@ TEST_F(NativeWidgetMacTest, ReparentNativeViewBounds) {
widget->Init(params);
widget->SetContentsView(new View);
- NSView* child_view = widget->GetNativeView();
+ NSView* child_view = widget->GetNativeView().GetNativeNSView();
Widget::ReparentNativeView(child_view, parent->GetNativeView());
// Reparented content view has the size of the Widget that created it.
@@ -2026,13 +2069,13 @@ TEST_F(NativeWidgetMacTest, ReparentNativeViewBounds) {
NSRect native_parent_rect = NSMakeRect(50, 100, 200, 70);
base::scoped_nsobject<NSView> native_parent(
[[NSView alloc] initWithFrame:native_parent_rect]);
- [parent->GetNativeView() addSubview:native_parent];
+ [parent->GetNativeView().GetNativeNSView() addSubview:native_parent];
gfx::Rect screen_rect = widget->GetWindowBoundsInScreen();
EXPECT_EQ(100, screen_rect.x());
EXPECT_EQ(100, screen_rect.y());
- Widget::ReparentNativeView(child_view, native_parent);
+ Widget::ReparentNativeView(child_view, native_parent.get());
widget->SetBounds(widget_rect);
screen_rect = widget->GetWindowBoundsInScreen();
EXPECT_EQ(150, screen_rect.x());
@@ -2061,21 +2104,21 @@ TEST_F(NativeWidgetMacTest, ReparentNativeViewTypes) {
Widget::ReparentNativeView(child->GetNativeView(),
toplevel1->GetNativeView());
- EXPECT_EQ([child->GetNativeView() window],
- [toplevel1->GetNativeView() window]);
- EXPECT_EQ(0, [child->GetNativeWindow() alphaValue]);
+ EXPECT_EQ([child->GetNativeView().GetNativeNSView() window],
+ [toplevel1->GetNativeView().GetNativeNSView() window]);
+ EXPECT_EQ(0, [child->GetNativeWindow().GetNativeNSWindow() alphaValue]);
Widget::ReparentNativeView(child->GetNativeView(),
toplevel2->GetNativeView());
- EXPECT_EQ([child->GetNativeView() window],
- [toplevel2->GetNativeView() window]);
- EXPECT_EQ(0, [child->GetNativeWindow() alphaValue]);
- EXPECT_NE(0, [toplevel1->GetNativeWindow() alphaValue]);
+ EXPECT_EQ([child->GetNativeView().GetNativeNSView() window],
+ [toplevel2->GetNativeView().GetNativeNSView() window]);
+ EXPECT_EQ(0, [child->GetNativeWindow().GetNativeNSWindow() alphaValue]);
+ EXPECT_NE(0, [toplevel1->GetNativeWindow().GetNativeNSWindow() alphaValue]);
Widget::ReparentNativeView(toplevel2->GetNativeView(),
toplevel1->GetNativeView());
- EXPECT_EQ([toplevel2->GetNativeWindow() parentWindow],
- [toplevel1->GetNativeView() window]);
+ EXPECT_EQ([toplevel2->GetNativeWindow().GetNativeNSWindow() parentWindow],
+ [toplevel1->GetNativeView().GetNativeNSView() window]);
}
// Test class for Full Keyboard Access related tests.
@@ -2089,8 +2132,9 @@ class NativeWidgetMacFullKeyboardAccessTest : public NativeWidgetMacTest {
NativeWidgetMacTest::SetUp();
widget_ = CreateTopLevelPlatformWidget();
- bridge_ = BridgedNativeWidgetImpl::GetFromNativeWindow(
- widget_->GetNativeWindow());
+ bridge_ = BridgedNativeWidgetHostImpl::GetFromNativeWindow(
+ widget_->GetNativeWindow())
+ ->bridge_impl();
fake_full_keyboard_access_ =
ui::test::ScopedFakeFullKeyboardAccess::GetInstance();
DCHECK(fake_full_keyboard_access_);
@@ -2162,7 +2206,8 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
widget_ = CreateTopLevelPlatformWidget();
- starting_subviews_.reset([[widget_->GetNativeView() subviews] copy]);
+ starting_subviews_.reset(
+ [[widget_->GetNativeView().GetNativeNSView() subviews] copy]);
native_host_parent_ = new View();
widget_->GetContentsView()->AddChildView(native_host_parent_);
@@ -2175,7 +2220,7 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
hosts_.push_back(std::move(holder));
}
EXPECT_EQ(kNativeViewCount, native_host_parent_->child_count());
- EXPECT_NSEQ([widget_->GetNativeView() subviews],
+ EXPECT_NSEQ([widget_->GetNativeView().GetNativeNSView() subviews],
([GetStartingSubviews() arrayByAddingObjectsFromArray:@[
hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
]]));
@@ -2186,7 +2231,9 @@ class NativeWidgetMacViewsOrderTest : public WidgetTest {
WidgetTest::TearDown();
}
- NSView* GetContentNativeView() { return widget_->GetNativeView(); }
+ NSView* GetContentNativeView() {
+ return widget_->GetNativeView().GetNativeNSView();
+ }
NSArray<NSView*>* GetStartingSubviews() { return starting_subviews_; }
@@ -2269,7 +2316,7 @@ TEST_F(NativeWidgetMacTest, CanClose) {
ModalDialogDelegate* delegate = new ModalDialogDelegate(ui::MODAL_TYPE_NONE);
Widget* widget =
views::DialogDelegate::CreateDialogWidget(delegate, nullptr, nullptr);
- NSWindow* window = widget->GetNativeWindow();
+ NSWindow* window = widget->GetNativeWindow().GetNativeNSWindow();
delegate->set_can_close(false);
EXPECT_FALSE([[window delegate] windowShouldClose:window]);
delegate->set_can_close(true);
@@ -2310,7 +2357,9 @@ TEST_F(NativeWidgetMacTest, TouchBar) {
ModalDialogDelegate* delegate = new ModalDialogDelegate(ui::MODAL_TYPE_NONE);
views::DialogDelegate::CreateDialogWidget(delegate, nullptr, nullptr);
DialogClientView* client_view = delegate->GetDialogClientView();
- NSView* content = [delegate->GetWidget()->GetNativeWindow() contentView];
+ NSView* content =
+ [delegate->GetWidget()->GetNativeWindow().GetNativeNSWindow()
+ contentView];
NSString* principal = nil;
NSObject* old_touch_bar = nil;
diff --git a/chromium/ui/views/widget/native_widget_unittest.cc b/chromium/ui/views/widget/native_widget_unittest.cc
index 2914d8de4b2..661ea6a9611 100644
--- a/chromium/ui/views/widget/native_widget_unittest.cc
+++ b/chromium/ui/views/widget/native_widget_unittest.cc
@@ -62,7 +62,7 @@ class NativeWidgetTest : public ViewsTestBase {
TEST_F(NativeWidgetTest, CreateNativeWidget) {
ScopedTestWidget widget(CreateNativeWidget());
- EXPECT_TRUE(widget->GetWidget()->GetNativeView() != NULL);
+ EXPECT_TRUE(widget->GetWidget()->GetNativeView());
}
TEST_F(NativeWidgetTest, GetNativeWidgetForNativeView) {
diff --git a/chromium/ui/views/widget/root_view.cc b/chromium/ui/views/widget/root_view.cc
index 4d11e22af84..67a7e3fb70a 100644
--- a/chromium/ui/views/widget/root_view.cc
+++ b/chromium/ui/views/widget/root_view.cc
@@ -60,8 +60,9 @@ class PreEventDispatchHandler : public ui::EventHandler {
public:
explicit PreEventDispatchHandler(View* owner)
: owner_(owner) {
+ owner_->AddPreTargetHandler(this);
}
- ~PreEventDispatchHandler() override {}
+ ~PreEventDispatchHandler() override { owner_->RemovePreTargetHandler(this); }
private:
// ui::EventHandler:
@@ -170,7 +171,6 @@ RootView::RootView(Widget* widget)
focus_traversable_parent_view_(NULL),
event_dispatch_target_(NULL),
old_dispatch_target_(NULL) {
- AddPreTargetHandler(pre_dispatch_handler_.get());
AddPostTargetHandler(post_dispatch_handler_.get());
SetEventTargeter(
std::unique_ptr<ViewTargeter>(new RootViewTargeter(this, this)));
diff --git a/chromium/ui/views/widget/widget.h b/chromium/ui/views/widget/widget.h
index 2efbe5c4d89..e7116c1b21d 100644
--- a/chromium/ui/views/widget/widget.h
+++ b/chromium/ui/views/widget/widget.h
@@ -26,16 +26,6 @@
#include "ui/views/window/client_view.h"
#include "ui/views/window/non_client_view.h"
-#if defined(OS_WIN)
-// Windows headers define macros for these function names which screw with us.
-#if defined(IsMaximized)
-#undef IsMaximized
-#endif
-#if defined(IsMinimized)
-#undef IsMinimized
-#endif
-#endif
-
namespace base {
class TimeDelta;
}
diff --git a/chromium/ui/views/widget/widget_interactive_uitest.cc b/chromium/ui/views/widget/widget_interactive_uitest.cc
index ab1cd09214e..22d9afaae78 100644
--- a/chromium/ui/views/widget/widget_interactive_uitest.cc
+++ b/chromium/ui/views/widget/widget_interactive_uitest.cc
@@ -37,6 +37,7 @@
#include "ui/views/test/widget_test.h"
#include "ui/views/touchui/touch_selection_controller_impl.h"
#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_utils.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/wm/public/activation_client.h"
@@ -328,7 +329,7 @@ TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) {
Widget* widget1 = CreateWidget();
widget1->GetContentsView()->AddChildView(focusable_view1);
widget1->Show();
- aura::Window* root_window1 = widget1->GetNativeView()->GetRootWindow();
+ aura::Window* root_window1 = GetRootWindow(widget1);
focusable_view1->RequestFocus();
EXPECT_TRUE(root_window1 != NULL);
@@ -342,7 +343,7 @@ TEST_F(WidgetTestInteractive, DesktopNativeWidgetAuraActivationAndFocusTest) {
Widget* widget2 = CreateWidget();
widget1->GetContentsView()->AddChildView(focusable_view2);
widget2->Show();
- aura::Window* root_window2 = widget2->GetNativeView()->GetRootWindow();
+ aura::Window* root_window2 = GetRootWindow(widget2);
focusable_view2->RequestFocus();
ActivatePlatformWindow(widget2);
@@ -1064,7 +1065,7 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
gfx::NativeView modal_native_view = modal_dialog_widget->GetNativeView();
ASSERT_EQ(3u, focus_changes.size());
- EXPECT_EQ(nullptr, focus_changes[1]);
+ EXPECT_EQ(gfx::kNullNativeView, focus_changes[1]);
EXPECT_EQ(modal_native_view, focus_changes[2]);
#if defined(OS_MACOSX)
@@ -1078,7 +1079,7 @@ TEST_F(WidgetTestInteractive, WindowModalWindowDestroyedActivationTest) {
#endif
ASSERT_EQ(5u, focus_changes.size());
- EXPECT_EQ(nullptr, focus_changes[3]);
+ EXPECT_EQ(gfx::kNullNativeView, focus_changes[3]);
EXPECT_EQ(top_level_native_view, focus_changes[4]);
top_level_widget.CloseNow();
@@ -1175,8 +1176,9 @@ TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) {
RunPendingMessages();
- ui::test::EventGenerator generator(widget->GetNativeWindow());
- generator.GestureTapAt(gfx::Point(10, 10));
+ ui::test::EventGenerator generator(GetRootWindow(widget));
+ generator.GestureTapAt(textfield->GetBoundsInScreen().origin() +
+ gfx::Vector2d(10, 10));
ShowQuickMenuImmediately(static_cast<TouchSelectionControllerImpl*>(
textfield_test_api.touch_selection_controller()));
@@ -1683,7 +1685,7 @@ TEST_F(WidgetCaptureTest, FailedCaptureRequestIsNoop) {
widget.Show();
ui::test::EventGenerator generator(GetContext(), widget.GetNativeWindow());
- generator.set_current_location(gfx::Point(300, 10));
+ generator.set_current_screen_location(gfx::Point(300, 10));
generator.PressLeftButton();
EXPECT_FALSE(mouse_view1->pressed());
@@ -1722,8 +1724,8 @@ TEST_F(WidgetCaptureTest, MAYBE_MouseExitOnCaptureGrab) {
widget2.Show();
widget2.SetBounds(gfx::Rect(400, 0, 300, 300));
- ui::test::EventGenerator generator(widget1.GetNativeWindow());
- generator.set_current_location(gfx::Point(100, 100));
+ ui::test::EventGenerator generator(GetRootWindow(&widget1));
+ generator.set_current_screen_location(gfx::Point(100, 100));
generator.MoveMouseBy(0, 0);
EXPECT_EQ(1, mouse_view1->EnteredCalls());
diff --git a/chromium/ui/views/widget/widget_unittest.cc b/chromium/ui/views/widget/widget_unittest.cc
index 352e4fbfe64..fe6621a26df 100644
--- a/chromium/ui/views/widget/widget_unittest.cc
+++ b/chromium/ui/views/widget/widget_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/events/event_observer.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point.h"
@@ -32,6 +33,7 @@
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget_deletion_observer.h"
#include "ui/views/widget/widget_removals_observer.h"
+#include "ui/views/widget/widget_utils.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/views/window/native_frame_view.h"
@@ -1697,6 +1699,8 @@ TEST_F(WidgetTest, EventHandlersOnRootView) {
EXPECT_EQ(0, h1.GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(0, view->GetEventCount(ui::ET_MOUSEWHEEL));
EXPECT_EQ(0, h2.GetEventCount(ui::ET_MOUSEWHEEL));
+
+ root_view->RemovePreTargetHandler(&h1);
}
TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
@@ -1720,7 +1724,7 @@ TEST_F(WidgetTest, SynthesizeMouseMoveEvent) {
gfx::Point cursor_location(5, 5);
ui::test::EventGenerator generator(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget.get()) : GetContext(),
widget->GetNativeWindow());
generator.MoveMouseTo(cursor_location);
@@ -1777,7 +1781,7 @@ TEST_F(WidgetTest, MouseEventDispatchWhileTouchIsDown) {
event_count_view->AddPostTargetHandler(&consumer);
ui::test::EventGenerator generator(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget) : GetContext(),
widget->GetNativeWindow());
generator.PressTouch();
generator.ClickLeftButton();
@@ -1803,13 +1807,14 @@ TEST_F(WidgetTest, MousePressCausesCapture) {
widget->GetRootView()->AddChildView(event_count_view);
// No capture has been set.
- EXPECT_EQ(nullptr, internal::NativeWidgetPrivate::GetGlobalCapture(
- widget->GetNativeView()));
+ EXPECT_EQ(
+ gfx::kNullNativeView,
+ internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
MousePressEventConsumer consumer;
event_count_view->AddPostTargetHandler(&consumer);
ui::test::EventGenerator generator(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget) : GetContext(),
widget->GetNativeWindow());
generator.PressLeftButton();
@@ -1864,15 +1869,16 @@ TEST_F(WidgetTest, CaptureDuringMousePressNotOverridden) {
event_count_view->SetBounds(0, 0, 300, 300);
widget->GetRootView()->AddChildView(event_count_view);
- EXPECT_EQ(nullptr, internal::NativeWidgetPrivate::GetGlobalCapture(
- widget->GetNativeView()));
+ EXPECT_EQ(
+ gfx::kNullNativeView,
+ internal::NativeWidgetPrivate::GetGlobalCapture(widget->GetNativeView()));
Widget* widget2 = CreateTopLevelNativeWidget();
// Gives explicit capture to |widget2|
CaptureEventConsumer consumer(widget2);
event_count_view->AddPostTargetHandler(&consumer);
ui::test::EventGenerator generator(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget) : GetContext(),
widget->GetNativeWindow());
// This event should implicitly give capture to |widget|, except that
// |consumer| will explicitly set capture on |widget2|.
@@ -1890,52 +1896,69 @@ TEST_F(WidgetTest, CaptureDuringMousePressNotOverridden) {
widget->CloseNow();
}
-class ClosingEventHandler : public View {
+class ClosingEventObserver : public ui::EventObserver {
public:
- explicit ClosingEventHandler(Widget* widget) : widget_(widget) {}
+ explicit ClosingEventObserver(Widget* widget) : widget_(widget) {}
- // ui::EventHandler:
- void OnMouseEvent(ui::MouseEvent* event) override {
- // Don't close twice if closing the Widget generates a capture update event.
- if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)
+ // ui::EventObserver:
+ void OnEvent(const ui::Event& event) override {
+ // Guard against attempting to close the widget twice.
+ if (widget_)
widget_->CloseNow();
+ widget_ = nullptr;
}
private:
Widget* widget_;
- DISALLOW_COPY_AND_ASSIGN(ClosingEventHandler);
+ DISALLOW_COPY_AND_ASSIGN(ClosingEventObserver);
+};
+
+class ClosingView : public View {
+ public:
+ explicit ClosingView(Widget* widget) : widget_(widget) {}
+
+ // View:
+ void OnEvent(ui::Event* event) override {
+ // Guard against closing twice and writing to freed memory.
+ if (widget_ && event->type() == ui::ET_MOUSE_PRESSED) {
+ Widget* widget = widget_;
+ widget_ = nullptr;
+ widget->CloseNow();
+ }
+ }
+
+ private:
+ Widget* widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClosingView);
};
// Ensures that when multiple objects are intercepting OS-level events, that one
// can safely close a Widget that has capture.
TEST_F(WidgetTest, DestroyedWithCaptureViaEventMonitor) {
- // On Mus, a CHECK(!details.dispatcher_destroyed) is hit in the EventGenerator
- // call below. TODO(crbug/799428): Investigate.
- if (IsMus())
- return;
-
Widget* widget = CreateTopLevelNativeWidget();
TestWidgetObserver observer(widget);
widget->Show();
widget->SetSize(gfx::Size(300, 300));
- // We need two ClosingEventHandler (both will try to close the Widget). On Mac
+ // ClosingView and ClosingEventObserver both try to close the Widget. On Mac
// the order that EventMonitors receive OS events is not deterministic. If the
// one installed via SetCapture() sees it first, the event is swallowed (so
// both need to try). Note the regression test would only fail when the
// SetCapture() handler did _not_ swallow the event, but it still needs to try
// to close the Widget otherwise it will be left open, which fails elsewhere.
- ClosingEventHandler* view_handler = new ClosingEventHandler(widget);
- widget->GetContentsView()->AddChildView(view_handler);
- widget->SetCapture(view_handler);
+ ClosingView* closing_view = new ClosingView(widget);
+ widget->GetContentsView()->AddChildView(closing_view);
+ widget->SetCapture(closing_view);
- ClosingEventHandler monitor_handler(widget);
+ ClosingEventObserver closing_event_observer(widget);
auto monitor = EventMonitor::CreateApplicationMonitor(
- &monitor_handler, widget->GetNativeWindow());
+ &closing_event_observer, widget->GetNativeWindow(),
+ {ui::ET_MOUSE_PRESSED});
ui::test::EventGenerator generator(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget) : GetContext(),
widget->GetNativeWindow());
generator.set_target(ui::test::EventGenerator::Target::APPLICATION);
@@ -2045,7 +2068,7 @@ TEST_F(WidgetTest, WidgetDeleted_InOnMousePressed) {
widget->Show();
ui::test::EventGenerator generator(
- IsMus() ? widget->GetNativeWindow() : GetContext(),
+ IsMus() ? GetRootWindow(widget) : GetContext(),
widget->GetNativeWindow());
WidgetDeletionObserver deletion_observer(widget);
@@ -3384,7 +3407,7 @@ TEST_F(WidgetTest, MouseEventTypesViaGenerator) {
widget->Show();
ui::test::EventGenerator generator(GetContext(), widget->GetNativeWindow());
- generator.set_current_location(gfx::Point(20, 20));
+ generator.set_current_screen_location(gfx::Point(20, 20));
generator.ClickLeftButton();
EXPECT_EQ(1, view->GetEventCount(ui::ET_MOUSE_PRESSED));
diff --git a/chromium/ui/views/widget/widget_utils.cc b/chromium/ui/views/widget/widget_utils.cc
new file mode 100644
index 00000000000..94539dafdd0
--- /dev/null
+++ b/chromium/ui/views/widget/widget_utils.cc
@@ -0,0 +1,23 @@
+// 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/widget_utils.h"
+
+#include "ui/views/widget/widget.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#endif
+
+namespace views {
+
+gfx::NativeWindow GetRootWindow(const Widget* widget) {
+ gfx::NativeWindow window = widget->GetNativeWindow();
+#if defined(USE_AURA)
+ window = window->GetRootWindow();
+#endif
+ return window;
+}
+
+} // namespace views
diff --git a/chromium/ui/views/widget/widget_utils.h b/chromium/ui/views/widget/widget_utils.h
new file mode 100644
index 00000000000..f67d9f6efdd
--- /dev/null
+++ b/chromium/ui/views/widget/widget_utils.h
@@ -0,0 +1,20 @@
+// 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_WIDGET_WIDGET_UTILS_H_
+#define UI_VIEWS_WIDGET_WIDGET_UTILS_H_
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+class Widget;
+
+// Returns the root window for |widget|. On non-Aura, this is equivalent to
+// widget->GetNativeWindow().
+VIEWS_EXPORT gfx::NativeWindow GetRootWindow(const Widget* widget);
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WIDGET_H_
diff --git a/chromium/ui/views/widget/widget_utils_mac.mm b/chromium/ui/views/widget/widget_utils_mac.mm
index 990e17faf2f..6dbf0d11a46 100644
--- a/chromium/ui/views/widget/widget_utils_mac.mm
+++ b/chromium/ui/views/widget/widget_utils_mac.mm
@@ -11,7 +11,7 @@ namespace views {
gfx::Size GetWindowSizeForClientSize(Widget* widget, const gfx::Size& size) {
DCHECK(widget);
return BridgedNativeWidgetImpl::GetWindowSizeForClientSize(
- widget->GetNativeWindow(), size);
+ widget->GetNativeWindow().GetNativeNSWindow(), size);
}
} // namespace views
diff --git a/chromium/ui/views/win/hwnd_message_handler.cc b/chromium/ui/views/win/hwnd_message_handler.cc
index 9afbcf6ca30..322315fb109 100644
--- a/chromium/ui/views/win/hwnd_message_handler.cc
+++ b/chromium/ui/views/win/hwnd_message_handler.cc
@@ -219,6 +219,12 @@ BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) {
return TRUE;
}
+bool IsDwmCompositionEnabled() {
+ BOOL is_dwm_composition_enabled;
+ DwmIsCompositionEnabled(&is_dwm_composition_enabled);
+ return static_cast<bool>(is_dwm_composition_enabled);
+}
+
// The thickness of an auto-hide taskbar in pixels.
const int kAutoHideTaskbarThicknessPx = 2;
@@ -395,6 +401,7 @@ HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
touch_down_contexts_(0),
last_mouse_hwheel_time_(0),
dwm_transition_desired_(false),
+ dwm_composition_enabled_(IsDwmCompositionEnabled()),
sent_window_size_changing_(false),
left_button_down_on_caption_(false),
background_fullscreen_hack_(false),
@@ -843,6 +850,7 @@ void HWNDMessageHandler::SetCursor(HCURSOR cursor) {
}
void HWNDMessageHandler::FrameTypeChanged() {
+ needs_dwm_frame_clear_ = true;
if (!custom_window_region_.is_valid() && IsFrameSystemDrawn())
dwm_transition_desired_ = true;
if (!dwm_transition_desired_ || !IsFullscreen())
@@ -1629,7 +1637,16 @@ LRESULT HWNDMessageHandler::OnDwmCompositionChanged(UINT msg,
return 0;
}
- FrameTypeChanged();
+ bool dwm_composition_enabled = IsDwmCompositionEnabled();
+ if (dwm_composition_enabled_ != dwm_composition_enabled) {
+ // Do not cause the Window to be hidden and shown unless there was
+ // an actual change in the theme. This filter is necessary because
+ // Windows sends redundant WM_DWMCOMPOSITIONCHANGED messages when
+ // a laptop is reopened, and our theme change code causes wonky
+ // focus issues. See http://crbug.com/895855 for more information.
+ dwm_composition_enabled_ = dwm_composition_enabled;
+ FrameTypeChanged();
+ }
return 0;
}
@@ -1673,6 +1690,20 @@ void HWNDMessageHandler::OnEnterSizeMove() {
}
LRESULT HWNDMessageHandler::OnEraseBkgnd(HDC dc) {
+ gfx::Insets insets;
+ if (ui::win::IsAeroGlassEnabled() &&
+ delegate_->GetDwmFrameInsetsInPixels(&insets) && !insets.IsEmpty() &&
+ needs_dwm_frame_clear_) {
+ // This is necessary to avoid white flashing in the titlebar area around the
+ // minimize/maximize/close buttons.
+ needs_dwm_frame_clear_ = false;
+ RECT client_rect;
+ GetClientRect(hwnd(), &client_rect);
+ base::win::ScopedGDIObject<HBRUSH> brush(CreateSolidBrush(0));
+ // The DC and GetClientRect operate in client area coordinates.
+ RECT rect = {0, 0, client_rect.right, insets.top()};
+ FillRect(dc, &rect, brush.get());
+ }
// Needed to prevent resize flicker.
return 1;
}
@@ -2727,7 +2758,7 @@ void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) {
} else if (window_pos->flags & SWP_HIDEWINDOW) {
delegate_->HandleVisibilityChanged(false);
}
-
+ UpdateDwmFrame();
SetMsgHandled(FALSE);
}
@@ -2934,7 +2965,7 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message,
// Increment |touch_down_contexts_| on a pointer down. This variable
// is used to debounce the WM_MOUSEACTIVATE events.
- if (message == WM_POINTERDOWN) {
+ if (message == WM_POINTERDOWN || message == WM_NCPOINTERDOWN) {
touch_down_contexts_++;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
@@ -2988,6 +3019,23 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypeTouch(UINT message,
if (event_type == ui::ET_TOUCH_RELEASED)
id_generator_.ReleaseNumber(pointer_id);
+ // Mark touch released events handled. These will usually turn into tap
+ // gestures, and doing this avoids propagating the event to other windows.
+ if (delegate_->GetFrameMode() == FrameMode::SYSTEM_DRAWN) {
+ // WM_NCPOINTERUP must be DefWindowProc'ed in order for the system caption
+ // buttons to work correctly.
+ if (message == WM_POINTERUP)
+ event.SetHandled();
+ } else {
+ // Messages on HTCAPTION should be DefWindowProc'ed, as we let Windows
+ // take care of dragging the window and double-tapping to maximize.
+ const bool on_titlebar =
+ SendMessage(hwnd(), WM_NCHITTEST, 0, l_param) == HTCAPTION;
+ // Unlike above, we must mark both WM_POINTERUP and WM_NCPOINTERUP as
+ // handled, in order for the custom caption buttons to work correctly.
+ if (event_type == ui::ET_TOUCH_RELEASED && !on_titlebar)
+ event.SetHandled();
+ }
SetMsgHandled(event.handled());
}
return 0;
@@ -3068,6 +3116,9 @@ void HWNDMessageHandler::PerformDwmTransition() {
ResetWindowRegion(true, false);
// The non-client view needs to update too.
delegate_->HandleFrameChanged();
+ // This calls DwmExtendFrameIntoClientArea which must be called when DWM
+ // composition state changes.
+ UpdateDwmFrame();
if (IsVisible() && IsFrameSystemDrawn()) {
// For some reason, we need to hide the window after we change from a custom
@@ -3076,6 +3127,9 @@ void HWNDMessageHandler::PerformDwmTransition() {
// SetWindowRgn, but the details aren't clear. Additionally, we need to
// specify SWP_NOZORDER here, otherwise if you have multiple chrome windows
// open they will re-appear with a non-deterministic Z-order.
+ // Note: caused http://crbug.com/895855, where a laptop lid close+reopen
+ // puts window in the background but acts like a foreground window. Fixed by
+ // not calling this unless DWM composition actually changes.
UINT flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_HIDEWINDOW);
SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_SHOWWINDOW);
@@ -3086,6 +3140,16 @@ void HWNDMessageHandler::PerformDwmTransition() {
EnumChildWindows(hwnd(), &SendDwmCompositionChanged, NULL);
}
+void HWNDMessageHandler::UpdateDwmFrame() {
+ gfx::Insets insets;
+ if (ui::win::IsAeroGlassEnabled() &&
+ delegate_->GetDwmFrameInsetsInPixels(&insets)) {
+ MARGINS margins = {insets.left(), insets.right(), insets.top(),
+ insets.bottom()};
+ DwmExtendFrameIntoClientArea(hwnd(), &margins);
+ }
+}
+
void HWNDMessageHandler::GenerateTouchEvent(ui::EventType event_type,
const gfx::Point& point,
size_t id,
diff --git a/chromium/ui/views/win/hwnd_message_handler.h b/chromium/ui/views/win/hwnd_message_handler.h
index 593c3c0e95b..c0f8d689ffd 100644
--- a/chromium/ui/views/win/hwnd_message_handler.h
+++ b/chromium/ui/views/win/hwnd_message_handler.h
@@ -355,6 +355,9 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
CR_MESSAGE_HANDLER_EX(WM_POINTERUPDATE, OnPointerEvent)
CR_MESSAGE_HANDLER_EX(WM_POINTERENTER, OnPointerEvent)
CR_MESSAGE_HANDLER_EX(WM_POINTERLEAVE, OnPointerEvent)
+ CR_MESSAGE_HANDLER_EX(WM_NCPOINTERDOWN, OnPointerEvent)
+ CR_MESSAGE_HANDLER_EX(WM_NCPOINTERUP, OnPointerEvent)
+ CR_MESSAGE_HANDLER_EX(WM_NCPOINTERUPDATE, OnPointerEvent)
// Key events.
CR_MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
@@ -517,13 +520,6 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
WPARAM w_param,
LPARAM l_param);
- LRESULT GenerateMouseEventFromPointerEvent(
- UINT message,
- UINT32 pointer_id,
- const POINTER_INFO& pointer_info,
- const gfx::Point& point,
- const ui::PointerDetails& pointer_details);
-
// Returns true if the mouse message passed in is an OS synthesized mouse
// message.
// |message| identifies the mouse message.
@@ -536,6 +532,9 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// Provides functionality to transition a frame to DWM.
void PerformDwmTransition();
+ // Updates DWM frame to extend into client area if needed.
+ void UpdateDwmFrame();
+
// Generates a touch event and adds it to the |touch_events| parameter.
// |point| is the point where the touch was initiated.
// |id| is the event id associated with the touch event.
@@ -694,6 +693,11 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// glass. Defaults to false.
bool dwm_transition_desired_;
+ // Is DWM composition currently enabled?
+ // Note: According to MSDN docs for DwmIsCompositionEnabled(), this is always
+ // true starting in Windows 8.
+ bool dwm_composition_enabled_;
+
// True if HandleWindowSizeChanging has been called in the delegate, but not
// HandleClientSizeChanged.
bool sent_window_size_changing_;
@@ -736,6 +740,13 @@ class VIEWS_EXPORT HWNDMessageHandler : public gfx::WindowImpl,
// report the scroll phase information or not.
bool precision_touchpad_scroll_phase_enabled_;
+ // True if DWM frame should be cleared on next WM_ERASEBKGND message. This is
+ // necessary to avoid white flashing in the titlebar area around the
+ // minimize/maximize/close buttons. Clearing the frame on every WM_ERASEBKGND
+ // message causes black flickering in the titlebar region so we do it on for
+ // the first message after frame type changes.
+ bool needs_dwm_frame_clear_ = true;
+
// This is a map of the HMONITOR to full screeen window instance. It is safe
// to keep a raw pointer to the HWNDMessageHandler instance as we track the
// window destruction and ensure that the map is cleaned up.
diff --git a/chromium/ui/views/win/hwnd_message_handler_delegate.h b/chromium/ui/views/win/hwnd_message_handler_delegate.h
index b3f670dddf8..690bc7aedd2 100644
--- a/chromium/ui/views/win/hwnd_message_handler_delegate.h
+++ b/chromium/ui/views/win/hwnd_message_handler_delegate.h
@@ -23,7 +23,6 @@ class Accelerator;
class InputMethod;
class KeyEvent;
class MouseEvent;
-class PointerEvent;
class ScrollEvent;
class TouchEvent;
}
@@ -95,6 +94,10 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
virtual bool GetClientAreaInsets(gfx::Insets* insets,
HMONITOR monitor) const = 0;
+ // Returns true if DWM frame should be extended into client area by |insets|.
+ // Insets are specified in screen pixels not DIP because that's what DWM uses.
+ virtual bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const = 0;
+
// Returns the minimum and maximum size the window can be resized to by the
// user.
virtual void GetMinMaxSize(gfx::Size* min_size,
@@ -193,10 +196,6 @@ class VIEWS_EXPORT HWNDMessageHandlerDelegate {
// handled by the delegate.
virtual bool HandleMouseEvent(ui::MouseEvent* event) = 0;
- // Called when a pointer event is received. Returns true if the event was
- // handled by the delegate.
- virtual bool HandlePointerEvent(ui::PointerEvent* event) = 0;
-
// Called when an untranslated key event is received (i.e. pre-IME
// translation).
virtual void HandleKeyEvent(ui::KeyEvent* event) = 0;
diff --git a/chromium/ui/views/win/pen_event_processor.cc b/chromium/ui/views/win/pen_event_processor.cc
index e1429935534..67ee69fc47e 100644
--- a/chromium/ui/views/win/pen_event_processor.cc
+++ b/chromium/ui/views/win/pen_event_processor.cc
@@ -48,7 +48,7 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateEvent(
DCHECK(!eraser_pointer_id_ || *eraser_pointer_id_ == mapped_pointer_id);
eraser_pointer_id_ = mapped_pointer_id;
} else if (eraser_pointer_id_ && *eraser_pointer_id_ == mapped_pointer_id &&
- message == WM_POINTERUP) {
+ (message == WM_POINTERUP || message == WM_NCPOINTERUP)) {
input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
eraser_pointer_id_.reset();
}
@@ -113,6 +113,7 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateMouseEvent(
int click_count = 0;
switch (message) {
case WM_POINTERDOWN:
+ case WM_NCPOINTERDOWN:
event_type = ui::ET_MOUSE_PRESSED;
if (pointer_info.ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_DOWN)
changed_flag = ui::EF_LEFT_MOUSE_BUTTON;
@@ -122,6 +123,7 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateMouseEvent(
sent_mouse_down_ = true;
break;
case WM_POINTERUP:
+ case WM_NCPOINTERUP:
event_type = ui::ET_MOUSE_RELEASED;
if (pointer_info.ButtonChangeType == POINTER_CHANGE_FIRSTBUTTON_UP) {
flag |= ui::EF_LEFT_MOUSE_BUTTON;
@@ -137,6 +139,7 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateMouseEvent(
sent_mouse_down_ = false;
break;
case WM_POINTERUPDATE:
+ case WM_NCPOINTERUPDATE:
event_type = ui::ET_MOUSE_DRAGGED;
if (flag == ui::EF_NONE)
event_type = ui::ET_MOUSE_MOVED;
@@ -169,10 +172,12 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateTouchEvent(
ui::EventType event_type = ui::ET_TOUCH_MOVED;
switch (message) {
case WM_POINTERDOWN:
+ case WM_NCPOINTERDOWN:
event_type = ui::ET_TOUCH_PRESSED;
sent_touch_start_ = true;
break;
case WM_POINTERUP:
+ case WM_NCPOINTERUP:
event_type = ui::ET_TOUCH_RELEASED;
id_generator_->ReleaseNumber(pointer_id);
if (!sent_touch_start_)
@@ -180,6 +185,7 @@ std::unique_ptr<ui::Event> PenEventProcessor::GenerateTouchEvent(
sent_touch_start_ = false;
break;
case WM_POINTERUPDATE:
+ case WM_NCPOINTERUPDATE:
event_type = ui::ET_TOUCH_MOVED;
break;
default:
diff --git a/chromium/ui/views/window/dialog_client_view.cc b/chromium/ui/views/window/dialog_client_view.cc
index 7c5c56f4c27..ec17425f17a 100644
--- a/chromium/ui/views/window/dialog_client_view.cc
+++ b/chromium/ui/views/window/dialog_client_view.cc
@@ -7,11 +7,9 @@
#include <algorithm>
#include "build/build_config.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
-#include "ui/views/controls/button/blue_button.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/image_button.h"
diff --git a/chromium/ui/views/window/dialog_delegate.cc b/chromium/ui/views/window/dialog_delegate.cc
index 806e809b824..4530b5535be 100644
--- a/chromium/ui/views/window/dialog_delegate.cc
+++ b/chromium/ui/views/window/dialog_delegate.cc
@@ -11,7 +11,6 @@
#include "build/build_config.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/color_palette.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/bubble/bubble_border.h"
diff --git a/chromium/ui/views/window/non_client_view.cc b/chromium/ui/views/window/non_client_view.cc
index cad54b2424a..eb874a063a8 100644
--- a/chromium/ui/views/window/non_client_view.cc
+++ b/chromium/ui/views/window/non_client_view.cc
@@ -43,7 +43,6 @@ bool NonClientFrameView::GetClientMask(const gfx::Size& size,
NonClientView::NonClientView()
: client_view_(nullptr),
- mirror_client_in_rtl_(true),
overlay_view_(nullptr) {
SetEventTargeter(
std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
@@ -166,10 +165,6 @@ void NonClientView::Layout() {
// Then layout the ClientView, using those bounds.
gfx::Rect client_bounds = frame_view_->GetBoundsForClientView();
- // RTL code will mirror the ClientView in the frame by default. If this isn't
- // desired, do a second mirror here to get the standard LTR position.
- if (base::i18n::IsRTL() && !mirror_client_in_rtl_)
- client_bounds.set_x(GetMirroredXForRect(client_bounds));
if (client_bounds != client_view_->bounds()) {
client_view_->SetBoundsRect(client_bounds);
diff --git a/chromium/ui/views/window/non_client_view.h b/chromium/ui/views/window/non_client_view.h
index 27cc19d8bad..8a11a2790bd 100644
--- a/chromium/ui/views/window/non_client_view.h
+++ b/chromium/ui/views/window/non_client_view.h
@@ -217,8 +217,6 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate {
client_view_ = client_view;
}
- void set_mirror_client_in_rtl(bool mirror) { mirror_client_in_rtl_ = mirror; }
-
// Layout just the frame view. This is necessary on Windows when non-client
// metrics such as the position of the window controls changes independently
// of a window resize message.
@@ -251,9 +249,6 @@ class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate {
// implementation.
ClientView* client_view_;
- // Set to false if client_view_ position shouldn't be mirrored in RTL.
- bool mirror_client_in_rtl_;
-
// The NonClientFrameView that renders the non-client portions of the window.
// This object is not owned by the view hierarchy because it can be replaced
// dynamically as the system settings change.
diff --git a/chromium/ui/views_bridge_mac/bridge_factory_impl.mm b/chromium/ui/views_bridge_mac/bridge_factory_impl.mm
index 323abef93cc..d4ba3ea4de8 100644
--- a/chromium/ui/views_bridge_mac/bridge_factory_impl.mm
+++ b/chromium/ui/views_bridge_mac/bridge_factory_impl.mm
@@ -6,6 +6,7 @@
#include "base/no_destructor.h"
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+#include "ui/base/cocoa/remote_accessibility_api.h"
#include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
@@ -36,10 +37,39 @@ class Bridge : public BridgedNativeWidgetHostHelper {
void OnConnectionError() { delete this; }
// BridgedNativeWidgetHostHelper:
- NSView* GetNativeViewAccessible() override { return nil; }
- void DispatchKeyEvent(ui::KeyEvent* event) override {}
+ id GetNativeViewAccessible() override {
+ if (!remote_accessibility_element_) {
+ int64_t browser_pid = 0;
+ std::vector<uint8_t> element_token;
+ host_ptr_->GetAccessibilityTokens(
+ ui::RemoteAccessibility::GetTokenForLocalElement(
+ bridge_impl_->ns_window()),
+ ui::RemoteAccessibility::GetTokenForLocalElement(
+ bridge_impl_->ns_view()),
+ &browser_pid, &element_token);
+ [NSAccessibilityRemoteUIElement
+ registerRemoteUIProcessIdentifier:browser_pid];
+ remote_accessibility_element_ =
+ ui::RemoteAccessibility::GetRemoteElementFromToken(element_token);
+ }
+ return remote_accessibility_element_.get();
+ }
+ void DispatchKeyEvent(ui::KeyEvent* event) override {
+ bool event_handled = false;
+ host_ptr_->DispatchKeyEventRemote(std::make_unique<ui::KeyEvent>(*event),
+ &event_handled);
+ if (event_handled)
+ event->SetHandled();
+ }
bool DispatchKeyEventToMenuController(ui::KeyEvent* event) override {
- return false;
+ bool event_swallowed = false;
+ bool event_handled = false;
+ host_ptr_->DispatchKeyEventToMenuControllerRemote(
+ std::make_unique<ui::KeyEvent>(*event), &event_swallowed,
+ &event_handled);
+ if (event_handled)
+ event->SetHandled();
+ return event_swallowed;
}
void GetWordAt(const gfx::Point& location_in_content,
bool* found_word,
@@ -55,6 +85,8 @@ class Bridge : public BridgedNativeWidgetHostHelper {
mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr_;
std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
+ base::scoped_nsobject<NSAccessibilityRemoteUIElement>
+ remote_accessibility_element_;
};
} // namespace
@@ -67,7 +99,8 @@ BridgeFactoryImpl* BridgeFactoryImpl::Get() {
void BridgeFactoryImpl::BindRequest(
mojom::BridgeFactoryAssociatedRequest request) {
- binding_.Bind(std::move(request));
+ binding_.Bind(std::move(request),
+ ui::WindowResizeHelperMac::Get()->task_runner());
}
void BridgeFactoryImpl::CreateBridgedNativeWidget(
diff --git a/chromium/ui/views_bridge_mac/bridged_content_view.h b/chromium/ui/views_bridge_mac/bridged_content_view.h
index eefdeafe1b3..b10f06bbb3b 100644
--- a/chromium/ui/views_bridge_mac/bridged_content_view.h
+++ b/chromium/ui/views_bridge_mac/bridged_content_view.h
@@ -66,8 +66,8 @@ VIEWS_EXPORT
@property(assign, nonatomic) BOOL drawMenuBackgroundForBlur;
// Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
-- (id)initWithBridge:(views::BridgedNativeWidgetImpl*)bridge
- bounds:(gfx::Rect)rect;
+- (instancetype)initWithBridge:(views::BridgedNativeWidgetImpl*)bridge
+ bounds:(gfx::Rect)rect;
// Clear the hosted view. For example, if it is about to be destroyed.
- (void)clearView;
diff --git a/chromium/ui/views_bridge_mac/bridged_content_view.mm b/chromium/ui/views_bridge_mac/bridged_content_view.mm
index ad444b08bd3..397425e8905 100644
--- a/chromium/ui/views_bridge_mac/bridged_content_view.mm
+++ b/chromium/ui/views_bridge_mac/bridged_content_view.mm
@@ -254,7 +254,7 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (void)insertTextInternal:(id)text;
// Returns the native Widget's drag drop client. Possibly null.
-- (views_bridge_mac::DragDropClient*)dragDropClient;
+- (views_bridge_mac::DragDropClient*)dragDropClient NS_RETURNS_INNER_POINTER;
// Menu action handlers.
- (void)undo:(id)sender;
@@ -273,8 +273,8 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
@synthesize textInputClient = textInputClient_;
@synthesize drawMenuBackgroundForBlur = drawMenuBackgroundForBlur_;
-- (id)initWithBridge:(views::BridgedNativeWidgetImpl*)bridge
- bounds:(gfx::Rect)bounds {
+- (instancetype)initWithBridge:(views::BridgedNativeWidgetImpl*)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());
@@ -713,14 +713,14 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
return NO;
BOOL result = [super becomeFirstResponder];
if (result && bridge_)
- bridge_->host()->SetIsFirstResponder(true);
+ bridge_->host()->OnIsFirstResponderChanged(true);
return result;
}
- (BOOL)resignFirstResponder {
BOOL result = [super resignFirstResponder];
if (result && bridge_)
- bridge_->host()->SetIsFirstResponder(false);
+ bridge_->host()->OnIsFirstResponderChanged(false);
return result;
}
@@ -753,7 +753,8 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
[super setFrameSize:newSize];
if (bridge_)
- bridge_->host()->SetViewSize(gfx::Size(newSize.width, newSize.height));
+ bridge_->host()->OnViewSizeChanged(
+ gfx::Size(newSize.width, newSize.height));
}
- (BOOL)isOpaque {
@@ -1597,7 +1598,8 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
- (id)accessibilityAttributeValue:(NSString*)attribute {
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- return @[ bridge_->host_helper()->GetNativeViewAccessible() ];
+ if (id accessible = bridge_->host_helper()->GetNativeViewAccessible())
+ return @[ accessible ];
}
return [super accessibilityAttributeValue:attribute];
@@ -1609,6 +1611,9 @@ ui::TextEditCommand GetTextEditCommandForMenuAction(SEL action) {
}
- (id)accessibilityFocusedUIElement {
+ // This function should almost-never be called because when |self| is the
+ // first responder for the key NSWindow, BridgedNativeWidgetHostImpl's
+ // AccessibilityFocusOverrider will override the accessibility focus query.
if (!bridge_)
return nil;
return [bridge_->host_helper()->GetNativeViewAccessible()
diff --git a/chromium/ui/views_bridge_mac/bridged_native_widget_host_helper.h b/chromium/ui/views_bridge_mac/bridged_native_widget_host_helper.h
index 4fe8218cc2a..4a7ec49d242 100644
--- a/chromium/ui/views_bridge_mac/bridged_native_widget_host_helper.h
+++ b/chromium/ui/views_bridge_mac/bridged_native_widget_host_helper.h
@@ -25,11 +25,8 @@ class VIEWS_BRIDGE_MAC_EXPORT BridgedNativeWidgetHostHelper {
public:
virtual ~BridgedNativeWidgetHostHelper() = 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;
+ // Retrieve the NSObject for accessibility for this widget.
+ virtual id GetNativeViewAccessible() = 0;
// Synchronously dispatch a key event. Note that this function will modify
// |event| based on whether or not it was handled.
diff --git a/chromium/ui/views_bridge_mac/bridged_native_widget_impl.h b/chromium/ui/views_bridge_mac/bridged_native_widget_impl.h
index acdb1997003..13d9a63b873 100644
--- a/chromium/ui/views_bridge_mac/bridged_native_widget_impl.h
+++ b/chromium/ui/views_bridge_mac/bridged_native_widget_impl.h
@@ -66,16 +66,12 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
static gfx::Size GetWindowSizeForClientSize(NSWindow* window,
const gfx::Size& size);
- // Retrieves the bridge associated with the given NSWindow. Returns null if
- // the supplied handle has no associated Widget.
- static BridgedNativeWidgetImpl* GetFromNativeWindow(NSWindow* window);
-
// Retrieve a BridgedNativeWidgetImpl* from its id.
static BridgedNativeWidgetImpl* GetFromId(uint64_t bridged_native_widget_id);
// Create an NSWindow for the specified parameters.
static base::scoped_nsobject<NativeWidgetMacNSWindow> CreateNSWindow(
- views_bridge_mac::mojom::CreateWindowParams* params);
+ const views_bridge_mac::mojom::CreateWindowParams* params);
// Creates one side of the bridge. |host| and |parent| must not be NULL.
BridgedNativeWidgetImpl(uint64_t bridged_native_widget_id,
@@ -169,13 +165,14 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
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);
-
// Whether to run a custom animation for the provided |transition|.
bool ShouldRunCustomAnimationFor(
views_bridge_mac::mojom::VisibilityTransition transition) const;
+ // Redispatch a keyboard event using the widget's window's CommandDispatcher.
+ // Return true if the event is handled.
+ bool RedispatchKeyEvent(NSEvent* event);
+
// display::DisplayObserver:
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) override;
@@ -203,6 +200,7 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
const gfx::Size& minimum_content_size) override;
void SetVisibilityState(
views_bridge_mac::mojom::WindowVisibilityState new_state) override;
+ void SetAnimationEnabled(bool animation_enabled) override;
void SetTransitionsToAnimate(
views_bridge_mac::mojom::VisibilityTransition transitions) override;
void SetVisibleOnAllSpaces(bool always_visible) override;
@@ -221,6 +219,12 @@ class VIEWS_EXPORT BridgedNativeWidgetImpl
void UpdateTooltip() override;
void AcquireCapture() override;
void ReleaseCapture() override;
+ void RedispatchKeyEvent(uint64_t type,
+ uint64_t modifier_flags,
+ double timestamp,
+ const base::string16& characters,
+ const base::string16& characters_ignoring_modifiers,
+ uint32_t key_code) override;
// TODO(ccameron): This method exists temporarily as we move all direct access
// of TextInputClient out of BridgedContentView.
diff --git a/chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm b/chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm
index 86b67f18fba..1f368c2fb23 100644
--- a/chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm
+++ b/chromium/ui/views_bridge_mac/bridged_native_widget_impl.mm
@@ -29,9 +29,11 @@
#import "ui/gfx/mac/nswindow_frame_controls.h"
#import "ui/views_bridge_mac/bridged_content_view.h"
#import "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
+#import "ui/views_bridge_mac/browser_native_widget_window_mac.h"
#import "ui/views_bridge_mac/cocoa_mouse_capture.h"
#import "ui/views_bridge_mac/cocoa_window_move_loop.h"
#include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
+#import "ui/views_bridge_mac/native_widget_mac_frameless_nswindow.h"
#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
#import "ui/views_bridge_mac/views_nswindow_delegate.h"
@@ -66,7 +68,7 @@ constexpr auto kUIPaintTimeout = base::TimeDelta::FromSeconds(5);
@implementation ViewsNSWindowCloseAnimator
-- (id)initWithWindow:(NSWindow*)window {
+- (instancetype)initWithWindow:(NSWindow*)window {
if ((self = [super init])) {
window_.reset([window retain]);
animation_.reset(
@@ -234,16 +236,6 @@ gfx::Size BridgedNativeWidgetImpl::GetWindowSizeForClientSize(
}
// static
-BridgedNativeWidgetImpl* BridgedNativeWidgetImpl::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
BridgedNativeWidgetImpl* BridgedNativeWidgetImpl::GetFromId(
uint64_t bridged_native_widget_id) {
auto found = GetIdToWidgetImplMap().find(bridged_native_widget_id);
@@ -255,14 +247,41 @@ BridgedNativeWidgetImpl* BridgedNativeWidgetImpl::GetFromId(
// static
base::scoped_nsobject<NativeWidgetMacNSWindow>
BridgedNativeWidgetImpl::CreateNSWindow(
- views_bridge_mac::mojom::CreateWindowParams* params) {
- base::scoped_nsobject<NativeWidgetMacNSWindow> result(
- [[NativeWidgetMacNSWindow alloc]
+ const views_bridge_mac::mojom::CreateWindowParams* params) {
+ base::scoped_nsobject<NativeWidgetMacNSWindow> ns_window;
+ switch (params->window_class) {
+ case views_bridge_mac::mojom::WindowClass::kDefault:
+ ns_window.reset([[NativeWidgetMacNSWindow alloc]
+ initWithContentRect:ui::kWindowSizeDeterminedLater
+ styleMask:params->style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ break;
+ case views_bridge_mac::mojom::WindowClass::kBrowser:
+ ns_window.reset([[BrowserNativeWidgetWindow alloc]
+ initWithContentRect:ui::kWindowSizeDeterminedLater
+ styleMask:params->style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ break;
+ case views_bridge_mac::mojom::WindowClass::kFrameless:
+ ns_window.reset([[NativeWidgetMacFramelessNSWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:params->style_mask
backing:NSBackingStoreBuffered
defer:NO]);
- return result;
+ break;
+ }
+ if (@available(macOS 10.10, *)) {
+ if (params->titlebar_appears_transparent)
+ [ns_window setTitlebarAppearsTransparent:YES];
+
+ if (params->window_title_hidden)
+ [ns_window setTitleVisibility:NSWindowTitleHidden];
+ }
+ if (params->animation_enabled)
+ [ns_window setAnimationBehavior:NSWindowAnimationBehaviorDocumentWindow];
+ return ns_window;
}
BridgedNativeWidgetImpl::BridgedNativeWidgetImpl(
@@ -301,6 +320,7 @@ void BridgedNativeWidgetImpl::SetWindow(
window_delegate_.reset(
[[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
window_ = std::move(window);
+ [window_ setBridgeImpl:this];
[window_ setBridgedNativeWidgetId:id_];
[window_ setReleasedWhenClosed:NO]; // Owned by scoped_nsobject.
[window_ setDelegate:window_delegate_];
@@ -683,8 +703,10 @@ bool BridgedNativeWidgetImpl::HasCapture() {
}
bool BridgedNativeWidgetImpl::RunMoveLoop(const gfx::Vector2d& drag_offset) {
- DCHECK(!HasCapture());
// https://crbug.com/876493
+ CHECK(!HasCapture());
+ // Does some *other* widget have capture?
+ CHECK(!CocoaMouseCapture::GetGlobalCaptureWindow());
CHECK(!window_move_loop_);
// RunMoveLoop caller is responsible for updating the window to be under the
@@ -741,6 +763,7 @@ void BridgedNativeWidgetImpl::OnWindowWillClose() {
DCHECK(!show_animation_);
[window_ setDelegate:nil];
+ [window_ setBridgeImpl:nullptr];
// Ensure that |this| cannot be reached by its id while it is being destroyed.
size_t erased = GetIdToWidgetImplMap().erase(id_);
@@ -991,6 +1014,15 @@ bool BridgedNativeWidgetImpl::ShouldRunCustomAnimationFor(
return true;
}
+bool BridgedNativeWidgetImpl::RedispatchKeyEvent(NSEvent* event) {
+ NSWindow* window = ns_window();
+ DCHECK([window.class conformsToProtocol:@protocol(CommandDispatchingWindow)]);
+ NSObject<CommandDispatchingWindow>* command_dispatching_window =
+ base::mac::ObjCCastStrict<NSObject<CommandDispatchingWindow>>(window);
+ return
+ [[command_dispatching_window commandDispatcher] redispatchKeyEvent:event];
+}
+
NSWindow* BridgedNativeWidgetImpl::ns_window() {
return window_.get();
}
@@ -1129,6 +1161,28 @@ void BridgedNativeWidgetImpl::SetTextInputClient(
[bridged_view_ setTextInputClient:text_input_client];
}
+void BridgedNativeWidgetImpl::RedispatchKeyEvent(
+ uint64_t type,
+ uint64_t modifier_flags,
+ double timestamp,
+ const base::string16& characters,
+ const base::string16& characters_ignoring_modifiers,
+ uint32_t key_code) {
+ NSEvent* event =
+ [NSEvent keyEventWithType:static_cast<NSEventType>(type)
+ location:NSZeroPoint
+ modifierFlags:modifier_flags
+ timestamp:timestamp
+ windowNumber:[window_ windowNumber]
+ context:nil
+ characters:base::SysUTF16ToNSString(characters)
+ charactersIgnoringModifiers:base::SysUTF16ToNSString(
+ characters_ignoring_modifiers)
+ isARepeat:NO
+ keyCode:key_code];
+ RedispatchKeyEvent(event);
+}
+
////////////////////////////////////////////////////////////////////////////////
// BridgedNativeWidgetImpl, former BridgedNativeWidgetOwner:
@@ -1233,7 +1287,7 @@ void BridgedNativeWidgetImpl::UpdateWindowGeometry() {
void BridgedNativeWidgetImpl::UpdateWindowDisplay() {
host_->OnWindowDisplayChanged(
- display::Screen::GetScreen()->GetDisplayNearestWindow(window_));
+ display::Screen::GetScreen()->GetDisplayNearestWindow(window_.get()));
}
bool BridgedNativeWidgetImpl::IsWindowModalSheet() const {
diff --git a/chromium/ui/views_bridge_mac/browser_native_widget_window_mac.h b/chromium/ui/views_bridge_mac/browser_native_widget_window_mac.h
new file mode 100644
index 00000000000..6b7004a96f1
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/browser_native_widget_window_mac.h
@@ -0,0 +1,13 @@
+// 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_BRIDGE_MAC_BROWSER_NATIVE_WIDGET_WINDOW_MAC_H_
+#define UI_VIEWS_BRIDGE_MAC_BROWSER_NATIVE_WIDGET_WINDOW_MAC_H_
+
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+
+@interface BrowserNativeWidgetWindow : NativeWidgetMacNSWindow
+@end
+
+#endif // UI_VIEWS_BRIDGE_MAC_BROWSER_NATIVE_WIDGET_WINDOW_MAC_H_
diff --git a/chromium/ui/views_bridge_mac/browser_native_widget_window_mac.mm b/chromium/ui/views_bridge_mac/browser_native_widget_window_mac.mm
new file mode 100644
index 00000000000..e391bf976bf
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/browser_native_widget_window_mac.mm
@@ -0,0 +1,99 @@
+// 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.
+
+#import "ui/views_bridge_mac/browser_native_widget_window_mac.h"
+
+#import <AppKit/AppKit.h>
+
+#include "ui/views_bridge_mac/bridged_native_widget_impl.h"
+#include "ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom.h"
+
+@interface NSWindow (PrivateBrowserNativeWidgetAPI)
++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle;
+@end
+
+@interface NSThemeFrame (PrivateBrowserNativeWidgetAPI)
+- (CGFloat)_titlebarHeight;
+- (void)setStyleMask:(NSUInteger)styleMask;
+@end
+
+@interface BrowserWindowFrame : NativeWidgetMacNSWindowTitledFrame
+@end
+
+@implementation BrowserWindowFrame {
+ BOOL _inFullScreen;
+}
+
+// NSThemeFrame overrides.
+
+- (CGFloat)_titlebarHeight {
+ bool overrideTitlebarHeight = false;
+ float titlebarHeight = 0;
+
+ if (!_inFullScreen) {
+ auto* window = base::mac::ObjCCast<NativeWidgetMacNSWindow>([self window]);
+ views::BridgedNativeWidgetImpl* bridgeImpl = [window bridgeImpl];
+ if (bridgeImpl) {
+ bridgeImpl->host()->GetWindowFrameTitlebarHeight(&overrideTitlebarHeight,
+ &titlebarHeight);
+ }
+ }
+ if (overrideTitlebarHeight)
+ return titlebarHeight;
+ return [super _titlebarHeight];
+}
+
+- (void)setStyleMask:(NSUInteger)styleMask {
+ _inFullScreen = (styleMask & NSWindowStyleMaskFullScreen) != 0;
+ [super setStyleMask:styleMask];
+}
+
+- (BOOL)_shouldCenterTrafficLights {
+ return YES;
+}
+
+// The base implementation justs tests [self class] == [NSThemeFrame class].
+- (BOOL)_shouldFlipTrafficLightsForRTL API_AVAILABLE(macos(10.12)) {
+ return [[self window] windowTitlebarLayoutDirection] ==
+ NSUserInterfaceLayoutDirectionRightToLeft;
+}
+
+// On 10.10, this prevents the window server from treating the title bar as an
+// unconditionally-draggable region, and allows -[BridgedContentView hitTest:]
+// to choose case-by-case whether to take a mouse event or let it turn into a
+// window drag. Not needed for newer macOS. See r549802 for details.
+- (NSRect)_draggableFrame NS_DEPRECATED_MAC(10_10, 10_11) {
+ return NSZeroRect;
+}
+
+@end
+
+@implementation BrowserNativeWidgetWindow
+
+// NSWindow (PrivateAPI) overrides.
+
++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
+ // - NSThemeFrame and its subclasses will be nil if it's missing at runtime.
+ if ([BrowserWindowFrame class])
+ return [BrowserWindowFrame class];
+ return [super frameViewClassForStyleMask:windowStyle];
+}
+
+// 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;
+}
+
+// Handle "Move focus to the window toolbar" configured in System Preferences ->
+// Keyboard -> Shortcuts -> Keyboard. Usually Ctrl+F5. The argument (|unknown|)
+// tends to just be nil.
+- (void)_handleFocusToolbarHotKey:(id)unknown {
+ views::BridgedNativeWidgetImpl* bridgeImpl = [self bridgeImpl];
+ if (bridgeImpl)
+ bridgeImpl->host()->OnFocusWindowToolbar();
+}
+
+@end
diff --git a/chromium/ui/views_bridge_mac/cocoa_window_move_loop.mm b/chromium/ui/views_bridge_mac/cocoa_window_move_loop.mm
index 4b2c64f0941..f35e625d206 100644
--- a/chromium/ui/views_bridge_mac/cocoa_window_move_loop.mm
+++ b/chromium/ui/views_bridge_mac/cocoa_window_move_loop.mm
@@ -28,7 +28,8 @@
@end
@implementation WeakCocoaWindowMoveLoop
-- (id)initWithWeakPtr:(const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
+- (instancetype)initWithWeakPtr:
+ (const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
if ((self = [super init])) {
weak_ = weak;
}
diff --git a/chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom b/chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom
index a256b186a6e..6a583e8f983 100644
--- a/chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom
+++ b/chromium/ui/views_bridge_mac/mojo/bridged_native_widget.mojom
@@ -9,11 +9,36 @@ import "ui/base/mojo/ui_base_types.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/mojo/ca_layer_params.mojom";
+// The window class (subclass of kNativeWidgetMacNSWindow) to use for a given
+// window.
+enum WindowClass {
+ // NativeWidgetMacNSWindow
+ kDefault,
+ // BrowserNativeWidgetWindow
+ kBrowser,
+ // NativeWidgetMacFramelessNSWindow
+ kFrameless,
+};
+
// Parameters used to described creation of an NSWindow.
-// TODO(ccameron): Add additional members to support all window sub-classes.
struct CreateWindowParams {
+ // The subclass of NativeWidgetMacNSWindow to use for this window.
+ WindowClass window_class;
+
// The NSWindowStyleMask for the window.
uint64 style_mask;
+
+ // Whether or not the titlebar should be forced to be transparent. If so, then
+ // the window is responsible for drawing its own titlebar. Note that the
+ // traffic lights will be drawn independent of this setting.
+ bool titlebar_appears_transparent;
+
+ // Whether or not to hide the default title drawn by the window. If so, then
+ // the window is responsible for drawing its own title.
+ bool window_title_hidden;
+
+ // Whether or not window animations should be initially enabled.
+ bool animation_enabled;
};
// Ways of changing the visibility of the bridged NSWindow.
@@ -110,6 +135,9 @@ interface BridgedNativeWidget {
// descendant windows where necessary.
SetVisibilityState(WindowVisibilityState new_state);
+ // Enables or disables all window animations.
+ SetAnimationEnabled(bool animation_enabled);
+
// Sets which transitions will animate. Currently this only affects non-native
// animations.
SetTransitionsToAnimate(VisibilityTransition transitions);
@@ -156,4 +184,17 @@ interface BridgedNativeWidget {
// CocoaMouseCaptureDelegate, then captures all mouse events until released.
AcquireCapture();
ReleaseCapture();
+
+ // Redispatch a keyboard event using the widget's window's CommandDispatcher.
+ // Note that the callers of this method use content::NativeWebKeyboardEvent,
+ // which would introduce a layering violation here. Specify explicitly as
+ // arguments only what is used in constructing the |os_event| member of
+ // content::NativeWebKeyboardEvent, to avoid this layering violation.
+ RedispatchKeyEvent(
+ uint64 type,
+ uint64 modifier_flags,
+ double timestamp,
+ mojo_base.mojom.String16 characters,
+ mojo_base.mojom.String16 characters_ignoring_modifiers,
+ uint32 key_code);
};
diff --git a/chromium/ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom b/chromium/ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom
index cba9a6b77eb..5f08a4554e8 100644
--- a/chromium/ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom
+++ b/chromium/ui/views_bridge_mac/mojo/bridged_native_widget_host.mojom
@@ -20,9 +20,10 @@ interface BridgedNativeWidgetHost {
// Called when the window's native theme changes.
OnWindowNativeThemeChanged();
- // Resize the underlying views::View to |new_size|. Note that this will not
- // necessarily match the content bounds from OnWindowGeometryChanged.
- SetViewSize(gfx.mojom.Size new_size);
+ // Resize the underlying views::View to |new_size| in response to the NSView's
+ // frame changing size. Note that this will not necessarily match the content
+ // bounds from OnWindowGeometryChanged.
+ OnViewSizeChanged(gfx.mojom.Size new_size);
// Indicate if full keyboard accessibility is needed and update focus if
// needed.
@@ -30,7 +31,7 @@ interface BridgedNativeWidgetHost {
// Indicate if the NSView for this widget is the first responder for the
// NSWindow for this widget.
- SetIsFirstResponder(bool is_first_responder);
+ OnIsFirstResponderChanged(bool is_first_responder);
// Indicate if mouse capture is active.
OnMouseCaptureActiveChanged(bool capture_is_active);
@@ -156,4 +157,22 @@ interface BridgedNativeWidgetHost {
// the key window (is active, in views terminology).
[Sync]
GetCanWindowClose() => (bool can_window_close);
+
+ // Synchronously query if the NSWindow's theme frame overrides the titlebar
+ // height, and, if so, what the overridden height is.
+ [Sync]
+ GetWindowFrameTitlebarHeight() => (bool override_titlebar_height,
+ float titlebar_height);
+
+ // Handle "Move focus to the window toolbar" shortcut.
+ OnFocusWindowToolbar();
+
+ // Return in |element_token| the token for the AX node for this view. Return
+ // the pid of the browser process to be registered as a remote UI process. Set
+ // the AX node for this view to have the element indicated by |window_token|
+ // as its window and the element indicated by |view_token| as its parent.
+ [Sync]
+ GetAccessibilityTokens(array<uint8> window_token,
+ array<uint8> view_token) =>
+ (int64 host_pid, array<uint8> element_token);
};
diff --git a/chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.h b/chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.h
new file mode 100644
index 00000000000..afe3482ef5e
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.h
@@ -0,0 +1,17 @@
+// 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_BRIDGE_MAC_NATIVE_WIDGET_MAC_FRAMELESS_NSWINDOW_H_
+#define UI_VIEWS_BRIDGE_MAC_NATIVE_WIDGET_MAC_FRAMELESS_NSWINDOW_H_
+
+#import "ui/views_bridge_mac/native_widget_mac_nswindow.h"
+
+// Overrides contentRect <-> frameRect conversion methods to keep them equal to
+// each other, even for windows that do not use NSBorderlessWindowMask. This
+// allows an NSWindow to be frameless without attaining undesired side-effects
+// of NSBorderlessWindowMask.
+@interface NativeWidgetMacFramelessNSWindow : NativeWidgetMacNSWindow
+@end
+
+#endif // UI_VIEWS_BRIDGE_MAC_NATIVE_WIDGET_MAC_FRAMELESS_NSWINDOW_H_
diff --git a/chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.mm b/chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.mm
new file mode 100644
index 00000000000..583003b9789
--- /dev/null
+++ b/chromium/ui/views_bridge_mac/native_widget_mac_frameless_nswindow.mm
@@ -0,0 +1,30 @@
+// 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_bridge_mac/native_widget_mac_frameless_nswindow.h"
+
+@interface NSWindow (PrivateAPI)
++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle;
+@end
+
+@interface NativeWidgetMacFramelessNSWindowFrame
+ : NativeWidgetMacNSWindowTitledFrame
+@end
+
+@implementation NativeWidgetMacFramelessNSWindowFrame
+- (CGFloat)_titlebarHeight {
+ return 0;
+}
+@end
+
+@implementation NativeWidgetMacFramelessNSWindow
+
++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
+ if ([NativeWidgetMacFramelessNSWindowFrame class]) {
+ return [NativeWidgetMacFramelessNSWindowFrame class];
+ }
+ return [super frameViewClassForStyleMask:windowStyle];
+}
+
+@end
diff --git a/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.h b/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.h
index ef8afe11aee..30b091bb60e 100644
--- a/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.h
+++ b/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.h
@@ -11,6 +11,10 @@
#include "ui/views/views_export.h"
#include "ui/views/widget/util_mac.h"
+namespace views {
+class BridgedNativeWidgetImpl;
+} // namespace views
+
@protocol WindowTouchBarDelegate;
// Weak lets Chrome launch even if a future macOS doesn't have the below classes
@@ -51,6 +55,9 @@ VIEWS_EXPORT
// may be used to look up the BridgedNativeWidgetHostImpl in the browser process
// or the BridgedNativeWidgetImpl in a display process.
@property(assign, nonatomic) uint64_t bridgedNativeWidgetId;
+
+// The BridgedNativeWidgetImpl that this will use to call back to the host.
+@property(assign, nonatomic) views::BridgedNativeWidgetImpl* bridgeImpl;
@end
#endif // UI_VIEWS_BRIDGE_MAC_NATIVE_WIDGET_MAC_NSWINDOW_H_
diff --git a/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm b/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm
index f0e7ac703ae..954ee2f0445 100644
--- a/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm
+++ b/chromium/ui/views_bridge_mac/native_widget_mac_nswindow.mm
@@ -32,9 +32,6 @@
// 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;
-
-// Retrieve the corresponding views::BridgedNativeWidgetImpl in this process.
-- (views::BridgedNativeWidgetImpl*)bridgeImpl;
@end
// Use this category to implement mouseDown: on multiple frame view classes
@@ -85,8 +82,10 @@
base::scoped_nsprotocol<id<UserInterfaceItemCommandHandler>> commandHandler_;
id<WindowTouchBarDelegate> touchBarDelegate_; // Weak.
uint64_t bridgedNativeWidgetId_;
+ views::BridgedNativeWidgetImpl* bridgeImpl_;
}
@synthesize bridgedNativeWidgetId = bridgedNativeWidgetId_;
+@synthesize bridgeImpl = bridgeImpl_;
- (instancetype)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)windowStyle
@@ -135,18 +134,16 @@
return base::mac::ObjCCastStrict<ViewsNSWindowDelegate>([self delegate]);
}
-- (views::BridgedNativeWidgetImpl*)bridgeImpl {
- return views::BridgedNativeWidgetImpl::GetFromId(bridgedNativeWidgetId_);
-}
-
- (BOOL)hasViewsMenuActive {
bool hasMenuController = false;
- [self bridgeImpl]->host()->GetHasMenuController(&hasMenuController);
+ if (bridgeImpl_)
+ bridgeImpl_->host()->GetHasMenuController(&hasMenuController);
return hasMenuController;
}
- (id)rootAccessibilityObject {
- return [self bridgeImpl]->host_helper()->GetNativeViewAccessible();
+ return bridgeImpl_ ? bridgeImpl_->host_helper()->GetNativeViewAccessible()
+ : nullptr;
}
// NSWindow overrides.
@@ -164,8 +161,8 @@
- (BOOL)_isTitleHidden {
bool shouldShowWindowTitle = YES;
- if ([self bridgeImpl])
- [self bridgeImpl]->host()->GetShouldShowWindowTitle(&shouldShowWindowTitle);
+ if (bridgeImpl_)
+ bridgeImpl_->host()->GetShouldShowWindowTitle(&shouldShowWindowTitle);
return !shouldShowWindowTitle;
}
@@ -182,32 +179,30 @@
// down, so check for a delegate.
- (BOOL)canBecomeKeyWindow {
bool canBecomeKey = NO;
- if ([self bridgeImpl])
- [self bridgeImpl]->host()->GetCanWindowBecomeKey(&canBecomeKey);
+ if (bridgeImpl_)
+ bridgeImpl_->host()->GetCanWindowBecomeKey(&canBecomeKey);
return canBecomeKey;
}
- (BOOL)canBecomeMainWindow {
- views::BridgedNativeWidgetImpl* bridgeImpl = [self bridgeImpl];
- if (!bridgeImpl)
+ if (!bridgeImpl_)
return NO;
// Dialogs and bubbles shouldn't take large shadows away from their parent.
- if (bridgeImpl->parent())
+ if (bridgeImpl_->parent())
return NO;
bool canBecomeKey = NO;
- if (bridgeImpl)
- bridgeImpl->host()->GetCanWindowBecomeKey(&canBecomeKey);
+ if (bridgeImpl_)
+ bridgeImpl_->host()->GetCanWindowBecomeKey(&canBecomeKey);
return canBecomeKey;
}
// Lets the traffic light buttons on the parent window keep their active state.
- (BOOL)hasKeyAppearance {
- views::BridgedNativeWidgetImpl* bridgeImpl = [self bridgeImpl];
- if (bridgeImpl) {
+ if (bridgeImpl_) {
bool isAlwaysRenderWindowAsKey = NO;
- bridgeImpl->host()->GetAlwaysRenderWindowAsKey(&isAlwaysRenderWindowAsKey);
+ bridgeImpl_->host()->GetAlwaysRenderWindowAsKey(&isAlwaysRenderWindowAsKey);
if (isAlwaysRenderWindowAsKey)
return YES;
}
@@ -328,11 +323,10 @@
// properties on the NSWindow and repeats them when focusing an item in the
// RootView's a11y group. See http://crbug.com/748221.
id superFocus = [super accessibilityFocusedUIElement];
- views::BridgedNativeWidgetImpl* bridgeImpl = [self bridgeImpl];
- if (!bridgeImpl || superFocus != self)
+ if (!bridgeImpl_ || superFocus != self)
return superFocus;
- return bridgeImpl->host_helper()->GetNativeViewAccessible();
+ return bridgeImpl_->host_helper()->GetNativeViewAccessible();
}
- (id)accessibilityAttributeValue:(NSString*)attribute {
diff --git a/chromium/ui/views_bridge_mac/views_nswindow_delegate.h b/chromium/ui/views_bridge_mac/views_nswindow_delegate.h
index bc9f33afddf..2ec72a05518 100644
--- a/chromium/ui/views_bridge_mac/views_nswindow_delegate.h
+++ b/chromium/ui/views_bridge_mac/views_nswindow_delegate.h
@@ -28,7 +28,8 @@ VIEWS_EXPORT
@property(retain, nonatomic) NSCursor* cursor;
// Initialize with the given |parent|.
-- (id)initWithBridgedNativeWidget:(views::BridgedNativeWidgetImpl*)parent;
+- (instancetype)initWithBridgedNativeWidget:
+ (views::BridgedNativeWidgetImpl*)parent;
// Notify that the window has been reordered in (or removed from) the window
// server's screen list. This is a substitute for -[NSWindowDelegate
diff --git a/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm b/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm
index ca77131d78f..7d1fbfa9925 100644
--- a/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm
+++ b/chromium/ui/views_bridge_mac/views_nswindow_delegate.mm
@@ -14,7 +14,8 @@
@implementation ViewsNSWindowDelegate
-- (id)initWithBridgedNativeWidget:(views::BridgedNativeWidgetImpl*)parent {
+- (instancetype)initWithBridgedNativeWidget:
+ (views::BridgedNativeWidgetImpl*)parent {
DCHECK(parent);
if ((self = [super init])) {
parent_ = parent;
diff --git a/chromium/ui/views_bridge_mac/views_scrollbar_bridge.h b/chromium/ui/views_bridge_mac/views_scrollbar_bridge.h
index 7b5809eba8f..a194dc539b0 100644
--- a/chromium/ui/views_bridge_mac/views_scrollbar_bridge.h
+++ b/chromium/ui/views_bridge_mac/views_scrollbar_bridge.h
@@ -27,7 +27,7 @@ class ViewsScrollbarBridgeDelegate {
// Initializes with the given delegate and registers for notifications on
// scroller style changes.
-- (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate;
+- (instancetype)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate;
// Sets |delegate_| to nullptr.
- (void)clearDelegate;
diff --git a/chromium/ui/views_bridge_mac/views_scrollbar_bridge.mm b/chromium/ui/views_bridge_mac/views_scrollbar_bridge.mm
index c720483d4fe..2e7eea34169 100644
--- a/chromium/ui/views_bridge_mac/views_scrollbar_bridge.mm
+++ b/chromium/ui/views_bridge_mac/views_scrollbar_bridge.mm
@@ -15,7 +15,7 @@
@implementation ViewsScrollbarBridge
-- (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate {
+- (instancetype)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate {
if ((self = [super init])) {
delegate_ = delegate;
[[NSNotificationCenter defaultCenter]
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts.cc b/chromium/ui/views_content_client/views_content_client_main_parts.cc
index 5a5abb34842..6b180f98d8b 100644
--- a/chromium/ui/views_content_client/views_content_client_main_parts.cc
+++ b/chromium/ui/views_content_client/views_content_client_main_parts.cc
@@ -36,6 +36,8 @@ void ViewsContentClientMainParts::PreMainMessageLoopRun() {
test_views_delegate->set_context_factory_private(
content::GetContextFactoryPrivate());
views_delegate_ = std::move(test_views_delegate);
+ run_loop_ = std::make_unique<base::RunLoop>();
+ views_content_client()->set_quit_closure(run_loop_->QuitClosure());
}
void ViewsContentClientMainParts::PostMainMessageLoopRun() {
@@ -44,9 +46,7 @@ void ViewsContentClientMainParts::PostMainMessageLoopRun() {
}
bool ViewsContentClientMainParts::MainMessageLoopRun(int* result_code) {
- base::RunLoop run_loop;
- views_content_client_->set_quit_closure(run_loop.QuitClosure());
- run_loop.Run();
+ run_loop_->Run();
return true;
}
diff --git a/chromium/ui/views_content_client/views_content_client_main_parts.h b/chromium/ui/views_content_client/views_content_client_main_parts.h
index c0f73a06e04..fec1081d4fc 100644
--- a/chromium/ui/views_content_client/views_content_client_main_parts.h
+++ b/chromium/ui/views_content_client/views_content_client_main_parts.h
@@ -10,6 +10,10 @@
#include "base/macros.h"
#include "content/public/browser/browser_main_parts.h"
+namespace base {
+class RunLoop;
+}
+
namespace content {
class ShellBrowserContext;
struct MainFunctionParams;
@@ -57,6 +61,8 @@ class ViewsContentClientMainParts : public content::BrowserMainParts {
ViewsContentClient* views_content_client_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+
DISALLOW_COPY_AND_ASSIGN(ViewsContentClientMainParts);
};
diff --git a/chromium/ui/webui/PLATFORM_OWNERS b/chromium/ui/webui/PLATFORM_OWNERS
index a93051bd3f8..ccd7fa3a048 100644
--- a/chromium/ui/webui/PLATFORM_OWNERS
+++ b/chromium/ui/webui/PLATFORM_OWNERS
@@ -1,5 +1,6 @@
# Please use more specific OWNERS when possible.
calamity@chromium.org
+dbeam@chromium.org
dpapad@chromium.org
dschuyler@chromium.org
michaelpg@chromium.org
diff --git a/chromium/ui/webui/mojo_web_ui_controller.cc b/chromium/ui/webui/mojo_web_ui_controller.cc
index 769e194449c..49316482f33 100644
--- a/chromium/ui/webui/mojo_web_ui_controller.cc
+++ b/chromium/ui/webui/mojo_web_ui_controller.cc
@@ -24,11 +24,8 @@ void MojoWebUIController::OnInterfaceRequestFromFrame(
content::RenderFrameHost* render_frame_host,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe) {
- if (!registry_.CanBindInterface(interface_name)) {
- LOG(WARNING) << "Cannot bind request to " << interface_name << "; ignoring "
- << "request.";
+ if (!registry_.CanBindInterface(interface_name))
return;
- }
// Right now, this is expected to be called only for main frames.
if (render_frame_host->GetParent()) {
diff --git a/chromium/ui/webui/resources/PRESUBMIT.py b/chromium/ui/webui/resources/PRESUBMIT.py
index d1933521c36..5252e6b819e 100644
--- a/chromium/ui/webui/resources/PRESUBMIT.py
+++ b/chromium/ui/webui/resources/PRESUBMIT.py
@@ -61,8 +61,7 @@ def _CommonChecks(input_api, output_api):
cwd = input_api.PresubmitLocalPath()
sys.path += [input_api.os_path.join(cwd, '..', '..', '..', 'tools')]
from web_dev_style import presubmit_support
- BLACKLIST = ['ui/webui/resources/js/analytics.js',
- 'ui/webui/resources/js/jstemplate_compiled.js']
+ BLACKLIST = ['ui/webui/resources/js/jstemplate_compiled.js']
file_filter = lambda f: f.LocalPath() not in BLACKLIST
results += presubmit_support.CheckStyle(input_api, output_api, file_filter)
finally:
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/.eslintrc.js b/chromium/ui/webui/resources/cr_components/.eslintrc.js
index 25e21f992eb..25e21f992eb 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/.eslintrc.js
+++ b/chromium/ui/webui/resources/cr_components/.eslintrc.js
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html
index 73d8209664f..6e41d2c0e1d 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_delete_confirmation_dialog.html
@@ -1,6 +1,7 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="certificate_shared_css.html">
@@ -8,7 +9,7 @@
<dom-module id="certificate-delete-confirmation-dialog">
<template>
- <style include="certificate-shared"></style>
+ <style include="certificate-shared paper-button-style"></style>
<cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">
[[getTitleText_(model, certificateType)]]
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html
index f5dedd662cb..b559ee76fdf 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_decryption_dialog.html
@@ -2,6 +2,7 @@
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="certificate_shared_css.html">
@@ -9,7 +10,7 @@
<dom-module id="certificate-password-decryption-dialog">
<template>
- <style include="certificate-shared">
+ <style include="certificate-shared paper-button-style">
cr-input {
--cr-input-error-display: none;
}
@@ -21,7 +22,7 @@
<div slot="body">
<cr-input type="password" id="password"
label="[[i18n('certificateManagerPassword')]]"
- value="{{password_}}">
+ value="{{password_}}" autofocus>
</cr-input>
</div>
<div slot="button-container">
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html
index 6541eeaadc5..c971f287553 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_password_encryption_dialog.html
@@ -2,6 +2,7 @@
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
@@ -10,7 +11,7 @@
<dom-module id="certificate-password-encryption-dialog">
<template>
- <style include="certificate-shared">
+ <style include="certificate-shared paper-button-style">
cr-input {
--cr-input-error-display: none;
margin-top: var(--cr-form-field-bottom-spacing);
@@ -29,7 +30,7 @@
<div class="password-buttons">
<cr-input type="password" value="{{password_}}" id="password"
label="[[i18n('certificateManagerPassword')]]"
- on-input="validate_"></cr-input>
+ on-input="validate_" autofocus></cr-input>
<cr-input type="password"
value="{{confirmPassword_}}" id="confirmPassword"
label="[[i18n('certificateManagerConfirmPassword')]]"
diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html
index ae1d5c587a9..0ef4dc1b48b 100644
--- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html
+++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificates_error_dialog.html
@@ -1,13 +1,14 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<link rel="import" href="certificate_shared_css.html">
<dom-module id="certificates-error-dialog">
<template>
- <style include="certificate-shared"></style>
+ <style include="certificate-shared paper-button-style"></style>
<cr-dialog id="dialog" close-text="[[i18n('close')]]">
<div slot="title">[[model.title]]</div>
<div slot="body">
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
index a75218ee419..660f1ac657f 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
@@ -33,7 +33,7 @@
}
</style>
<iron-pages attr-for-selected="is"
- selected="[[visiblePageName_]]"
+ selected="[[visiblePageName]]"
selected-item="{{visiblePage_}}">
<template is="dom-if" if="[[shouldPasswordPageBeIncluded_(delegate)]]"
restamp>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
index 3dc0dd457d8..9be02cb2a60 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
@@ -41,7 +41,7 @@ cr.define('multidevice_setup', function() {
forwardButtonDisabled: {
type: Boolean,
computed: 'shouldForwardButtonBeDisabled_(' +
- 'passwordPageForwardButtonDisabled_, visiblePageName_)',
+ 'passwordPageForwardButtonDisabled_, visiblePageName)',
notify: true
},
@@ -68,12 +68,12 @@ cr.define('multidevice_setup', function() {
/**
* Element name of the currently visible page.
*
- * @private {!multidevice_setup.PageName}
+ * @type {!multidevice_setup.PageName}
*/
- visiblePageName_: {
+ visiblePageName: {
type: String,
value: PageName.START,
- notify: true, // For testing purposes only.
+ notify: true,
},
/**
@@ -161,16 +161,16 @@ cr.define('multidevice_setup', function() {
/** @private */
onCancelRequested_: function() {
- this.exitSetupFlow_();
+ this.exitSetupFlow_(false /* didUserCompleteSetup */);
},
/** @private */
onBackwardNavigationRequested_: function() {
// The back button is only visible on the password page.
- assert(this.visiblePageName_ == PageName.PASSWORD);
+ assert(this.visiblePageName == PageName.PASSWORD);
this.$$('password-page').clearPasswordTextInput();
- this.visiblePageName_ = PageName.START;
+ this.visiblePageName = PageName.START;
},
/** @private */
@@ -187,20 +187,20 @@ cr.define('multidevice_setup', function() {
/** @private */
navigateForward_: function() {
- switch (this.visiblePageName_) {
+ switch (this.visiblePageName) {
case PageName.FAILURE:
- this.visiblePageName_ = PageName.START;
+ this.visiblePageName = PageName.START;
return;
case PageName.PASSWORD:
this.$$('password-page').clearPasswordTextInput();
this.setHostDevice_();
return;
case PageName.SUCCESS:
- this.exitSetupFlow_();
+ this.exitSetupFlow_(true /* didUserCompleteSetup */);
return;
case PageName.START:
if (this.delegate.isPasswordRequiredToSetHost())
- this.visiblePageName_ = PageName.PASSWORD;
+ this.visiblePageName = PageName.PASSWORD;
else
this.setHostDevice_();
return;
@@ -221,11 +221,11 @@ cr.define('multidevice_setup', function() {
}
if (this.delegate.shouldExitSetupFlowAfterSettingHost()) {
- this.exitSetupFlow_();
+ this.exitSetupFlow_(true /* didUserCompleteSetup */);
return;
}
- this.visiblePageName_ = PageName.SUCCESS;
+ this.visiblePageName = PageName.SUCCESS;
this.fire('forward-button-focus-requested');
})
.catch((error) => {
@@ -254,7 +254,7 @@ cr.define('multidevice_setup', function() {
* @private
*/
shouldForwardButtonBeDisabled_: function() {
- return (this.visiblePageName_ == PageName.PASSWORD) &&
+ return (this.visiblePageName == PageName.PASSWORD) &&
this.passwordPageForwardButtonDisabled_;
},
@@ -298,11 +298,11 @@ cr.define('multidevice_setup', function() {
/**
* Notifies observers that the setup flow has completed.
- *
+ * @param {boolean} didUserCompleteSetup
* @private
*/
- exitSetupFlow_: function() {
- this.fire('setup-exited');
+ exitSetupFlow_: function(didUserCompleteSetup) {
+ this.fire('setup-exited', {didUserCompleteSetup: didUserCompleteSetup});
},
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
index ae1eab83c96..484f8a8f537 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn
@@ -9,7 +9,9 @@ js_type_check("closure_compile") {
":network_apnlist",
":network_choose_mobile",
":network_config",
+ ":network_config_input",
":network_config_select",
+ ":network_config_toggle",
":network_ip_config",
":network_nameservers",
":network_password_input",
@@ -48,8 +50,25 @@ js_library("network_config") {
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
}
+js_library("network_config_element_behavior") {
+ deps = [
+ "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
+ ]
+}
+
+js_library("network_config_input") {
+ deps = [
+ ":network_config_element_behavior",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
+}
+
js_library("network_config_select") {
deps = [
+ ":network_config_element_behavior",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior",
]
@@ -57,6 +76,15 @@ js_library("network_config_select") {
extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
}
+js_library("network_config_toggle") {
+ deps = [
+ ":network_config_element_behavior",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+ ]
+ externs_list = [ "$externs_path/networking_private.js" ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
+}
+
js_library("network_ip_config") {
deps = [
"//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
@@ -73,8 +101,12 @@ js_library("network_nameservers") {
js_library("network_password_input") {
deps = [
+ ":network_config_element_behavior",
+ "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
"//ui/webui/resources/js:i18n_behavior",
]
+ externs_list = [ "$externs_path/networking_private.js" ]
+ extra_sources = [ "$interfaces_path/networking_private_interface.js" ]
}
js_library("network_property_list") {
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js
index eb882f59f78..538ab5b2865 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js
@@ -91,13 +91,13 @@ Polymer({
if (!this.networkProperties || !this.networkProperties.Cellular)
return;
- /** @type {!CrOnc.APNProperties|undefined} */ var activeApn;
- var cellular = this.networkProperties.Cellular;
- /** @type {!chrome.networkingPrivate.ManagedAPNProperties|undefined} */ var
- apn = cellular.APN;
+ /** @type {!CrOnc.APNProperties|undefined} */ let activeApn;
+ const cellular = this.networkProperties.Cellular;
+ /** @type {!chrome.networkingPrivate.ManagedAPNProperties|undefined} */
+ const apn = cellular.APN;
if (apn && apn.AccessPointName) {
activeApn = /** @type {!CrOnc.APNProperties|undefined} */ (
- CrOnc.getSimpleActiveProperties(apn));
+ CrOnc.getActiveProperties(apn));
} else if (cellular.LastGoodAPN && cellular.LastGoodAPN.AccessPointName) {
activeApn = cellular.LastGoodAPN;
}
@@ -113,18 +113,18 @@ Polymer({
*/
setApnSelectList_: function(activeApn) {
// Copy the list of APNs from this.networkProperties.
- var result = this.getApnList_().slice();
+ const result = this.getApnList_().slice();
// Test whether |activeApn| is in the current APN list in networkProperties.
- var activeApnInList = activeApn && result.some(function(a) {
+ const activeApnInList = activeApn && result.some(function(a) {
return a.AccessPointName == activeApn.AccessPointName;
});
// If |activeApn| is specified and not in the list, use the active
// properties for 'other'. Otherwise use any existing 'other' properties.
- var otherApnProperties =
+ const otherApnProperties =
(activeApn && !activeApnInList) ? activeApn : this.otherApn_;
- var otherApn = this.createApnObject_(otherApnProperties);
+ const otherApn = this.createApnObject_(otherApnProperties);
// Always use 'Other' for the name of custom APN entries (the name does
// not get saved).
@@ -155,7 +155,7 @@ Polymer({
* @private
*/
createApnObject_: function(apnProperties) {
- var newApn = {AccessPointName: ''};
+ const newApn = {AccessPointName: ''};
if (apnProperties)
Object.assign(newApn, apnProperties);
return newApn;
@@ -169,8 +169,8 @@ Polymer({
getApnList_: function() {
if (!this.networkProperties || !this.networkProperties.Cellular)
return [];
- /** @type {!chrome.networkingPrivate.ManagedAPNList|undefined} */ var
- apnlist = this.networkProperties.Cellular.APNList;
+ /** @type {!chrome.networkingPrivate.ManagedAPNList|undefined} */
+ const apnlist = this.networkProperties.Cellular.APNList;
if (!apnlist)
return [];
return /** @type {!Array<!CrOnc.APNProperties>} */ (
@@ -183,8 +183,8 @@ Polymer({
* @private
*/
onSelectApnChange_: function(event) {
- var target = /** @type {!HTMLSelectElement} */ (event.target);
- var accessPointName = target.value;
+ const target = /** @type {!HTMLSelectElement} */ (event.target);
+ const accessPointName = target.value;
// When selecting 'Other', don't set a change event unless a valid
// non-default value has been set for Other.
if (this.isOtherSelected_(accessPointName) &&
@@ -204,7 +204,7 @@ Polymer({
onOtherApnChange_: function(event) {
// TODO(benchan/stevenjb): Move this to shill or
// onc_translator_onc_to_shill.cc.
- var value = (event.detail.field == 'AccessPointName') ?
+ const value = (event.detail.field == 'AccessPointName') ?
event.detail.value.toUpperCase() :
event.detail.value;
this.set('otherApn_.' + event.detail.field, value);
@@ -226,8 +226,8 @@ Polymer({
* @private
*/
sendApnChange_: function(accessPointName) {
- var apnList = this.getApnList_();
- var apn = this.findApnInList(apnList, accessPointName);
+ const apnList = this.getApnList_();
+ let apn = this.findApnInList(apnList, accessPointName);
if (apn == undefined) {
apn = this.createApnObject_();
if (this.otherApn_) {
@@ -247,8 +247,8 @@ Polymer({
isOtherSelected_: function(accessPointName) {
if (!this.networkProperties || !this.networkProperties.Cellular)
return false;
- var apnList = this.getApnList_();
- var apn = this.findApnInList(apnList, accessPointName);
+ const apnList = this.getApnList_();
+ const apn = this.findApnInList(apnList, accessPointName);
return apn == undefined;
},
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_choose_mobile.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_choose_mobile.js
index b5b50b12fb1..b6126963195 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_choose_mobile.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_choose_mobile.js
@@ -66,13 +66,13 @@ Polymer({
networkPropertiesChanged_: function() {
if (!this.networkProperties || !this.networkProperties.Cellular)
return;
- var cellular = this.networkProperties.Cellular;
+ const cellular = this.networkProperties.Cellular;
this.mobileNetworkList_ = cellular.FoundNetworks ||
[{NetworkId: 'none', LongName: this.i18n('networkCellularNoNetworks')}];
// Set selectedMobileNetworkId_ after the dom-repeat has been stamped.
this.async(() => {
- var selected = this.mobileNetworkList_.find(function(mobileNetwork) {
+ let selected = this.mobileNetworkList_.find(function(mobileNetwork) {
return mobileNetwork.Status == 'current';
});
if (!selected)
@@ -110,7 +110,7 @@ Polymer({
properties.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED) {
return false;
}
- var found = this.get('Cellular.FoundNetworks', properties);
+ const found = this.get('Cellular.FoundNetworks', properties);
return !!found && found.length > 0;
},
@@ -122,7 +122,7 @@ Polymer({
getSecondaryText_: function(properties) {
if (!properties || !properties.Cellular)
return '';
- var cellular = properties.Cellular;
+ const cellular = properties.Cellular;
if (cellular.Scanning)
return this.i18n('networkCellularScanning');
else if (this.scanRequested_)
@@ -157,7 +157,7 @@ Polymer({
* @private
*/
onChange_: function(event) {
- var target = /** @type {!HTMLSelectElement} */ (event.target);
+ const target = /** @type {!HTMLSelectElement} */ (event.target);
if (!target.value || target.value == 'none')
return;
this.networkingPrivate.selectCellularMobileNetwork(
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html
index f6053ce9367..aea5e4d05ac 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -1,13 +1,14 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="network_shared_css.html">
-<link rel="import" href="network_password_input.html">
+<link rel="import" href="network_config_input.html">
<link rel="import" href="network_config_select.html">
+<link rel="import" href="network_config_toggle.html">
+<link rel="import" href="network_password_input.html">
+<link rel="import" href="network_shared_css.html">
<dom-module id="network-config">
<template>
@@ -16,9 +17,9 @@
<!-- SSID (WiFi) -->
<template is="dom-if" if="[[isType_(NetworkType_.WI_FI, type)]]" restamp>
- <cr-input id="ssid" label="[[i18n('OncWiFi-SSID')]]"
+ <network-config-input id="ssid" label="[[i18n('OncWiFi-SSID')]]"
value="{{configProperties_.WiFi.SSID}}" readonly="[[hasGuid_(guid)]]">
- </cr-input>
+ </network-config-input>
</template>
<!-- Security (WiFi and Ethernet) -->
@@ -27,7 +28,8 @@
value="{{security_}}"
disabled="[[!securityIsEnabled_(guid, type)]]"
items="[[getSecurityItems_(type)]]"
- onc-prefix="WiFi.Security">
+ onc-prefix="WiFi.Security"
+ property="[[getManagedSecurity_(managedProperties)]]">
</network-config-select>
</template>
@@ -36,119 +38,130 @@
restamp>
<network-password-input label="[[i18n('OncWiFi-Passphrase')]]"
value="{{configProperties_.WiFi.Passphrase}}"
- on-enter="connectIfConfigured_">
+ on-enter="connectIfConfigured_"
+ property="[[managedProperties.WiFi.Passphrase]]">
</network-password-input>
</template>
<!-- VPN -->
<template is="dom-if" if="[[showVpn_]]" restamp>
- <cr-input label="[[i18n('OncVPN-Host')]]"
- value="{{configProperties_.VPN.Host}}">
- </cr-input>
- <cr-input label="[[i18n('OncName')]]"
- value="{{configProperties_.Name}}" readonly="[[hasGuid_(guid)]]">
- </cr-input>
+ <network-config-input label="[[i18n('OncVPN-Host')]]"
+ value="{{configProperties_.VPN.Host}}"
+ property="[[managedProperties.VPN.Host]]">
+ </network-config-input>
+ <network-config-input label="[[i18n('OncName')]]"
+ value="{{configProperties_.Name}}"
+ readonly="[[hasGuid_(guid)]]">
+ </network-config-input>
<network-config-select id="outer" label="[[i18n('OncVPN-Type')]]"
value="{{vpnType_}}" items="[[vpnTypeItems_]]"
- onc-prefix="VPN.Type" disabled="[[hasGuid_(guid)]]">
+ onc-prefix="VPN.Type" disabled="[[hasGuid_(guid)]]"
+ property="[[managedProperties.VPN.Type]]">
</network-config-select>
<template is="dom-if" if="[[!showVpn_.OpenVPN]]">
- <cr-input label="[[i18n('OncVPN-L2TP-Username')]]"
- value="{{configProperties_.VPN.L2TP.Username}}">
- </cr-input>
+ <network-config-input label="[[i18n('OncVPN-L2TP-Username')]]"
+ value="{{configProperties_.VPN.L2TP.Username}}"
+ property="[[managedProperties.VPN.L2TP.Username]]">
+ </network-config-input>
<network-password-input label="[[i18n('OncVPN-L2TP-Password')]]"
- value="{{configProperties_.VPN.L2TP.Password}}">
+ value="{{configProperties_.VPN.L2TP.Password}}"
+ property="[[managedProperties.VPN.L2TP.Password]]">
</network-password-input>
- <cr-input label="[[i18n('OncVPN-IPsec-Group')]]"
- value="{{configProperties_.VPN.IPsec.Group}}">
- </cr-input>
+ <network-config-input label="[[i18n('OncVPN-IPsec-Group')]]"
+ value="{{configProperties_.VPN.IPsec.Group}}"
+ property="[[managedProperties.VPN.IPsec.Group]]">
+ </network-config-input>
<template is="dom-if" if="[[!showVpn_.Cert]]">
<network-password-input label="[[i18n('OncVPN-IPsec-PSK')]]"
value="{{configProperties_.VPN.IPsec.PSK}}"
- on-focus="onPskFocus_" on-blur="onPskBlur_"
- on-input="onPskInput_">
+ property="[[managedProperties.VPN.IPsec.PSK]]">
</network-password-input>
</template>
</template>
<template is="dom-if" if="[[showVpn_.OpenVPN]]">
- <cr-input label="[[i18n('OncVPN-OpenVPN-Username')]]"
- value="{{configProperties_.VPN.OpenVPN.Username}}">
- </cr-input>
+ <network-config-input label="[[i18n('OncVPN-OpenVPN-Username')]]"
+ value="{{configProperties_.VPN.OpenVPN.Username}}"
+ property="[[managedProperties.VPN.OpenVPN.Username]]">
+ </network-config-input>
<network-password-input label="[[i18n('OncVPN-OpenVPN-Password')]]"
- value="{{configProperties_.VPN.OpenVPN.Password}}">
+ value="{{configProperties_.VPN.OpenVPN.Password}}"
+ property="[[managedProperties.VPN.OpenVPN.Password]]">
</network-password-input>
- <cr-input label="[[i18n('OncVPN-OpenVPN-OTP')]]"
- value="{{configProperties_.VPN.OpenVPN.OTP}}">
- </cr-input>
+ <network-config-input label="[[i18n('OncVPN-OpenVPN-OTP')]]"
+ value="{{configProperties_.VPN.OpenVPN.OTP}}"
+ property="[[managedProperties.VPN.OpenVPN.OTP]]">
+ </network-config-input>
</template>
<template is="dom-if" if="[[showVpn_.Cert]]">
<network-config-select id="vpnServerCa"
label="[[i18n('OncEAP-ServerCA')]]"
value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]"
- cert-list>
+ cert-list
+ property="[[getManagedVpnServerCaRefs_(managedProperties)]]">
</network-config-select>
<network-config-select id="vpnUserCert"
label="[[i18n('OncEAP-UserCert')]]"
value="{{selectedUserCertHash_}}" items="[[userCerts_]]"
- cert-list>
+ cert-list
+ property="[[getManagedVpnClientCertType_(managedProperties)]]">
</network-config-select>
</template>
- <div class="property-box">
- <div id="vpnSaveCredentialsLabel" class="start">
- [[i18n('networkConfigSaveCredentials')]]
- </div>
- <cr-toggle checked="{{vpnSaveCredentials_}}"
- aria-labelledby="vpnSaveCredentialsLabel">
- </cr-toggle>
- </div>
+ <network-config-toggle label="[[i18n('networkConfigSaveCredentials')]]"
+ checked="{{vpnSaveCredentials_}}"
+ property="[[getManagedVpnSaveCredentials_(managedProperties)]]">
+ </network-config-toggle>
</template>
<!-- EAP (WiFi, WiMAX, Ethernet) -->
<template is="dom-if" if="[[showEap_]]" restamp>
<network-config-select id="outer" label="[[i18n('OncEAP-Outer')]]"
value="{{eapProperties_.Outer}}" items="[[eapOuterItems_]]"
- onc-prefix="EAP.Outer" hidden="[[!showEap_.Outer]]">
+ onc-prefix="EAP.Outer" hidden="[[!showEap_.Outer]]"
+ property="[[managedEapProperties_.Outer]]">
</network-config-select>
<network-config-select id="inner" label="[[i18n('OncEAP-Inner')]]"
value="{{eapProperties_.Inner}}"
items="[[getEapInnerItems_(eapProperties_.Outer)]]"
- onc-prefix="EAP.Inner" hidden="[[!showEap_.Inner]]">
+ onc-prefix="EAP.Inner" hidden="[[!showEap_.Inner]]"
+ property="[[managedEapProperties_.Inner]]">
</network-config-select>
<network-config-select id="serverCa" label="[[i18n('OncEAP-ServerCA')]]"
value="{{selectedServerCaHash_}}" items="[[serverCaCerts_]]"
- hidden="[[!showEap_.ServerCA]]" cert-list>
+ hidden="[[!showEap_.ServerCA]]" cert-list
+ property="[[managedEapProperties_.UseSystemCAs]]">
</network-config-select>
- <cr-input label="[[i18n('OncEAP-SubjectMatch')]]"
+ <network-config-input label="[[i18n('OncEAP-SubjectMatch')]]"
value="{{eapProperties_.SubjectMatch}}"
- hidden="[[!showEap_.SubjectMatch]]">
- </cr-input>
+ hidden="[[!showEap_.SubjectMatch]]"
+ property="[[managedEapProperties_.SubjectMatch]]">
+ </network-config-input>
<network-config-select id="userCert" label="[[i18n('OncEAP-UserCert')]]"
value="{{selectedUserCertHash_}}" items="[[userCerts_]]"
- hidden="[[!showEap_.UserCert]]" cert-list>
+ hidden="[[!showEap_.UserCert]]" cert-list
+ property="[[managedEapProperties_.ClientCertType]]">
</network-config-select>
- <cr-input label="[[i18n('OncEAP-Identity')]]"
- value="{{eapProperties_.Identity}}" hidden="[[!showEap_.Identity]]">
- </cr-input>
+ <network-config-input label="[[i18n('OncEAP-Identity')]]"
+ value="{{eapProperties_.Identity}}" hidden="[[!showEap_.Identity]]"
+ property="[[managedEapProperties_.Identity]]">
+ </network-config-input>
<network-password-input label="[[i18n('OncEAP-Password')]]"
- value="{{eapProperties_.Password}}" hidden="[[!showEap_.Password]]">
+ value="{{eapProperties_.Password}}" hidden="[[!showEap_.Password]]"
+ property="[[managedEapProperties_.Password]]">
</network-password-input>
- <cr-input label="[[i18n('OncEAP-AnonymousIdentity')]]"
+ <network-config-input label="[[i18n('OncEAP-AnonymousIdentity')]]"
value="{{eapProperties_.AnonymousIdentity}}"
- hidden="[[!showEap_.AnonymousIdentity]]">
- </cr-input>
- <div class="property-box">
- <div id="eapSaveCredentialsLabel" class="start">
- [[i18n('networkConfigSaveCredentials')]]
- </div>
- <cr-toggle checked="{{eapProperties_.SaveCredentials}}"
- aria-labelledby="eapSaveCredentialsLabel">
- </cr-toggle>
- </div>
+ hidden="[[!showEap_.AnonymousIdentity]]"
+ property="[[managedEapProperties_.AnonymousIdentity]]">
+ </network-config-input>
+ <network-config-toggle label="[[i18n('networkConfigSaveCredentials')]]"
+ checked="{{eapProperties_.SaveCredentials}}"
+ property="[[managedEapProperties_.SaveCredentials]]">
+ </network-config-toggle>
</template>
<!-- Share (WiFi and WiMAX) -->
<template is="dom-if"
- if="[[shareIsVisible_(guid, type, networkProperties)]]" restamp>
+ if="[[shareIsVisible_(guid, type, managedProperties)]]" restamp>
<div class="property-box">
<div id="shareLabel" class="start">[[i18n('networkConfigShare')]]</div>
<cr-toggle id="share" checked="{{shareNetwork_}}"
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js
index ef0f00c2489..78ca586d781 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -13,7 +13,7 @@
* Note: closure does not always recognize this if inside function() {}.
* @enum {string}
*/
-var VPNConfigType = {
+const VPNConfigType = {
L2TP_IPSEC_PSK: 'L2TP_IPsec_PSK',
L2TP_IPSEC_CERT: 'L2TP_IPsec_Cert',
OPEN_VPN: 'OpenVPN',
@@ -22,14 +22,11 @@ var VPNConfigType = {
(function() {
'use strict';
-/** @const */ var DEFAULT_HASH = 'default';
-/** @const */ var DO_NOT_CHECK_HASH = 'do-not-check';
-/** @const */ var NO_CERTS_HASH = 'no-certs';
-/** @const */ var NO_USER_CERT_HASH = 'no-user-cert';
+/** @type {string} */ const DEFAULT_HASH = 'default';
+/** @type {string} */ const DO_NOT_CHECK_HASH = 'do-not-check';
+/** @type {string} */ const NO_CERTS_HASH = 'no-certs';
+/** @type {string} */ const NO_USER_CERT_HASH = 'no-user-cert';
-// Used to indicate a saved but unknown PSK value. Will appear as *'s in the
-// PSK field by default.
-/** @const */ var UNKNOWN_PSK = ' ';
Polymer({
is: 'network-config',
@@ -79,26 +76,36 @@ Polymer({
value: false,
},
+ /** Set to any error from the last configuration result. */
+ error: {
+ type: String,
+ notify: true,
+ },
+
/**
- * The current properties if an existing network being configured.
+ * The managed properties of an existing network.
+ * This is used for determination of managed fields.
* This will be undefined when configuring a new network.
- * @private {!chrome.networkingPrivate.NetworkProperties|undefined}
+ * @private {!chrome.networkingPrivate.ManagedProperties|undefined}
*/
- networkProperties: {
+ managedProperties: {
type: Object,
notify: true,
},
- /** Set to any error from the last configuration result. */
- error: {
- type: String,
- notify: true,
+ /**
+ * Managed EAP properties used for determination of managed EAP fields.
+ * @private {?chrome.networkingPrivate.ManagedEAPProperties}
+ */
+ managedEapProperties_: {
+ type: Object,
+ value: null,
},
- /** Set if |guid| is not empty once networkProperties are received. */
+ /** Set if |guid| is not empty once managedProperties are received. */
propertiesReceived_: Boolean,
- /** Set once properties have been sent; prevents multiple saves. */
+ /** Set once managedProperties have been sent; prevents multiple saves. */
propertiesSent_: Boolean,
/**
@@ -150,15 +157,6 @@ Polymer({
selectedUserCertHash_: String,
/**
- * Set to true when the PSK is saved but the value is unknown.
- * @private
- */
- pskSavedUnknown_: {
- type: Boolean,
- value: false,
- },
-
- /**
* Whether all required properties have been set.
* @private
*/
@@ -312,7 +310,7 @@ Polymer({
observers: [
'setEnableConnect_(isConfigured_, propertiesSent_)',
'setEnableSave_(isConfigured_, propertiesReceived_)',
- 'updateConfigProperties_(networkProperties)',
+ 'updateConfigProperties_(managedProperties)',
'updateSecurity_(configProperties_, security_)',
'updateEapOuter_(eapProperties_.Outer)',
'updateEapCerts_(eapProperties_.*, serverCaCerts_, userCerts_)',
@@ -358,13 +356,14 @@ Polymer({
this.propertiesSent_ = false;
this.selectedServerCaHash_ = undefined;
this.selectedUserCertHash_ = undefined;
- this.guid = this.networkProperties.GUID;
- this.type = this.networkProperties.Type;
+ this.guid = this.managedProperties.GUID;
+ this.type = this.managedProperties.Type;
if (this.guid) {
- this.networkingPrivate.getProperties(this.guid, (properties) => {
- this.getPropertiesCallback_(properties);
- this.focusFirstInput_();
- });
+ this.networkingPrivate.getManagedProperties(
+ this.guid, (managedProperties) => {
+ this.getManagedPropertiesCallback_(managedProperties);
+ this.focusFirstInput_();
+ });
} else {
this.async(() => {
this.focusFirstInput_();
@@ -393,7 +392,7 @@ Polymer({
this.propertiesSent_ = true;
this.error = '';
- var propertiesToSet = this.getPropertiesToSet_();
+ const propertiesToSet = this.getPropertiesToSet_();
if (this.getSource_() == CrOnc.Source.NONE) {
// Set 'AutoConnect' to false for VPN or if prohibited by policy.
// Note: Do not set AutoConnect to true, the connection manager will do
@@ -417,8 +416,8 @@ Polymer({
/** @private */
focusFirstInput_: function() {
Polymer.dom.flush();
- var e = this.$$(
- 'cr-input:not([readonly]),' +
+ const e = this.$$(
+ 'network-config-input:not([readonly]),' +
'network-password-input:not([disabled]),' +
'network-config-select:not([disabled])');
if (e)
@@ -453,18 +452,18 @@ Polymer({
getSource_: function() {
if (!this.guid)
return CrOnc.Source.NONE;
- var source = this.networkProperties.Source;
+ const source = this.managedProperties.Source;
return source ? /** @type {!CrOnc.Source} */ (source) : CrOnc.Source.NONE;
},
/** @private */
onCertificateListsChanged_: function() {
this.networkingPrivate.getCertificateLists(function(certificateLists) {
- var isOpenVpn = this.type == CrOnc.Type.VPN &&
+ const isOpenVpn = this.type == CrOnc.Type.VPN &&
this.get('VPN.Type', this.configProperties_) ==
CrOnc.VPNType.OPEN_VPN;
- var caCerts = certificateLists.serverCaCertificates.slice();
+ const caCerts = certificateLists.serverCaCertificates.slice();
if (!isOpenVpn) {
// 'Default' is the same as 'Do not check' except it sets
// eap.UseSystemCAs (which does not apply to OpenVPN).
@@ -475,7 +474,7 @@ Polymer({
this.i18n('networkCADoNotCheck'), DO_NOT_CHECK_HASH));
this.set('serverCaCerts_', caCerts);
- var userCerts = certificateLists.userCertificates.slice();
+ let userCerts = certificateLists.userCertificates.slice();
// Only hardware backed user certs are supported.
userCerts.forEach(function(cert) {
if (!cert.hardwareBacked)
@@ -508,94 +507,56 @@ Polymer({
},
/**
- * networkingPrivate.getProperties callback.
- * @param {!chrome.networkingPrivate.NetworkProperties} properties
+ * networkingPrivate.getManagedProperties callback.
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @private
*/
- getPropertiesCallback_: function(properties) {
- if (!properties) {
- // If |properties| is null, the network no longer exists; close the page.
+ getManagedPropertiesCallback_: function(managedProperties) {
+ if (!managedProperties) {
+ // If |managedProperties| is null,
+ // the network no longer exists; close the page.
console.error('Network no longer exists: ' + this.guid);
this.close_();
return;
}
- if (properties.Type == CrOnc.Type.ETHERNET &&
- this.get('Ethernet.Authentication', properties) !=
+ if (managedProperties.Type == CrOnc.Type.ETHERNET &&
+ CrOnc.getActiveValue(
+ /** @type {chrome.networkingPrivate.ManagedDOMString|undefined} */
+ (this.get('Ethernet.Authentication', managedProperties))) !=
CrOnc.Authentication.WEP_8021X) {
// Ethernet may have EAP properties set in a separate EthernetEap
- // configuration. Request that before calling |setNetworkProperties_|.
+ // configuration. Request that before calling |setManagedProperties_|.
this.networkingPrivate.getNetworks(
{networkType: CrOnc.Type.ETHERNET, visible: false, configured: true},
- this.getEthernetEap_.bind(this, properties));
+ this.getEthernetEap_.bind(this, managedProperties));
return;
}
- if (properties.Type == CrOnc.Type.VPN) {
+ if (managedProperties.Type == CrOnc.Type.VPN) {
this.vpnSaveCredentials_ =
- !!this.get('VPN.OpenVPN.SaveCredentials', properties) ||
- !!this.get('VPN.IPsec.SaveCredentials', properties) ||
- !!this.get('VPN.L2TP.SaveCredentials', properties);
- if (this.get('VPN.IPsec.PSK', properties) === '') {
- // If an empty PSK is provided, show a blank value in the UI to indicate
- // that the PSK has a saved value.
- this.pskSavedUnknown_ = true;
- this.set('VPN.IPsec.PSK', UNKNOWN_PSK, properties);
- } else {
- this.pskSavedUnknown_ = false;
- }
- }
-
- this.setNetworkProperties_(properties);
- },
-
- /**
- * If the IPsec.PSK field is focused and the PSK value is saved but unknown,
- * clear the pseudo value set in getPropertiesCallback_.
- * @param {!InputEvent} e
- * @private
- */
- onPskFocus_: function(e) {
- if (this.pskSavedUnknown_) {
- // We can not rely on data binding to update the target value when a
- // field is focused.
- e.target.value = '';
- this.set('VPN.IPsec.PSK', '', this.configProperties_);
- }
- },
-
- /**
- * If the IPsec.PSK field is in the saved-but-unknown state, restore the
- * pseudo value when the field is unfocused.
- * @param {!InputEvent} e
- * @private
- */
- onPskBlur_: function(e) {
- if (this.pskSavedUnknown_) {
- // The target is still focused so we can not rely on data binding to
- // update the target value.
- e.target.value = UNKNOWN_PSK;
- this.set('VPN.IPsec.PSK', UNKNOWN_PSK, this.configProperties_);
+ !!CrOnc.getActiveValue(
+ /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */
+ (this.get('VPN.OpenVPN.SaveCredentials', managedProperties))) ||
+ !!CrOnc.getActiveValue(
+ /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */
+ (this.get('VPN.IPsec.SaveCredentials', managedProperties))) ||
+ !!CrOnc.getActiveValue(
+ /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */
+ (this.get('VPN.L2TP.SaveCredentials', managedProperties)));
}
- },
- /**
- * When the IPsec.PSK field is changed, clear pskSavedUnknown_.
- * @param {!InputEvent} e
- * @private
- */
- onPskInput_: function(e) {
- this.pskSavedUnknown_ = false;
+ this.setManagedProperties_(managedProperties);
},
-
/**
- * @param {!chrome.networkingPrivate.NetworkProperties} properties
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @private
*/
- setNetworkProperties_: function(properties) {
+ setManagedProperties_: function(managedProperties) {
this.propertiesReceived_ = true;
- this.networkProperties = properties;
- this.setError_(properties.ErrorState);
+ this.managedProperties = managedProperties;
+ this.managedEapProperties_ = this.getManagedEap_(managedProperties);
+ this.setError_(managedProperties.ErrorState);
this.updateCertError_();
// Set the current shareNetwork_ value when properties are received.
@@ -605,36 +566,37 @@ Polymer({
/**
* networkingPrivate.getNetworks callback. Expects an array of Ethernet
* networks and looks for an EAP configuration to apply.
- * @param {!chrome.networkingPrivate.NetworkProperties} properties
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
* @param {!Array<chrome.networkingPrivate.NetworkStateProperties>} networks
* @private
*/
- getEthernetEap_: function(properties, networks) {
+ getEthernetEap_: function(managedProperties, networks) {
if (this.getRuntimeError_()) {
- this.setNetworkProperties_(properties);
+ this.setManagedProperties_(managedProperties);
return;
}
// Look for an existing EAP configuration. This may be stored in a
// separate 'Ethernet EAP Parameters' configuration.
- var ethernetEap = networks.find(function(network) {
+ const ethernetEap = networks.find(function(network) {
return !!network.Ethernet &&
network.Ethernet.Authentication == CrOnc.Authentication.WEP_8021X;
});
if (!ethernetEap) {
- this.setNetworkProperties_(properties);
+ this.setManagedProperties_(managedProperties);
return;
}
- this.networkingPrivate.getProperties(ethernetEap.GUID, (eapProperties) => {
- if (!this.getRuntimeError_() && eapProperties.Ethernet.EAP) {
- this.guid = eapProperties.GUID;
- this.security_ = CrOnc.Security.WPA_EAP;
- properties.GUID = eapProperties.GUID;
- properties.Ethernet.EAP = eapProperties.Ethernet.EAP;
- }
- this.setNetworkProperties_(properties);
- });
+ this.networkingPrivate.getManagedProperties(
+ ethernetEap.GUID, (eapProperties) => {
+ if (!this.getRuntimeError_() && eapProperties.Ethernet.EAP) {
+ this.guid = eapProperties.GUID;
+ this.security_ = CrOnc.Security.WPA_EAP;
+ managedProperties.GUID = eapProperties.GUID;
+ managedProperties.Ethernet.EAP = eapProperties.Ethernet.EAP;
+ }
+ this.setManagedProperties_(managedProperties);
+ });
},
/**
@@ -642,7 +604,7 @@ Polymer({
* @private
*/
getSecurityItems_() {
- if (this.networkProperties.Type == CrOnc.Type.WI_FI) {
+ if (this.managedProperties.Type == CrOnc.Type.WI_FI) {
return [
CrOnc.Security.NONE, CrOnc.Security.WEP_PSK, CrOnc.Security.WPA_PSK,
CrOnc.Security.WPA_EAP
@@ -653,7 +615,7 @@ Polymer({
/** @private */
setShareNetwork_: function() {
- var source = this.getSource_();
+ const source = this.getSource_();
if (source != CrOnc.Source.NONE) {
// Configured networks can not change whether they are shared.
this.shareNetwork_ =
@@ -666,13 +628,13 @@ Polymer({
}
if (this.shareAllowEnable) {
// New insecure WiFi networks are always shared.
- if (this.networkProperties.Type == CrOnc.Type.WI_FI &&
+ if (this.managedProperties.Type == CrOnc.Type.WI_FI &&
this.security_ == CrOnc.Security.NONE) {
this.shareNetwork_ = true;
return;
}
// Networks requiring a user certificate cannot be shared.
- var eap = this.eapProperties_;
+ const eap = this.eapProperties_;
if (eap && eap.Outer == CrOnc.EAPType.EAP_TLS) {
this.shareNetwork_ = false;
return;
@@ -682,7 +644,7 @@ Polymer({
},
/**
- * Updates the config properties when |this.networkProperties| changes.
+ * Updates the config properties when |this.managedProperties| changes.
* This gets called once when navigating to the page when default properties
* are set, and again for existing networks when the properties are received.
* @private
@@ -692,21 +654,27 @@ Polymer({
this.showVpn_ = null;
this.vpnType_ = undefined;
- var properties = this.networkProperties;
- var configProperties =
+ const managedProperties = this.managedProperties;
+ const configProperties =
/** @type {chrome.networkingPrivate.NetworkConfigProperties} */ ({
- Name: properties.Name || '',
- Type: properties.Type,
+ Name: CrOnc.getActiveValue(managedProperties.Name) || '',
+ Type: managedProperties.Type,
});
- switch (properties.Type) {
+ switch (managedProperties.Type) {
case CrOnc.Type.WI_FI:
- if (properties.WiFi) {
+ if (managedProperties.WiFi) {
configProperties.WiFi = {
- AutoConnect: properties.WiFi.AutoConnect,
- EAP: Object.assign({}, properties.WiFi.EAP),
- Passphrase: properties.WiFi.Passphrase,
- SSID: properties.WiFi.SSID,
- Security: properties.WiFi.Security
+ AutoConnect:
+ /** @type {boolean|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.WiFi.AutoConnect)),
+ EAP: Object.assign(
+ {}, CrOnc.getActiveProperties(managedProperties.WiFi.EAP)),
+ Passphrase: /** @type {string|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.WiFi.Passphrase)),
+ SSID: /** @type {string|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.WiFi.SSID)),
+ Security: /** @type {string|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.WiFi.Security))
};
} else {
configProperties.WiFi = {
@@ -720,11 +688,13 @@ Polymer({
break;
case CrOnc.Type.ETHERNET:
configProperties.Ethernet = {
- AutoConnect: !!this.get('Ethernet.AutoConnect', properties)
+ AutoConnect: !!CrOnc.getActiveValue(
+ /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */ (
+ this.get('Ethernet.AutoConnect', managedProperties)))
};
- if (properties.Ethernet && properties.Ethernet.EAP) {
- configProperties.Ethernet.EAP =
- Object.assign({}, properties.Ethernet.EAP),
+ if (managedProperties.Ethernet && managedProperties.Ethernet.EAP) {
+ configProperties.Ethernet.EAP = Object.assign(
+ {}, CrOnc.getActiveProperties(managedProperties.Ethernet.EAP)),
configProperties.Ethernet.EAP.Outer =
configProperties.Ethernet.EAP.Outer || CrOnc.EAPType.LEAP;
}
@@ -733,10 +703,13 @@ Polymer({
CrOnc.Security.NONE;
break;
case CrOnc.Type.WI_MAX:
- if (properties.WiMAX) {
+ if (managedProperties.WiMAX) {
configProperties.WiMAX = {
- AutoConnect: properties.WiMAX.AutoConnect,
- EAP: Object.assign({}, properties.WiMAX.EAP),
+ AutoConnect:
+ /** @type {boolean|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.WiMAX.AutoConnect)),
+ EAP: Object.assign(
+ {}, CrOnc.getActiveProperties(managedProperties.WiMAX.EAP)),
};
// WiMAX has no EAP.Outer property, only Identity and Password.
} else {
@@ -747,21 +720,27 @@ Polymer({
this.security_ = CrOnc.Security.WPA_EAP;
break;
case CrOnc.Type.VPN:
- if (properties.VPN) {
- var vpn = {
- Host: properties.VPN.Host,
- Type: properties.VPN.Type,
+ if (managedProperties.VPN) {
+ const vpn = {
+ Host: /** @type {string|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.VPN.Host)),
+ Type: /** @type {string|undefined} */ (
+ CrOnc.getActiveValue(managedProperties.VPN.Type)),
};
if (vpn.Type == CrOnc.VPNType.L2TP_IPSEC) {
vpn.IPsec =
/** @type {chrome.networkingPrivate.IPSecProperties} */ (
Object.assign(
{AuthenticationType: CrOnc.IPsecAuthenticationType.PSK},
- properties.VPN.IPsec));
- vpn.L2TP = Object.assign({Username: ''}, properties.VPN.L2TP);
+ CrOnc.getActiveProperties(
+ managedProperties.VPN.IPsec)));
+ vpn.L2TP = Object.assign(
+ {Username: ''},
+ CrOnc.getActiveProperties(managedProperties.VPN.L2TP));
} else {
assert(vpn.Type == CrOnc.VPNType.OPEN_VPN);
- vpn.OpenVPN = Object.assign({}, properties.VPN.OpenVPN);
+ vpn.OpenVPN = Object.assign(
+ {}, CrOnc.getActiveProperties(managedProperties.VPN.OpenVPN));
}
configProperties.VPN = vpn;
} else {
@@ -778,7 +757,7 @@ Polymer({
this.set('eapProperties_', this.getEap_(this.configProperties_));
if (!this.eapProperties_)
this.showEap_ = null;
- if (properties.Type == CrOnc.Type.VPN)
+ if (managedProperties.Type == CrOnc.Type.VPN)
this.vpnType_ = this.getVpnTypeFromProperties_(this.configProperties_);
},
@@ -793,13 +772,13 @@ Polymer({
// Set the share value to its default when the security type changes.
this.setShareNetwork_();
} else if (this.type == CrOnc.Type.ETHERNET) {
- var auth = this.security_ == CrOnc.Security.WPA_EAP ?
+ const auth = this.security_ == CrOnc.Security.WPA_EAP ?
CrOnc.Authentication.WEP_8021X :
CrOnc.Authentication.NONE;
this.set('Ethernet.Authentication', auth, this.configProperties_);
}
if (this.security_ == CrOnc.Security.WPA_EAP) {
- var eap = this.getEap_(this.configProperties_, true);
+ const eap = this.getEap_(this.configProperties_, true);
eap.Outer = eap.Outer || CrOnc.EAPType.LEAP;
this.setEap_(eap);
} else {
@@ -813,10 +792,10 @@ Polymer({
* @private
*/
updateEapOuter_: function() {
- var eap = this.eapProperties_;
+ const eap = this.eapProperties_;
if (!eap || !eap.Outer)
return;
- var innerItems = this.getEapInnerItems_(eap.Outer);
+ const innerItems = this.getEapInnerItems_(eap.Outer);
if (innerItems.length > 0) {
if (!eap.Inner || innerItems.indexOf(eap.Inner) < 0)
this.set('eapProperties_.Inner', innerItems[0]);
@@ -832,9 +811,9 @@ Polymer({
// EAP is used for all configurable types except VPN.
if (this.type == CrOnc.Type.VPN)
return;
- var eap = this.eapProperties_;
- var pem = eap && eap.ServerCAPEMs ? eap.ServerCAPEMs[0] : '';
- var certId =
+ const eap = this.eapProperties_;
+ const pem = eap && eap.ServerCAPEMs ? eap.ServerCAPEMs[0] : '';
+ const certId =
eap && eap.ClientCertType == 'PKCS11Id' ? eap.ClientCertPKCS11Id : '';
this.setSelectedCerts_(pem, certId);
},
@@ -846,7 +825,7 @@ Polymer({
this.updateCertError_();
return;
}
- var outer = this.eapProperties_.Outer;
+ const outer = this.eapProperties_.Outer;
switch (this.type) {
case CrOnc.Type.WI_MAX:
this.showEap_ = {
@@ -879,7 +858,7 @@ Polymer({
* @private
*/
getEap_: function(properties, opt_create) {
- var eap;
+ let eap;
switch (properties.Type) {
case CrOnc.Type.WI_FI:
eap = properties.WiFi && properties.WiFi.EAP;
@@ -918,11 +897,33 @@ Polymer({
},
/**
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
+ * @return {?chrome.networkingPrivate.ManagedEAPProperties}
+ * @private
+ */
+ getManagedEap_: function(managedProperties) {
+ let managedEap;
+ switch (managedProperties.Type) {
+ case CrOnc.Type.WI_FI:
+ managedEap = managedProperties.WiFi && managedProperties.WiFi.EAP;
+ break;
+ case CrOnc.Type.ETHERNET:
+ managedEap =
+ managedProperties.Ethernet && managedProperties.Ethernet.EAP;
+ break;
+ case CrOnc.Type.WI_MAX:
+ managedEap = managedProperties.WiMAX && managedProperties.WiMAX.EAP;
+ break;
+ }
+ return managedEap || null;
+ },
+
+ /**
* @param {!chrome.networkingPrivate.NetworkConfigProperties} properties
* @private
*/
getVpnTypeFromProperties_: function(properties) {
- var vpn = properties.VPN;
+ const vpn = properties.VPN;
assert(vpn);
if (vpn.Type == CrOnc.VPNType.L2TP_IPSEC) {
return vpn.IPsec.AuthenticationType ==
@@ -938,7 +939,7 @@ Polymer({
if (this.configProperties_ === undefined)
return;
- var vpn = this.configProperties_.VPN;
+ const vpn = this.configProperties_.VPN;
if (!vpn) {
this.showVpn_ = null;
this.updateCertError_();
@@ -975,8 +976,8 @@ Polymer({
updateVpnIPsecCerts_: function() {
if (this.vpnType_ != VPNConfigType.L2TP_IPSEC_CERT)
return;
- var pem, certId;
- var ipsec = /** @type {chrome.networkingPrivate.IPSecProperties} */ (
+ let pem, certId;
+ const ipsec = /** @type {chrome.networkingPrivate.IPSecProperties} */ (
this.get('VPN.IPsec', this.configProperties_));
if (ipsec) {
pem = ipsec.ServerCAPEMs && ipsec.ServerCAPEMs[0];
@@ -990,8 +991,8 @@ Polymer({
updateOpenVPNCerts_: function() {
if (this.vpnType_ != VPNConfigType.OPEN_VPN)
return;
- var pem, certId;
- var openvpn = /** @type {chrome.networkingPrivate.OpenVPNProperties} */ (
+ let pem, certId;
+ const openvpn = /** @type {chrome.networkingPrivate.OpenVPNProperties} */ (
this.get('VPN.OpenVPN', this.configProperties_));
if (openvpn) {
pem = openvpn.ServerCAPEMs && openvpn.ServerCAPEMs[0];
@@ -1006,14 +1007,14 @@ Polymer({
updateCertError_: function() {
// If |this.error| was set to something other than a cert error, do not
// change it.
- /** @const */ var noCertsError = 'networkErrorNoUserCertificate';
- /** @const */ var noValidCertsError = 'networkErrorNotHardwareBacked';
+ /** @const */ const noCertsError = 'networkErrorNoUserCertificate';
+ /** @const */ const noValidCertsError = 'networkErrorNotHardwareBacked';
if (this.error && this.error != noCertsError &&
this.error != noValidCertsError) {
return;
}
- var requireCerts = (this.showEap_ && this.showEap_.UserCert) ||
+ const requireCerts = (this.showEap_ && this.showEap_.UserCert) ||
(this.showVpn_ && this.showVpn_.UserCert);
if (!requireCerts) {
this.setError_('');
@@ -1023,7 +1024,7 @@ Polymer({
this.setError_(noCertsError);
return;
}
- var validUserCert = this.userCerts_.find(function(cert) {
+ const validUserCert = this.userCerts_.find(function(cert) {
return !!cert.hash;
});
if (!validUserCert) {
@@ -1043,7 +1044,7 @@ Polymer({
*/
setSelectedCerts_: function(pem, certId) {
if (pem) {
- var serverCa = this.serverCaCerts_.find(function(cert) {
+ const serverCa = this.serverCaCerts_.find(function(cert) {
return cert.pem == pem;
});
if (serverCa)
@@ -1051,7 +1052,7 @@ Polymer({
}
if (certId) {
- var userCert = this.userCerts_.find(function(cert) {
+ const userCert = this.userCerts_.find(function(cert) {
return cert.PKCS11Id == certId;
});
if (userCert)
@@ -1086,7 +1087,7 @@ Polymer({
this.selectedServerCaHash_ = undefined;
if (!this.selectedServerCaHash_ ||
this.selectedServerCaHash_ == DEFAULT_HASH) {
- var eap = this.eapProperties_;
+ const eap = this.eapProperties_;
if (eap && eap.UseSystemCAs === false)
this.selectedServerCaHash_ = DO_NOT_CHECK_HASH;
}
@@ -1114,7 +1115,7 @@ Polymer({
if (!this.get('WiFi.SSID', this.configProperties_))
return false;
if (this.configRequiresPassphrase_()) {
- var passphrase = this.get('WiFi.Passphrase', this.configProperties_);
+ const passphrase = this.get('WiFi.Passphrase', this.configProperties_);
if (!passphrase || passphrase.length < this.MIN_PASSPHRASE_LENGTH)
return false;
}
@@ -1208,7 +1209,7 @@ Polymer({
return false;
if (this.security_ == CrOnc.Security.WPA_EAP) {
- var eap = this.getEap_(this.configProperties_);
+ const eap = this.getEap_(this.configProperties_);
if (eap && eap.Outer == CrOnc.EAPType.EAP_TLS)
return false;
}
@@ -1235,7 +1236,7 @@ Polymer({
* @private
*/
eapIsConfigured_: function() {
- var eap = this.getEap_(this.configProperties_);
+ const eap = this.getEap_(this.configProperties_);
if (!eap)
return false;
if (eap.Outer != CrOnc.EAPType.EAP_TLS)
@@ -1248,14 +1249,13 @@ Polymer({
* @private
*/
vpnIsConfigured_: function() {
- var vpn = this.configProperties_.VPN;
+ const vpn = this.configProperties_.VPN;
if (!this.configProperties_.Name || !vpn || !vpn.Host)
return false;
switch (this.vpnType_) {
case VPNConfigType.L2TP_IPSEC_PSK:
- return !!this.get('L2TP.Username', vpn) &&
- (this.pskSavedUnknown_ || !!this.get('IPsec.PSK', vpn));
+ return !!this.get('L2TP.Username', vpn) && !!this.get('IPsec.PSK', vpn);
case VPNConfigType.L2TP_IPSEC_CERT:
return !!this.get('L2TP.Username', vpn) &&
this.selectedUserCertHashIsValid_();
@@ -1270,13 +1270,13 @@ Polymer({
/** @private */
getPropertiesToSet_: function() {
- var propertiesToSet = Object.assign({}, this.configProperties_);
+ const propertiesToSet = Object.assign({}, this.configProperties_);
// Do not set AutoConnect by default, the connection manager will set
// it to true on a successful connection.
CrOnc.setTypeProperty(propertiesToSet, 'AutoConnect', undefined);
if (this.guid)
propertiesToSet.GUID = this.guid;
- var eap = this.getEap_(propertiesToSet);
+ const eap = this.getEap_(propertiesToSet);
if (eap)
this.setEapProperties_(eap);
if (this.configProperties_.Type == CrOnc.Type.VPN) {
@@ -1293,10 +1293,10 @@ Polymer({
* @private
*/
getServerCaPems_: function() {
- var caHash = this.selectedServerCaHash_ || '';
+ const caHash = this.selectedServerCaHash_ || '';
if (!caHash || caHash == DO_NOT_CHECK_HASH || caHash == DEFAULT_HASH)
return [];
- var serverCa = this.findCert_(this.serverCaCerts_, caHash);
+ const serverCa = this.findCert_(this.serverCaCerts_, caHash);
return serverCa && serverCa.pem ? [serverCa.pem] : [];
},
@@ -1305,12 +1305,12 @@ Polymer({
* @private
*/
getUserCertPkcs11Id_: function() {
- var userCertHash = this.selectedUserCertHash_ || '';
+ const userCertHash = this.selectedUserCertHash_ || '';
if (!this.selectedUserCertHashIsValid_() ||
userCertHash == NO_USER_CERT_HASH) {
return '';
}
- var userCert = this.findCert_(this.userCerts_, userCertHash);
+ const userCert = this.findCert_(this.userCerts_, userCertHash);
return (userCert && userCert.PKCS11Id) || '';
},
@@ -1323,7 +1323,7 @@ Polymer({
eap.ServerCAPEMs = this.getServerCaPems_();
- var pkcs11Id = this.getUserCertPkcs11Id_();
+ const pkcs11Id = this.getUserCertPkcs11Id_();
eap.ClientCertType = pkcs11Id ? 'PKCS11Id' : 'None';
eap.ClientCertPKCS11Id = pkcs11Id || '';
},
@@ -1333,11 +1333,11 @@ Polymer({
* @private
*/
setOpenVPNProperties_: function(propertiesToSet) {
- var openvpn = propertiesToSet.VPN.OpenVPN || {};
+ const openvpn = propertiesToSet.VPN.OpenVPN || {};
openvpn.ServerCAPEMs = this.getServerCaPems_();
- var pkcs11Id = this.getUserCertPkcs11Id_();
+ const pkcs11Id = this.getUserCertPkcs11Id_();
openvpn.ClientCertType = pkcs11Id ? 'PKCS11Id' : 'None';
openvpn.ClientCertPKCS11Id = pkcs11Id || '';
@@ -1352,7 +1352,6 @@ Polymer({
}
openvpn.SaveCredentials = this.vpnSaveCredentials_;
-
propertiesToSet.VPN.OpenVPN = openvpn;
},
@@ -1361,7 +1360,7 @@ Polymer({
* @private
*/
setVpnIPsecProperties_: function(propertiesToSet) {
- var vpn = propertiesToSet.VPN;
+ const vpn = propertiesToSet.VPN;
assert(vpn.IPsec);
if (vpn.IPsec.AuthenticationType == CrOnc.IPsecAuthenticationType.CERT) {
vpn.IPsec.ClientCertType = 'PKCS11Id';
@@ -1371,8 +1370,6 @@ Polymer({
vpn.IPsec.IKEVersion = 1;
vpn.IPsec.SaveCredentials = this.vpnSaveCredentials_;
vpn.L2TP.SaveCredentials = this.vpnSaveCredentials_;
- if (this.pskSavedUnknown_)
- delete vpn.IPsec.PSK;
},
/**
@@ -1394,7 +1391,7 @@ Polymer({
this.propertiesSent_ = false;
return;
}
- var connectState = this.networkProperties.ConnectionState;
+ const connectState = this.managedProperties.ConnectionState;
if (connect &&
(!connectState ||
connectState == CrOnc.ConnectionState.NOT_CONNECTED)) {
@@ -1413,7 +1410,7 @@ Polymer({
this.setError_(this.getRuntimeError_());
if (this.error) {
console.error(
- 'createNetworkError, type: ' + this.networkProperties.Type + ': ' +
+ 'createNetworkError, type: ' + this.managedProperties.Type + ': ' +
'error: ' + this.error);
this.propertiesSent_ = false;
return;
@@ -1428,7 +1425,7 @@ Polymer({
*/
startConnect_: function(guid) {
this.networkingPrivate.startConnect(guid, () => {
- var error = this.getRuntimeError_();
+ const error = this.getRuntimeError_();
if (!error || error == 'connected' || error == 'connect-canceled' ||
error == 'connecting') {
// Connect is in progress, completed or canceled, close the dialog.
@@ -1473,5 +1470,59 @@ Polymer({
setError_: function(error) {
this.error = error || '';
},
+
+ /**
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
+ * @return {chrome.networkingPrivate.ManagedDOMString|undefined}
+ * @private
+ */
+ getManagedSecurity_: function(managedProperties) {
+ let managedSecurity = undefined;
+ switch (managedProperties.Type) {
+ case CrOnc.Type.WI_FI:
+ managedSecurity =
+ managedProperties.WiFi && managedProperties.WiFi.Security;
+ break;
+ case CrOnc.Type.ETHERNET:
+ managedSecurity = managedProperties.Ethernet &&
+ managedProperties.Ethernet.Authentication;
+ break;
+ }
+ return managedSecurity;
+ },
+
+ /**
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
+ * @return {!chrome.networkingPrivate.ManagedBoolean|undefined}
+ * @private
+ */
+ getManagedVpnSaveCredentials_: function(managedProperties) {
+ return /** @type {chrome.networkingPrivate.ManagedBoolean|undefined} */ (
+ this.get('VPN.OpenVPN.SaveCredentials', managedProperties) ||
+ this.get('VPN.IPsec.SaveCredentials', managedProperties) ||
+ this.get('VPN.L2TP.SaveCredentials', managedProperties));
+ },
+
+ /**
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
+ * @return {!chrome.networkingPrivate.ManagedDOMStringList|undefined}
+ * @private
+ */
+ getManagedVpnServerCaRefs_: function(managedProperties) {
+ return /** @type {chrome.networkingPrivate.ManagedDOMStringList|undefined} */ (
+ this.get('VPN.OpenVPN.ServerCARefs', managedProperties) ||
+ this.get('VPN.IPsec.ServerCARefs', managedProperties));
+ },
+
+ /**
+ * @param {!chrome.networkingPrivate.ManagedProperties} managedProperties
+ * @return {!chrome.networkingPrivate.ManagedDOMString|undefined}
+ * @private
+ */
+ getManagedVpnClientCertType_: function(managedProperties) {
+ return /** @type {chrome.networkingPrivate.ManagedDOMString|undefined} */ (
+ this.get('VPN.OpenVPN.ClientCertType', managedProperties) ||
+ this.get('VPN.IPsec.ClientCertType', managedProperties));
+ },
});
})();
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.html
new file mode 100644
index 00000000000..1adda9a34ce
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
+<script src="network_config_element_behavior.js"></script>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.js
new file mode 100644
index 00000000000..c99c004adb9
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.js
@@ -0,0 +1,37 @@
+// 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.
+
+/**
+ * @fileoverview Behavior for network config elements.
+ */
+
+/** @polymerBehavior */
+const NetworkConfigElementBehavior = {
+ properties: {
+ disabled: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
+
+ /**
+ * Network managed property associated with the config element.
+ * @type {?CrOnc.ManagedProperty}
+ */
+ property: {
+ type: Object,
+ value: null,
+ },
+ },
+
+ /**
+ * @param {boolean} disabled
+ * @param {?CrOnc.ManagedProperty} property
+ * @return {boolean} True if the element should be disabled.
+ * @private
+ */
+ getDisabled_: function(disabled, property) {
+ return disabled || (!!property && this.isNetworkPolicyEnforced(property));
+ },
+};
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html
new file mode 100644
index 00000000000..5f66677bcdd
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.html
@@ -0,0 +1,40 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="network_config_element_behavior.html">
+<link rel="import" href="network_shared_css.html">
+
+<dom-module id="network-config-input">
+ <template>
+ <style include="network-shared">
+ #container {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ }
+
+ cr-input {
+ width: 100%;
+ }
+
+ cr-policy-network-indicator {
+ --cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
+ }
+ </style>
+
+ <div id="container">
+ <cr-input label="[[label]]" value="{{value}}"
+ hidden="[[hidden]]" readonly="[[readonly]]"
+ disabled="[[getDisabled_(disabled, property)]]">
+ </cr-input>
+ <cr-policy-network-indicator
+ property="[[property]]" tooltip-position="left">
+ </cr-policy-network-indicator>
+ </div>
+
+ </template>
+ <script src="network_config_input.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.js
new file mode 100644
index 00000000000..e5281f2cce2
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_input.js
@@ -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.
+
+/**
+ * @fileoverview Polymer element for network configuration input fields.
+ */
+Polymer({
+ is: 'network-config-input',
+
+ behaviors: [CrPolicyNetworkBehavior, NetworkConfigElementBehavior],
+
+ properties: {
+ label: String,
+
+ hidden: {
+ type: Boolean,
+ reflectToAttribute: true,
+ },
+
+ readonly: {
+ type: Boolean,
+ reflectToAttribute: true,
+ },
+
+ value: {
+ type: String,
+ notify: true,
+ },
+ },
+
+ focus: function() {
+ this.$$('cr-input').focus();
+ },
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.html
index 0fb698c7f07..9cde37d474f 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.html
@@ -1,7 +1,11 @@
<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/md_select_css.html">
+<link rel="import" href="network_config_element_behavior.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-config-select">
@@ -24,19 +28,35 @@
margin-bottom: var(--cr-form-field-bottom-spacing);
padding: 0;
}
+
+ #inner {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ }
+
+ cr-policy-network-indicator {
+ --cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
+ }
</style>
<div id="outer">
<div id="label">[[label]]</div>
- <select class="md-select" disabled="[[disabled]]"
- value="{{value::change}}" aria-label$="[[label]]">
- <template is="dom-repeat" items="[[items]]">
- <option value="[[getItemValue_(item)]]"
- disabled="[[!getItemEnabled_(item)]]">
- [[getItemLabel_(item, oncPrefix)]]
- </option>
- </template>
- </select>
+ <div id="inner">
+ <select class="md-select"
+ disabled="[[getDisabled_(disabled, property)]]"
+ value="{{value::change}}" aria-label$="[[label]]">
+ <template is="dom-repeat" items="[[items]]">
+ <option value="[[getItemValue_(item)]]"
+ disabled="[[!getItemEnabled_(item)]]">
+ [[getItemLabel_(item, oncPrefix)]]
+ </option>
+ </template>
+ </select>
+ <cr-policy-network-indicator
+ property="[[property]]" tooltip-position="left">
+ </cr-policy-network-indicator>
+ </div>
</div>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.js
index fa7e9672cbc..6bf3e829c95 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_select.js
@@ -8,16 +8,15 @@
Polymer({
is: 'network-config-select',
- behaviors: [I18nBehavior],
+ behaviors: [
+ I18nBehavior,
+ CrPolicyNetworkBehavior,
+ NetworkConfigElementBehavior,
+ ],
properties: {
label: String,
- disabled: {
- type: Boolean,
- reflectToAttribute: true,
- },
-
/** Set to true if |items| is a list of certificates. */
certList: Boolean,
@@ -53,7 +52,7 @@ Polymer({
updateSelected_: function() {
// Wait for the dom-repeat to populate the <option> entries.
this.async(function() {
- var select = this.$$('select');
+ const select = this.$$('select');
if (select.value != this.value)
select.value = this.value;
});
@@ -70,8 +69,8 @@ Polymer({
return this.getCertificateName_(
/** @type {chrome.networkingPrivate.Certificate}*/ (item));
}
- var key = /** @type {string} */ (item);
- var oncKey = 'Onc' + prefix.replace(/\./g, '-') + '_' + key;
+ const key = /** @type {string} */ (item);
+ const oncKey = 'Onc' + prefix.replace(/\./g, '-') + '_' + key;
if (this.i18nExists(oncKey))
return this.i18n(oncKey);
assertNotReached('ONC Key not found: ' + oncKey);
@@ -96,7 +95,7 @@ Polymer({
*/
getItemEnabled_: function(item) {
if (this.certList) {
- var cert = /** @type {chrome.networkingPrivate.Certificate}*/ (item);
+ const cert = /** @type {chrome.networkingPrivate.Certificate}*/ (item);
return !!cert.hash;
}
return true;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.html
new file mode 100644
index 00000000000..6e2ad80a3eb
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.html
@@ -0,0 +1,32 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="network_config_element_behavior.html">
+<link rel="import" href="network_shared_css.html">
+
+<dom-module id="network-config-toggle">
+ <template>
+ <style include="network-shared">
+ cr-policy-network-indicator {
+ --cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
+ }
+ </style>
+
+ <div class="property-box">
+ <div class="start">
+ [[label]]
+ </div>
+ <cr-toggle checked="{{checked}}"
+ disabled="[[getDisabled_(disabled, property)]]"
+ aria-label$="[[label]]">
+ </cr-toggle>
+ <cr-policy-network-indicator
+ property="[[property]]" tooltip-position="left">
+ </cr-policy-network-indicator>
+ </div>
+ </template>
+ <script src="network_config_toggle.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.js
new file mode 100644
index 00000000000..d4535bbe253
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config_toggle.js
@@ -0,0 +1,23 @@
+// 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.
+
+/**
+ * @fileoverview Polymer element for network configuration toggle.
+ */
+Polymer({
+ is: 'network-config-toggle',
+
+ behaviors: [CrPolicyNetworkBehavior, NetworkConfigElementBehavior],
+
+ properties: {
+ label: String,
+
+ checked: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ notify: true,
+ },
+ },
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
index b7e07cc1c72..7f3cb3dd6ec 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_ip_config.js
@@ -81,21 +81,21 @@ Polymer({
if (!this.networkProperties)
return;
- var properties = this.networkProperties;
+ const properties = this.networkProperties;
if (newValue.GUID != (oldValue && oldValue.GUID))
this.savedStaticIp_ = undefined;
// Update the 'automatic' property.
if (properties.IPAddressConfigType) {
- var ipConfigType = CrOnc.getActiveValue(properties.IPAddressConfigType);
+ const ipConfigType = CrOnc.getActiveValue(properties.IPAddressConfigType);
this.automatic_ = (ipConfigType != CrOnc.IPConfigType.STATIC);
}
if (properties.IPConfigs || properties.StaticIPConfig) {
// Update the 'ipConfig' property.
- var ipv4 = this.getIPConfigUIProperties_(
+ const ipv4 = this.getIPConfigUIProperties_(
CrOnc.getIPConfigForType(properties, CrOnc.IPType.IPV4));
- var ipv6 = this.getIPConfigUIProperties_(
+ let ipv6 = this.getIPConfigUIProperties_(
CrOnc.getIPConfigForType(properties, CrOnc.IPType.IPV6));
if (properties.ConnectionState == CrOnc.ConnectionState.CONNECTED &&
ipv4 && ipv4.IPAddress) {
@@ -111,7 +111,7 @@ Polymer({
/** @private */
onAutomaticChange_: function() {
if (!this.automatic_) {
- var defaultIpv4 = {
+ const defaultIpv4 = {
Gateway: '192.168.1.1',
IPAddress: '192.168.1.1',
RoutingPrefix: '255.255.255.0',
@@ -147,9 +147,9 @@ Polymer({
getIPConfigUIProperties_: function(ipconfig) {
if (!ipconfig)
return undefined;
- var result = {};
- for (var key in ipconfig) {
- var value = ipconfig[key];
+ const result = {};
+ for (const key in ipconfig) {
+ const value = ipconfig[key];
if (key == 'RoutingPrefix')
result.RoutingPrefix = CrOnc.getRoutingPrefixAsNetmask(value);
else
@@ -165,9 +165,9 @@ Polymer({
* @private
*/
getIPConfigProperties_: function(ipconfig) {
- var result = {};
- for (var key in ipconfig) {
- var value = ipconfig[key];
+ const result = {};
+ for (const key in ipconfig) {
+ const value = ipconfig[key];
if (key == 'RoutingPrefix')
result.RoutingPrefix = CrOnc.getRoutingPrefixAsLength(value);
else
@@ -183,7 +183,7 @@ Polymer({
hasIpConfigFields_: function() {
if (!this.ipConfigFields_)
return false;
- for (var i = 0; i < this.ipConfigFields_.length; ++i) {
+ for (let i = 0; i < this.ipConfigFields_.length; ++i) {
if (this.get(this.ipConfigFields_[i], this.ipConfig_) != undefined)
return true;
}
@@ -213,8 +213,8 @@ Polymer({
onIPChange_: function(event) {
if (!this.ipConfig_)
return;
- var field = event.detail.field;
- var value = event.detail.value;
+ const field = event.detail.field;
+ const value = event.detail.value;
// Note: |field| includes the 'ipv4.' prefix.
this.set('ipConfig_.' + field, value);
this.sendStaticIpConfig_();
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html
index 7cb2f0fd87b..a38f89212e4 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.html
@@ -3,10 +3,10 @@
<link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/html/md_select_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-nameservers">
@@ -22,8 +22,8 @@
margin-inline-start: 38px;
}
- paper-radio-group {
- --paper-radio-group-item-padding: 12px;
+ cr-radio-group {
+ --cr-radio-group-item-padding: 12px;
width: 100%;
}
@@ -46,10 +46,9 @@
</div>
<div id="radioGroupDiv">
- <paper-radio-group id="nameserverType" class="layout vertical"
+ <cr-radio-group id="nameserverType" class="layout vertical"
selected="[[nameserversType_]]"
- selectable="cr-radio-button"
- on-paper-radio-group-changed="onTypeChange_"
+ on-selected-changed="onTypeChange_"
aria-label="[[i18n('networkNameservers')]]">
<!-- Automatic nameservers -->
<cr-radio-button name="automatic">
@@ -91,7 +90,7 @@
</template>
</div>
</template>
- </paper-radio-group>
+ </cr-radio-group>
</div>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js
index c59320d6aaa..e1cf0a478a0 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js
@@ -81,16 +81,16 @@ Polymer({
this.savedNameservers_ = [];
// Update the 'nameservers' property.
- var nameservers = [];
- var ipv4 =
+ let nameservers = [];
+ const ipv4 =
CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4);
if (ipv4 && ipv4.NameServers)
nameservers = ipv4.NameServers;
// Update the 'nameserversType' property.
- var configType =
+ const configType =
CrOnc.getActiveValue(this.networkProperties.NameServersConfigType);
- var type;
+ let type;
if (configType == CrOnc.IPConfigType.STATIC) {
if (nameservers.join(',') == this.GOOGLE_NAMESERVERS.join(',')) {
type = 'google';
@@ -114,7 +114,7 @@ Polymer({
setNameservers_: function(nameserversType, nameservers, sendNameservers) {
if (nameserversType == 'custom') {
// Add empty entries for unset custom nameservers.
- for (var i = nameservers.length; i < this.MAX_NAMESERVERS; ++i)
+ for (let i = nameservers.length; i < this.MAX_NAMESERVERS; ++i)
nameservers[i] = '';
this.savedNameservers_ = nameservers.slice();
}
@@ -162,11 +162,10 @@ Polymer({
/**
* Event triggered when the selected type changes. Updates nameservers and
* sends the change value if necessary.
- * @param {!Event} event
* @private
*/
- onTypeChange_: function(event) {
- var type = this.$$('#nameserverType').selected;
+ onTypeChange_: function() {
+ const type = this.$$('#nameserverType').selected;
this.nameserversType_ = type;
if (type == 'custom') {
// Restore the saved nameservers.
@@ -194,12 +193,12 @@ Polymer({
* @private
*/
sendNameServers_: function() {
- var type = this.nameserversType_;
+ const type = this.nameserversType_;
if (type == 'custom') {
- var nameservers = new Array(this.MAX_NAMESERVERS);
- for (var i = 0; i < this.MAX_NAMESERVERS; ++i) {
- var nameserverInput = this.$$('#nameserver' + i);
+ const nameservers = new Array(this.MAX_NAMESERVERS);
+ for (let i = 0; i < this.MAX_NAMESERVERS; ++i) {
+ const nameserverInput = this.$$('#nameserver' + i);
nameservers[i] = nameserverInput ? nameserverInput.value : '';
}
this.nameservers_ = nameservers;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.html
index f43fe575bad..d84c2c86688 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.html
@@ -1,33 +1,54 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="network_config_element_behavior.html">
<link rel="import" href="network_shared_css.html">
<dom-module id="network-password-input">
<template>
<style include="network-shared">
+ #container {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ }
+
cr-input {
width: 100%;
}
- paper-icon-button-light {
- margin: 0;
- width: var(--network-control-margin);
+ cr-policy-network-indicator {
+ --cr-tooltip-icon-margin-start: var(--cr-controlled-by-spacing);
}
</style>
- <cr-input id="input" label="[[label]]" value="{{value}}"
- disabled="[[disabled]]" type="[[getInputType_(showPassword)]]"
- on-keypress="onInputKeypress_">
- <paper-icon-button-light id="icon" slot="suffix"
- class$="[[getIconClass_(showPassword)]]">
- <button on-tap="onShowPasswordTap_"
- title="[[getShowPasswordTitle_(showPassword)]]">
- </button>
- </paper-icon-button-light>
- </cr-input>
+ <div id="container">
+ <cr-input id="input" label="[[label]]" value="{{value}}"
+ disabled="[[getDisabled_(disabled, property)]]"
+ type="[[getInputType_(showPassword)]]"
+ on-focus="onFocus_" on-blur="onBlur_" on-input="onInput_"
+ on-keypress="onKeypress_">
+ </cr-input>
+ <template is="dom-if" if="[[!showPolicyIndicator_]]" restamp>
+ <paper-icon-button-light id="icon" slot="suffix"
+ class$="[[getIconClass_(showPassword)]]">
+ <button on-tap="onShowPasswordTap_"
+ disabled="[[getButtonDisabled_(value)]]"
+ title="[[getShowPasswordTitle_(showPassword)]]">
+ </button>
+ </paper-icon-button-light>
+ </template>
+ <template is="dom-if" if="[[showPolicyIndicator_]]" restamp>
+ <cr-policy-network-indicator
+ property="[[property]]" tooltip-position="left">
+ </cr-policy-network-indicator>
+ </template>
+ </div>
</template>
<script src="network_password_input.js"></script>
</dom-module>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.js
index 806dbcc4716..fda9d28de7a 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_password_input.js
@@ -5,10 +5,20 @@
/**
* @fileoverview Polymer element for network password input fields.
*/
+
+// Used to indicate a saved but unknown credential value. Will appear as *'s in
+// the credential (passphrase, password, etc.) field by default.
+// See |kFakeCredential| in chromeos/network/policy_util.h.
+/** @type {string} */ const FAKE_CREDENTIAL = 'FAKE_CREDENTIAL_VPaJDV9x';
+
Polymer({
is: 'network-password-input',
- behaviors: [I18nBehavior],
+ behaviors: [
+ I18nBehavior,
+ CrPolicyNetworkBehavior,
+ NetworkConfigElementBehavior,
+ ],
properties: {
label: {
@@ -16,11 +26,6 @@ Polymer({
reflectToAttribute: true,
},
- disabled: {
- type: Boolean,
- reflectToAttribute: true,
- },
-
value: {
type: String,
notify: true,
@@ -30,6 +35,28 @@ Polymer({
type: Boolean,
value: false,
},
+
+ showPolicyIndicator_: {
+ type: Boolean,
+ value: false,
+ computed: 'getDisabled_(disabled, property)',
+ },
+
+ /** @private */
+ restoreUnknown_: {
+ type: Boolean,
+ value: false,
+ },
+ },
+
+ observers: [
+ 'updateShowPassword_(value)',
+ ],
+
+ /** @private */
+ updateShowPassword_: function() {
+ if (this.value == FAKE_CREDENTIAL)
+ this.showPassword = false;
},
focus: function() {
@@ -62,6 +89,17 @@ Polymer({
},
/**
+ * @param {string} value
+ * @return {boolean} True if the value equals |FAKE_CREDENTIAL| to
+ * prevent users from seeing this fake credential, but they should be able to
+ * see their custom input.
+ * @private
+ */
+ getButtonDisabled_: function(value) {
+ return value == FAKE_CREDENTIAL;
+ },
+
+ /**
* @param {!Event} event
* @private
*/
@@ -74,10 +112,54 @@ Polymer({
* @param {!Event} event
* @private
*/
- onInputKeypress_: function(event) {
+ onKeypress_: function(event) {
if (event.target.id != 'input' || event.key != 'Enter')
return;
event.stopPropagation();
this.fire('enter');
},
+
+ /**
+ * If the input field is focused and the value is |FAKE_CREDENTIAL|,
+ * clear the value.
+ * @param {!InputEvent} e
+ * @private
+ */
+ onFocus_: function(e) {
+ if (this.value != FAKE_CREDENTIAL)
+ return;
+ // We can not rely on data binding to update the target value when a
+ // field is focused.
+ e.target.value = '';
+ this.value = '';
+ // Remember to restore |FAKE_CREDENTIAL| if the user doesn't change
+ // the input value.
+ this.restoreUnknown_ = true;
+ },
+
+ /**
+ * If the input field should be restored, restore the |FAKE_CREDENTIAL|
+ * value when the field is unfocused.
+ * @param {!InputEvent} e
+ * @private
+ */
+ onBlur_: function(e) {
+ if (!this.restoreUnknown_)
+ return;
+ // The target is still focused so we can not rely on data binding to
+ // update the target value.
+ e.target.value = FAKE_CREDENTIAL;
+ this.value = FAKE_CREDENTIAL;
+ },
+
+ /**
+ * When the input field is changed, clear |restoreUnknown_|.
+ * @param {!InputEvent} e
+ * @private
+ */
+ onInput_: function(e) {
+ this.restoreUnknown_ = false;
+ },
+
+
});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
index 547f81f6ebe..42629e96f16 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_property_list.js
@@ -75,14 +75,14 @@ Polymer({
onValueChange_: function(event) {
if (!this.propertyDict)
return;
- var key = event.target.id;
- var curValue = this.get(key, this.propertyDict);
+ const key = event.target.id;
+ let curValue = this.get(key, this.propertyDict);
if (typeof curValue == 'object' && !Array.isArray(curValue)) {
// Extract the property from an ONC managed dictionary.
curValue = CrOnc.getActiveValue(
/** @type {!CrOnc.ManagedProperty} */ (curValue));
}
- var newValue = this.getValueFromEditField_(key, event.target.value);
+ const newValue = this.getValueFromEditField_(key, event.target.value);
if (newValue == curValue)
return;
this.fire('property-change', {field: key, value: newValue});
@@ -95,15 +95,15 @@ Polymer({
* @private
*/
getPropertyLabel_: function(key, prefix) {
- var oncKey = 'Onc' + prefix + key;
+ let oncKey = 'Onc' + prefix + key;
oncKey = oncKey.replace(/\./g, '-');
if (this.i18nExists(oncKey))
return this.i18n(oncKey);
// We do not provide translations for every possible network property key.
// For keys specific to a type, strip the type prefix.
- var result = prefix + key;
- for (var entry in chrome.networkingPrivate.NetworkType) {
- var type = chrome.networkingPrivate.NetworkType[entry];
+ let result = prefix + key;
+ for (const entry in chrome.networkingPrivate.NetworkType) {
+ const type = chrome.networkingPrivate.NetworkType[entry];
if (result.startsWith(type + '.')) {
result = result.substr(type.length + 1);
break;
@@ -123,7 +123,7 @@ Polymer({
return key => {
if (editFieldTypes.hasOwnProperty(key))
return true;
- var value = this.getPropertyValue_(key, prefix, propertyDict);
+ const value = this.getPropertyValue_(key, prefix, propertyDict);
return value !== undefined && value !== '';
};
},
@@ -135,12 +135,12 @@ Polymer({
* @private
*/
isPropertyEditable_: function(key, propertyDict) {
- var property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
+ const property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
this.get(key, propertyDict));
if (property === undefined) {
// Unspecified properties in policy configurations are not user
// modifiable. https://crbug.com/819837.
- var source = propertyDict.Source;
+ const source = propertyDict.Source;
return source != 'UserPolicy' && source != 'DevicePolicy';
}
return !this.isNetworkPolicyEnforced(property);
@@ -153,7 +153,7 @@ Polymer({
* @private
*/
isEditType_: function(key, editFieldTypes) {
- var editType = editFieldTypes[key];
+ const editType = editFieldTypes[key];
return editType == 'String' || editType == 'StringArray' ||
editType == 'Password';
},
@@ -198,7 +198,7 @@ Polymer({
* @private
*/
getProperty_: function(key, propertyDict) {
- var property = this.get(key, propertyDict);
+ const property = this.get(key, propertyDict);
if (property === undefined && propertyDict.Source) {
// Provide an empty property object with the network policy source.
// See https://crbug.com/819837 for more info.
@@ -215,7 +215,7 @@ Polymer({
* @private
*/
getPropertyValue_: function(key, prefix, propertyDict) {
- var value = this.get(key, propertyDict);
+ let value = this.get(key, propertyDict);
if (value === undefined)
return '';
if (typeof value == 'object' && !Array.isArray(value)) {
@@ -226,15 +226,15 @@ Polymer({
if (Array.isArray(value))
return value.join(', ');
- var customValue = this.getCustomPropertyValue_(key, value);
+ const customValue = this.getCustomPropertyValue_(key, value);
if (customValue)
return customValue;
if (typeof value == 'number' || typeof value == 'boolean')
return value.toString();
assert(typeof value == 'string');
- var valueStr = /** @type {string} */ (value);
- var oncKey = 'Onc' + prefix + key;
+ const valueStr = /** @type {string} */ (value);
+ let oncKey = 'Onc' + prefix + key;
oncKey = oncKey.replace(/\./g, '-');
oncKey += '_' + valueStr;
if (this.i18nExists(oncKey))
@@ -250,7 +250,7 @@ Polymer({
* @private
*/
getValueFromEditField_(key, fieldValue) {
- var editType = this.editFieldTypes[key];
+ const editType = this.editFieldTypes[key];
if (editType == 'StringArray')
return fieldValue.toString().split(/, */);
return fieldValue;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
index c827a0ddfe5..f5ca74c1d59 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy.js
@@ -150,12 +150,12 @@ Polymer({
return;
/** @type {!CrOnc.ProxySettings} */
- var proxy = this.createDefaultProxySettings_();
+ const proxy = this.createDefaultProxySettings_();
// For shared networks with unmanaged proxy settings, ignore any saved
// proxy settings (use the default values).
if (this.isShared_()) {
- var property = this.getProxySettingsTypeProperty_();
+ const property = this.getProxySettingsTypeProperty_();
if (!this.isControlled(property) && !this.useSharedProxies) {
this.setProxyAsync_(proxy);
return; // Proxy settings will be ignored.
@@ -163,30 +163,29 @@ Polymer({
}
/** @type {!chrome.networkingPrivate.ManagedProxySettings|undefined} */
- var proxySettings = this.networkProperties.ProxySettings;
+ const proxySettings = this.networkProperties.ProxySettings;
if (proxySettings) {
proxy.Type = /** @type {!CrOnc.ProxySettingsType} */ (
CrOnc.getActiveValue(proxySettings.Type));
if (proxySettings.Manual) {
- proxy.Manual.HTTPProxy = /** @type {!CrOnc.ProxyLocation|undefined} */ (
- CrOnc.getSimpleActiveProperties(
- proxySettings.Manual.HTTPProxy)) ||
+ proxy.Manual.HTTPProxy =
+ /** @type {!CrOnc.ProxyLocation|undefined} */ (
+ CrOnc.getActiveProperties(proxySettings.Manual.HTTPProxy)) ||
{Host: '', Port: 80};
proxy.Manual.SecureHTTPProxy =
/** @type {!CrOnc.ProxyLocation|undefined} */ (
- CrOnc.getSimpleActiveProperties(
+ CrOnc.getActiveProperties(
proxySettings.Manual.SecureHTTPProxy)) ||
{Host: '', Port: 80};
proxy.Manual.FTPProxy =
/** @type {!CrOnc.ProxyLocation|undefined} */ (
- CrOnc.getSimpleActiveProperties(
- proxySettings.Manual.FTPProxy)) ||
+ CrOnc.getActiveProperties(proxySettings.Manual.FTPProxy)) ||
{Host: '', Port: 80};
proxy.Manual.SOCKS =
/** @type {!CrOnc.ProxyLocation|undefined} */ (
- CrOnc.getSimpleActiveProperties(proxySettings.Manual.SOCKS)) ||
+ CrOnc.getActiveProperties(proxySettings.Manual.SOCKS)) ||
{Host: '', Port: 80};
- var jsonHttp = proxy.Manual.HTTPProxy;
+ const jsonHttp = proxy.Manual.HTTPProxy;
this.useSameProxy_ =
(CrOnc.proxyMatches(jsonHttp, proxy.Manual.SecureHTTPProxy) &&
CrOnc.proxyMatches(jsonHttp, proxy.Manual.FTPProxy) &&
@@ -207,7 +206,7 @@ Polymer({
proxy.Manual = proxy.Manual || this.savedManual_;
// Set the Web Proxy Auto Discovery URL.
- var ipv4 =
+ const ipv4 =
CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4);
this.WPAD_ = (ipv4 && ipv4.WebProxyAutoDiscoveryUrl) ||
this.i18n('networkProxyWpadNone');
@@ -255,11 +254,11 @@ Polymer({
* @private
*/
sendProxyChange_: function() {
- var proxy =
+ const proxy =
/** @type {!CrOnc.ProxySettings} */ (Object.assign({}, this.proxy_));
if (proxy.Type == CrOnc.ProxySettingsType.MANUAL) {
- var manual = proxy.Manual;
- var defaultProxy = manual.HTTPProxy || {Host: '', Port: 80};
+ const manual = proxy.Manual;
+ const defaultProxy = manual.HTTPProxy || {Host: '', Port: 80};
if (this.useSameProxy_) {
proxy.Manual.SecureHTTPProxy = /** @type {!CrOnc.ProxyLocation} */ (
Object.assign({}, defaultProxy));
@@ -294,12 +293,12 @@ Polymer({
* @private
*/
onTypeChange_: function(event) {
- var target = /** @type {!HTMLSelectElement} */ (event.target);
- var type = /** @type {chrome.networkingPrivate.ProxySettingsType} */ (
+ const target = /** @type {!HTMLSelectElement} */ (event.target);
+ const type = /** @type {chrome.networkingPrivate.ProxySettingsType} */ (
target.value);
this.set('proxy_.Type', type);
- var proxyTypeChangeIsReady;
- var elementToFocus;
+ let proxyTypeChangeIsReady;
+ let elementToFocus;
switch (type) {
case CrOnc.ProxySettingsType.DIRECT:
case CrOnc.ProxySettingsType.WPAD:
@@ -347,7 +346,7 @@ Polymer({
/** @private */
onAddProxyExclusionTap_: function() {
- var value = this.$.proxyExclusion.value;
+ const value = this.$.proxyExclusion.value;
if (!value)
return;
this.push('proxy_.ExcludeDomains', value);
@@ -415,7 +414,7 @@ Polymer({
return false;
if (!this.networkProperties.hasOwnProperty('ProxySettings'))
return true; // No proxy settings defined, so not enforced.
- var property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
+ const property = /** @type {!CrOnc.ManagedProperty|undefined} */ (
this.get('ProxySettings.' + propertyName, this.networkProperties));
if (!property)
return true;
@@ -448,8 +447,8 @@ Polymer({
isSaveManualProxyEnabled_: function() {
if (!this.proxyIsUserModified_)
return false;
- var manual = this.proxy_.Manual;
- var httpHost = this.get('HTTPProxy.Host', manual);
+ const manual = this.proxy_.Manual;
+ const httpHost = this.get('HTTPProxy.Host', manual);
if (this.useSameProxy_)
return !!httpHost;
return !!httpHost || !!this.get('SecureHTTPProxy.Host', manual) ||
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.js
index 347b22980d3..fe55fb38fec 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_exclusions.js
@@ -38,7 +38,7 @@ Polymer({
* @private
*/
onRemoveTap_: function(event) {
- var index = event.model.index;
+ const index = event.model.index;
this.splice('exclusions', index, 1);
this.fire('proxy-change');
}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js
index 4f22091bdd6..6dc6323608e 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_proxy_input.js
@@ -52,7 +52,7 @@ Polymer({
* @private
*/
onValueChange_: function() {
- var port = parseInt(this.value.Port, 10);
+ let port = parseInt(this.value.Port, 10);
if (isNaN(port))
port = 80;
this.value.Port = port;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
index 9b8016669f5..01be1577af9 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
@@ -95,7 +95,8 @@
<div slot="title">[[i18n('networkSimEnterPinTitle')]]</div>
<div slot="body">
<network-password-input id="enterPin" value="{{pin_}}"
- label="[[i18n('networkSimEnterPin')]]" on-enter="sendEnterPin_">
+ label="[[i18n('networkSimEnterPin')]]" on-enter="sendEnterPin_"
+ disabled="[[inProgress_]]">
</network-password-input>
<div class="dialog-error">
[[getErrorMsg_(error_, networkProperties)]]
@@ -118,14 +119,16 @@
<div slot="title">[[i18n('networkSimChangePinTitle')]]</div>
<div slot="body">
<network-password-input id="changePinOld" value="{{pin_}}"
- label="[[i18n('networkSimEnterOldPin')]]">
+ label="[[i18n('networkSimEnterOldPin')]]"
+ disabled="[[inProgress_]]">
</network-password-input>
<network-password-input id="changePinNew1" value="{{pin_new1_}}"
- label="[[i18n('networkSimEnterNewPin')]]">
+ label="[[i18n('networkSimEnterNewPin')]]"
+ disabled="[[inProgress_]]">
</network-password-input>
<network-password-input id="changePinNew2" value="{{pin_new2_}}"
label="[[i18n('networkSimReEnterNewPin')]]"
- on-enter="sendChangePin_">
+ on-enter="sendChangePin_" disabled="[[inProgress_]]">
</network-password-input>
<div class="dialog-error">
[[getErrorMsg_(error_, networkProperties)]]
@@ -148,7 +151,8 @@
<div slot="title">[[i18n('networkSimLockedTitle')]]</div>
<div slot="body">
<network-password-input id="unlockPin" value="{{pin_}}"
- label="[[i18n('networkSimEnterPin')]]" on-enter="sendUnlockPin_">
+ label="[[i18n('networkSimEnterPin')]]" on-enter="sendUnlockPin_"
+ disabled="[[inProgress_]]">
</network-password-input>
<div class="dialog-error">
[[getErrorMsg_(error_, networkProperties)]]
@@ -174,14 +178,16 @@
Enter the 8-digit PIN Unblocking Key provided by your carrier
</div>
<network-password-input id="unlockPuk" value="{{puk_}}"
- label="[[i18n('networkSimEnterPuk')]]">
+ label="[[i18n('networkSimEnterPuk')]]"
+ disabled="[[inProgress_]]">
</network-password-input>
<network-password-input id="unlockPin1" value="{{pin_new1_}}"
- label="[[i18n('networkSimEnterNewPin')]]">
+ label="[[i18n('networkSimEnterNewPin')]]"
+ disabled="[[inProgress_]]">
</network-password-input>
<network-password-input id="unlockPin2" value="{{pin_new2_}}"
label="[[i18n('networkSimReEnterNewPin')]]"
- on-enter="sendUnlockPuk_">
+ on-enter="sendUnlockPuk_" disabled="[[inProgress_]]">
</network-password-input>
<div class="dialog-error">
[[i18n('networkSimLockedWarning')]]
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js
index 5962b8c49eb..4bc791255de 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js
@@ -7,7 +7,7 @@
*/
/** @enum {string} */
-var ErrorType = {
+const ErrorType = {
NONE: 'none',
INCORRECT_PIN: 'incorrect-pin',
INCORRECT_PUK: 'incorrect-puk',
@@ -18,9 +18,9 @@ var ErrorType = {
(function() {
-var PIN_MIN_LENGTH = 4;
-var PUK_MIN_LENGTH = 8;
-var TOGGLE_DEBOUNCE_MS = 500;
+const PIN_MIN_LENGTH = 4;
+const PUK_MIN_LENGTH = 8;
+const TOGGLE_DEBOUNCE_MS = 500;
Polymer({
is: 'network-siminfo',
@@ -161,10 +161,10 @@ Polymer({
networkPropertiesChanged_: function() {
if (!this.networkProperties || !this.networkProperties.Cellular)
return;
- var simLockStatus = this.networkProperties.Cellular.SIMLockStatus;
+ const simLockStatus = this.networkProperties.Cellular.SIMLockStatus;
this.pukRequired_ =
!!simLockStatus && simLockStatus.LockType == CrOnc.LockType.PUK;
- var lockEnabled = !!simLockStatus && simLockStatus.LockEnabled;
+ const lockEnabled = !!simLockStatus && simLockStatus.LockEnabled;
if (lockEnabled != this.lockEnabled_) {
this.setLockEnabled_ = lockEnabled;
this.updateLockEnabled_();
@@ -223,7 +223,7 @@ Polymer({
// If the PUK was activated while attempting to enter or change a pin,
// close the dialog and open the unlock PUK dialog.
- var showUnlockPuk = false;
+ let showUnlockPuk = false;
if (this.$.enterPinDialog.open) {
this.$.enterPinDialog.close();
showUnlockPuk = true;
@@ -271,7 +271,7 @@ Polymer({
* @private
*/
setCellularSimState_: function(simState) {
- var guid = (this.networkProperties && this.networkProperties.GUID) || '';
+ const guid = (this.networkProperties && this.networkProperties.GUID) || '';
this.setInProgress_();
this.networkingPrivate.setCellularSimState(guid, simState, () => {
this.inProgress_ = false;
@@ -292,7 +292,7 @@ Polymer({
* @private
*/
unlockCellularSim_: function(pin, puk) {
- var guid = (this.networkProperties && this.networkProperties.GUID) || '';
+ const guid = (this.networkProperties && this.networkProperties.GUID) || '';
this.setInProgress_();
this.networkingPrivate.unlockCellularSim(guid, pin, puk, () => {
this.inProgress_ = false;
@@ -316,10 +316,10 @@ Polymer({
event.stopPropagation();
if (!this.enterPinEnabled_)
return;
- var pin = this.$.enterPin.value;
+ const pin = this.$.enterPin.value;
if (!this.validatePin_(pin))
return;
- var simState = /** @type {!CrOnc.CellularSimState} */ ({
+ const simState = /** @type {!CrOnc.CellularSimState} */ ({
currentPin: pin,
requirePin: this.sendSimLockEnabled_,
});
@@ -352,10 +352,10 @@ Polymer({
*/
sendChangePin_: function(event) {
event.stopPropagation();
- var newPin = this.$.changePinNew1.value;
+ const newPin = this.$.changePinNew1.value;
if (!this.validatePin_(newPin, this.$.changePinNew2.value))
return;
- var simState = /** @type {!CrOnc.CellularSimState} */ ({
+ const simState = /** @type {!CrOnc.CellularSimState} */ ({
requirePin: true,
currentPin: this.$.changePinOld.value,
newPin: newPin
@@ -384,7 +384,7 @@ Polymer({
*/
sendUnlockPin_: function(event) {
event.stopPropagation();
- var pin = this.$.unlockPin.value;
+ const pin = this.$.unlockPin.value;
if (!this.validatePin_(pin))
return;
this.unlockCellularSim_(pin, '');
@@ -419,10 +419,10 @@ Polymer({
*/
sendUnlockPuk_: function(event) {
event.stopPropagation();
- var puk = this.$.unlockPuk.value;
+ const puk = this.$.unlockPuk.value;
if (!this.validatePuk_(puk))
return;
- var pin = this.$.unlockPin1.value;
+ const pin = this.$.unlockPin1.value;
if (!this.validatePin_(pin, this.$.unlockPin2.value))
return;
this.unlockCellularSim_(pin, puk);
@@ -457,7 +457,7 @@ Polymer({
if (this.error_ == ErrorType.NONE)
return '';
// TODO(stevenjb): Translate
- var msg;
+ let msg;
if (this.error_ == ErrorType.INCORRECT_PIN)
msg = 'Incorrect PIN.';
else if (this.error_ == ErrorType.INCORRECT_PUK)
@@ -470,7 +470,7 @@ Polymer({
msg = 'Invalid PUK.';
else
return 'UNKNOWN ERROR';
- var retriesLeft = this.simUnlockSent_ &&
+ const retriesLeft = this.simUnlockSent_ &&
this.get('Cellular.SIMLockStatus.RetriesLeft', this.networkProperties);
if (retriesLeft) {
msg += ' Retries left: ' + retriesLeft.toString();
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/OWNERS b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/OWNERS
new file mode 100644
index 00000000000..eb15f51e9ca
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/OWNERS
@@ -0,0 +1,5 @@
+alemate@chromium.org
+jdufault@chromium.org
+stevenjb@chromium.org
+
+# COMPONENT: UI>Settings
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
index 080f3cc0328..f4e00640a40 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
@@ -160,7 +160,7 @@
--cr-input-error-display: none;
--cr-input-input: {
font-size: 28px;
- letter-spacing: 28px;
+ letter-spacing: 18px;
};
--cr-input-padding-bottom: 1px;
--cr-input-padding-end: 0;
@@ -282,13 +282,15 @@
<paper-icon-button id="backspaceButton" class="digit-button"
disabled$="[[!hasInput_(value)]]"
icon="pin-keyboard:backspace"
+ on-tap="onBackspaceTap_"
on-pointerdown="onBackspacePointerDown_"
on-pointerout="clearAndReset_"
on-pointerup="onBackspacePointerUp_"
title="[[i18n('pinKeyboardDeleteAccessibleName')]]"
noink>
</paper-icon-button>
- <paper-ripple class="circle" center></paper-ripple>
+ <paper-ripple class="circle" center hidden="[[!hasInput_(value)]]">
+ </paper-ripple>
</div>
</div>
</div>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js
index ceaaae8adca..b208704a59f 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js
@@ -220,11 +220,11 @@ Polymer({
* @private
*/
onNumberTap_: function(event) {
- let numberValue = event.target.getAttribute('value');
+ const numberValue = event.target.getAttribute('value');
// Add the number where the caret is, then update the selection range of the
// input element.
- let selectionStart = this.selectionStart_;
+ const selectionStart = this.selectionStart_;
this.value = this.value.substring(0, this.selectionStart_) + numberValue +
this.value.substring(this.selectionEnd_);
@@ -277,6 +277,24 @@ Polymer({
},
/**
+ * Called when user taps the backspace the button. Only does something when
+ * the tap comes from the keyboard. onBackspacePointerDown_ and
+ * onBackspacePointerUp_ will handle the events if they come from mouse or
+ * touch. Note: This does not support repeatedly backspacing by holding down
+ * the space or enter key like touch or mouse does.
+ * @param {Event} event The event object.
+ * @private
+ */
+ onBackspaceTap_: function(event) {
+ if (!event.target.receivedFocusFromKeyboard)
+ return;
+
+ this.onPinClear_();
+ this.clearAndReset_();
+ event.stopImmediatePropagation();
+ },
+
+ /**
* Called when the user presses or touches the backspace button. Starts a
* timer which starts an interval to repeatedly backspace the pin value until
* the interval is cleared.
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.html b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.html
index 71e9a15fd8e..742a5c8d283 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.html
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.html
@@ -45,26 +45,30 @@ Where:
<dom-module id="setup-pin-keyboard">
<template>
<style include="settings-shared">
+ #errorIcon {
+ --iron-icon-height: 20px;
+ --iron-icon-width: 20px;
+ display: none;
+ }
+
.error {
color: var(--google-red-600);
}
- .error > iron-icon {
+ .error #errorIcon {
--iron-icon-fill-color: var(--google-red-600);
+ display: inline-block;
}
.warning {
color: var(--cr-secondary-text-color);
}
- .warning > iron-icon {
- --iron-icon-fill-color: var(--google-grey-refresh-700);
- }
-
#problemDiv {
align-items: center;
display: flex;
flex-direction: row;
+ font-size: 10px;
height: 32px;
min-height: 0;
}
@@ -74,10 +78,6 @@ Where:
#problemDiv[invisible] {
visibility: hidden;
}
-
- #problemMessage {
- font-size: 10px;
- }
</style>
<pin-keyboard id="pinKeyboard" on-pin-change="onPinChange_"
on-submit="onPinSubmit_" value="{{pinKeyboardValue_}}"
@@ -87,13 +87,11 @@ Where:
<!-- Warning/error; only shown if title is hidden. -->
<div id="problemDiv" class$="[[problemClass_]]"
invisible$="[[!problemMessageId_]]" problem>
- <div>
- <iron-icon icon="cr:error-outline"></iron-icon>
- <span id="problemMessage">
- [[formatProblemMessage_(locale, problemMessageId_,
- problemMessageParameters_)]]
- </span>
- </div>
+ <iron-icon id="errorIcon" icon="cr:error-outline"></iron-icon>
+ <span>
+ [[formatProblemMessage_(locale, problemMessageId_,
+ problemMessageParameters_)]]
+ </span>
</div>
</pin-keyboard>
</template>
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js
index 9dde5f4717f..12eaf15b7b2 100644
--- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js
+++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/setup_pin_keyboard.js
@@ -170,7 +170,8 @@ Polymer({
this.enableSubmit = false;
this.isConfirmStep = false;
this.hideProblem_();
- this.onPinChange_();
+ this.onPinChange_(
+ new CustomEvent('pin-change', {detail: {pin: this.pinKeyboardValue_}}));
},
/**
@@ -281,13 +282,16 @@ Polymer({
}
},
- /** @private */
- onPinChange_: function() {
+ /**
+ * @param {!CustomEvent} e Custom event containing the new pin.
+ * @private */
+ onPinChange_: function(e) {
+ const newPin = /** @type {{pin: string}} */ (e.detail).pin;
if (!this.isConfirmStep) {
- if (this.pinKeyboardValue_) {
+ if (newPin) {
this.quickUnlockPrivate.checkCredential(
- chrome.quickUnlockPrivate.QuickUnlockMode.PIN,
- this.pinKeyboardValue_, this.processPinProblems_.bind(this));
+ chrome.quickUnlockPrivate.QuickUnlockMode.PIN, newPin,
+ this.processPinProblems_.bind(this));
} else {
this.enableSubmit = false;
}
@@ -295,7 +299,7 @@ Polymer({
}
this.hideProblem_();
- this.enableSubmit = this.pinKeyboardValue_.length > 0;
+ this.enableSubmit = newPin.length > 0;
},
/** @private */
@@ -328,7 +332,8 @@ Polymer({
this.initialPin_ = this.pinKeyboardValue_;
this.pinKeyboardValue_ = '';
this.isConfirmStep = true;
- this.onPinChange_();
+ this.onPinChange_(new CustomEvent(
+ 'pin-change', {detail: {pin: this.pinKeyboardValue_}}));
this.$.pinKeyboard.focus();
this.writeUma(LockScreenProgress.ENTER_PIN);
return;
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn
new file mode 100644
index 00000000000..f8fdd29d7e7
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn
@@ -0,0 +1,30 @@
+# 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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+assert(is_chromeos, "SMB Shares is Chrome OS only.")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":add_smb_share_dialog",
+ ":smb_browser_proxy",
+ ]
+}
+
+js_library("smb_browser_proxy") {
+ deps = [
+ "//ui/webui/resources/js:cr",
+ ]
+}
+
+js_library("add_smb_share_dialog") {
+ deps = [
+ "//ui/webui/resources/cr_components/chromeos/smb_shares:smb_browser_proxy",
+ "//ui/webui/resources/cr_elements/cr_input:cr_input",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:i18n_behavior",
+ "//ui/webui/resources/js:web_ui_listener_behavior",
+ ]
+}
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/OWNERS b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/OWNERS
new file mode 100644
index 00000000000..704b95c8e4b
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/OWNERS
@@ -0,0 +1 @@
+khorimoto@chromium.org \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html
new file mode 100644
index 00000000000..7342022f0a8
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.html
@@ -0,0 +1,132 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/md_select_css.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="smb_browser_proxy.html">
+
+<dom-module id="add-smb-share-dialog">
+ <template>
+ <style include="md-select paper-button-style">
+ #dialog [slot=body] {
+ height: 350px;
+ }
+
+ .md-select {
+ width: 100%;
+ }
+
+ .label {
+ @apply --cr-form-field-label;
+ }
+
+ cr-input {
+ --cr-input-error-display: none;
+ }
+
+ cr-searchable-drop-down {
+ display: block;
+ --cr-searchable-drop-down-width: 472px;
+ }
+
+ .md-select,
+ cr-input:not(:last-child),
+ cr-searchable-drop-down {
+ margin-bottom: var(--cr-form-field-bottom-spacing);
+ }
+
+ cr-toast {
+ left: 0;
+ max-height: 78px;
+ max-width: 300px;
+ position: absolute;
+ right: 0;
+ }
+
+ paper-button {
+ position: relative;
+ top: 38px;
+ }
+
+ .error-message {
+ color: white;
+ font: 13px;
+ padding-bottom: 15px;
+ padding-top: 15px;
+ text-align: center;
+ white-space: normal;
+ }
+
+ [slot='button-container'] {
+ height: 78px;
+ justify-content: space-between;
+ }
+ </style>
+
+ <cr-dialog id="dialog">
+ <div slot="title">[[i18n('addSmbShare')]]</div>
+ <div slot="body" spellcheck="false">
+ <cr-searchable-drop-down id="address" label="[[i18n('smbShareUrl')]]"
+ value="{{mountUrl_}}" items="[[discoveredShares_]]"
+ placeholder="\\server\share" on-change="onURLChanged_"
+ update-value-on-input autofocus>
+ </cr-searchable-drop-down>
+ <cr-input id="name" label="[[i18n('smbShareName')]]"
+ value="{{mountName_}}" maxlength="64">
+ </cr-input>
+ <div id="authentication-method" hidden="[[!isActiveDirectory_]]">
+ <div id="authentication-label" class="label">
+ [[i18n('smbShareAuthenticationMethod')]]
+ </div>
+ <select class="md-select" aria-labelledby="authentication-label"
+ value="{{authenticationMethod_::change}}">
+ <option value="kerberos">
+ [[i18n('smbShareKerberosAuthentication')]]
+ </option>
+ <option value="credentials">
+ [[i18n('smbShareStandardAuthentication')]]
+ </option>
+ </select>
+ </div>
+ <div id="credentials"
+ hidden="[[!shouldShowCredentialUI_(authenticationMethod_)]]">
+ <cr-input id="username" label="[[i18n('smbShareUsername')]]"
+ value="{{username_}}">
+ </cr-input>
+ <cr-input id="password" type="password"
+ label="[[i18n('smbSharePassword')]]" value="{{password_}}">
+ </cr-input>
+ </div>
+ </div>
+ <div slot="button-container">
+ <!-- Error toast -->
+ <div>
+ <cr-toast id="errorToast" duration="3000">
+ <div class="error-message">
+ [[addShareResultText_]]
+ </div>
+ </cr-toast>
+ </div>
+ <!-- Buttons -->
+ <div>
+ <paper-button class="cancel-button" on-click="cancel_" id="cancel">
+ [[i18n('cancel')]]
+ </paper-button>
+ <paper-button class="action-button" on-click="onAddButtonTap_"
+ disabled="[[!canAddShare_(mountUrl_, inProgress_)]]">
+ [[i18n('add')]]
+ </paper-button>
+ </div>
+ </div>
+ </cr-dialog>
+ </template>
+ <script src="add_smb_share_dialog.js"></script>
+</dom-module>
+
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
new file mode 100644
index 00000000000..a309717b357
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
@@ -0,0 +1,180 @@
+// 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.
+
+/**
+ * @fileoverview 'add-smb-share-dialog' is a component for adding an SMB Share.
+ */
+
+Polymer({
+ is: 'add-smb-share-dialog',
+
+ behaviors: [I18nBehavior, WebUIListenerBehavior],
+
+ properties: {
+ lastUrl: {
+ type: String,
+ value: '',
+ },
+
+ /** @private {string} */
+ mountUrl_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private {string} */
+ mountName_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private {string} */
+ username_: {
+ type: String,
+ value: '',
+ },
+
+ /** @private {string} */
+ password_: {
+ type: String,
+ value: '',
+ },
+ /** @private {!Array<string>}*/
+ discoveredShares_: {
+ type: Array,
+ value: function() {
+ return [];
+ },
+ },
+
+ /** @private */
+ isActiveDirectory_: {
+ type: Boolean,
+ value: function() {
+ return loadTimeData.getBoolean('isActiveDirectoryUser');
+ },
+ },
+
+ /** @private */
+ authenticationMethod_: {
+ type: String,
+ value: function() {
+ return loadTimeData.getBoolean('isActiveDirectoryUser') ?
+ SmbAuthMethod.KERBEROS :
+ SmbAuthMethod.CREDENTIALS;
+ },
+ },
+
+ /** @private */
+ addShareResultText_: String,
+
+ /** @private */
+ inProgress_: {
+ type: Boolean,
+ value: false,
+ }
+ },
+
+ /** @private {?smb_shares.SmbBrowserProxy} */
+ browserProxy_: null,
+
+ /** @override */
+ created: function() {
+ this.browserProxy_ = smb_shares.SmbBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ attached: function() {
+ this.browserProxy_.startDiscovery();
+ this.$.dialog.showModal();
+
+ this.addWebUIListener('on-shares-found', this.onSharesFound_.bind(this));
+ this.mountUrl_ = this.lastUrl;
+ },
+
+ /** @private */
+ cancel_: function() {
+ this.$.dialog.cancel();
+ },
+
+ /** @private */
+ onAddButtonTap_: function() {
+ this.inProgress_ = true;
+ this.browserProxy_
+ .smbMount(
+ this.mountUrl_, this.mountName_.trim(), this.username_,
+ this.password_, this.authenticationMethod_)
+ .then(result => {
+ this.onAddShare_(result);
+ });
+ },
+
+ /** @private */
+ onURLChanged_: function() {
+ const parts = this.mountUrl_.split('\\');
+ this.mountName_ = parts[parts.length - 1];
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ canAddShare_: function() {
+ return !!this.mountUrl_ && !this.inProgress_;
+ },
+
+ /**
+ * @param {!Array<string>} shares
+ * @private
+ */
+ onSharesFound_: function(shares) {
+ this.discoveredShares_ = this.discoveredShares_.concat(shares);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowCredentialUI_: function() {
+ return this.authenticationMethod_ == SmbAuthMethod.CREDENTIALS;
+ },
+
+ /**
+ * @param {SmbMountResult} result
+ * @private
+ */
+ onAddShare_: function(result) {
+ this.inProgress_ = false;
+ switch (result) {
+ case SmbMountResult.SUCCESS:
+ this.$.dialog.close();
+ break;
+ case SmbMountResult.AUTHENTICATION_FAILED:
+ this.addShareResultText_ =
+ loadTimeData.getString('smbShareAddedAuthFailedMessage');
+ break;
+ case SmbMountResult.NOT_FOUND:
+ this.addShareResultText_ =
+ loadTimeData.getString('smbShareAddedNotFoundMessage');
+ break;
+ case SmbMountResult.UNSUPPORTED_DEVICE:
+ this.addShareResultText_ =
+ loadTimeData.getString('smbShareAddedUnsupportedDeviceMessage');
+ break;
+ case SmbMountResult.MOUNT_EXISTS:
+ this.addShareResultText_ =
+ loadTimeData.getString('smbShareAddedMountExistsMessage');
+ break;
+ case SmbMountResult.INVALID_URL:
+ this.addShareResultText_ =
+ loadTimeData.getString('smbShareAddedInvalidURLMessage');
+ break;
+ default:
+ this.addShareResultText_ =
+ loadTimeData.getString('smbShareAddedErrorMessage');
+ }
+ this.$.errorToast.show();
+ },
+
+});
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.html b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.html
new file mode 100644
index 00000000000..2d494727081
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="smb_browser_proxy.js"> </script> \ No newline at end of file
diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.js b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.js
new file mode 100644
index 00000000000..7d345fbe013
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/smb_browser_proxy.js
@@ -0,0 +1,79 @@
+// 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.
+
+/**
+ * @fileoverview A helper object used from the "add SMB share" dialog to
+ * interact with the browser. Used only on Chrome OS.
+ */
+
+/**
+ * @enum {number}
+ * These values must be kept in sync with the SmbMountResult enum in
+ * chrome/browser/chromeos/smb_client/smb_service.h.
+ */
+const SmbMountResult = {
+ SUCCESS: 0,
+ UNKNOWN_FAILURE: 1,
+ AUTHENTICATION_FAILED: 2,
+ NOT_FOUND: 3,
+ UNSUPPORTED_DEVICE: 4,
+ MOUNT_EXISTS: 5,
+ INVALID_URL: 6,
+ INVALID_OPERATION: 7,
+ DBUS_PARSE_FAILED: 8,
+ OUT_OF_MEMORY: 9,
+ ABORTED: 10,
+ IO_ERROR: 11,
+ TOO_MANY_OPENED: 12,
+};
+
+/** @enum {string} */
+const SmbAuthMethod = {
+ KERBEROS: 'kerberos',
+ CREDENTIALS: 'credentials',
+};
+
+cr.define('smb_shares', function() {
+ /** @interface */
+ class SmbBrowserProxy {
+ /**
+ * Attempts to mount an Smb filesystem with the provided url.
+ * @param {string} smbUrl File Share URL.
+ * @param {string} smbName Display name for the File Share.
+ * @param {string} username
+ * @param {string} password
+ * @param {string} authMethod
+ * @return {!Promise<SmbMountResult>}
+ */
+ smbMount(smbUrl, smbName, username, password, authMethod) {}
+
+ /**
+ * Starts the file share discovery process.
+ */
+ startDiscovery() {}
+ }
+
+ /** @implements {smb_shares.SmbBrowserProxy} */
+ class SmbBrowserProxyImpl {
+ /** @override */
+ smbMount(smbUrl, smbName, username, password, authMethod) {
+ return cr.sendWithPromise(
+ 'smbMount', smbUrl, smbName, username, password,
+ authMethod == SmbAuthMethod.KERBEROS);
+ }
+
+ /** @override */
+ startDiscovery() {
+ chrome.send('startDiscovery');
+ }
+ }
+
+ cr.addSingletonGetter(SmbBrowserProxyImpl);
+
+ return {
+ SmbBrowserProxy: SmbBrowserProxy,
+ SmbBrowserProxyImpl: SmbBrowserProxyImpl,
+ };
+
+});
diff --git a/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp b/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp
index 3bf1f1cdd56..2c978f4adc1 100644
--- a/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp
+++ b/chromium/ui/webui/resources/cr_components/cr_components_resources.grdp
@@ -131,6 +131,22 @@
file="cr_components/chromeos/network/network_config.js"
type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_ELEMENT_BEHAVIOR_HTML"
+ file="cr_components/chromeos/network/network_config_element_behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_ELEMENT_BEHAVIOR_JS"
+ file="cr_components/chromeos/network/network_config_element_behavior.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_INPUT_HTML"
+ file="cr_components/chromeos/network/network_config_input.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_INPUT_JS"
+ file="cr_components/chromeos/network/network_config_input.js"
+ type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_SELECT_HTML"
file="cr_components/chromeos/network/network_config_select.html"
type="chrome_html"
@@ -139,6 +155,14 @@
file="cr_components/chromeos/network/network_config_select.js"
type="chrome_html"
compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_TOGGLE_HTML"
+ file="cr_components/chromeos/network/network_config_toggle.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_NETWORK_CONFIG_TOGGLE_JS"
+ file="cr_components/chromeos/network/network_config_toggle.js"
+ type="chrome_html"
+ compress="gzip" />
<structure name="IDR_WEBUI_CHROMEOS_NETWORK_IP_CONFIG_HTML"
file="cr_components/chromeos/network/network_ip_config.html"
type="chrome_html"
@@ -340,5 +364,23 @@
file="cr_components/chromeos/multidevice_setup/ui_page.js"
type="chrome_html"
compress="gzip" />
+
+ <!-- Shared between settings and add new share flow. -->
+ <structure name="IDR_WEBUI_CHROMEOS_SMB_SHARES_SMB_BROWSER_PROXY_HTML"
+ file="cr_components/chromeos/smb_shares/smb_browser_proxy.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_SMB_SHARES_SMB_BROWSER_PROXY_JS"
+ file="cr_components/chromeos/smb_shares/smb_browser_proxy.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_SMB_SHARES_ADD_SMB_SHARE_DIALOG_HTML"
+ file="cr_components/chromeos/smb_shares/add_smb_share_dialog.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_WEBUI_CHROMEOS_SMB_SHARES_ADD_SMB_SHARE_DIALOG_JS"
+ file="cr_components/chromeos/smb_shares/add_smb_share_dialog.js"
+ type="chrome_html"
+ compress="gzip" />
</if>
</grit-part>
diff --git a/chromium/ui/webui/resources/cr_elements/.eslintrc.js b/chromium/ui/webui/resources/cr_elements/.eslintrc.js
new file mode 100644
index 00000000000..25e21f992eb
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/.eslintrc.js
@@ -0,0 +1,13 @@
+// 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.
+
+module.exports = {
+ 'env': {
+ 'browser': true,
+ 'es6': true,
+ },
+ 'rules': {
+ 'no-var': 'error',
+ },
+};
diff --git a/chromium/ui/webui/resources/cr_elements/BUILD.gn b/chromium/ui/webui/resources/cr_elements/BUILD.gn
index 9927b6e60e8..5d09ab60ec3 100644
--- a/chromium/ui/webui/resources/cr_elements/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/BUILD.gn
@@ -18,6 +18,7 @@ group("closure_compile") {
"cr_link_row:closure_compile",
"cr_profile_avatar_selector:closure_compile",
"cr_radio_button:closure_compile",
+ "cr_radio_group:closure_compile",
"cr_searchable_drop_down:closure_compile",
"cr_slider:closure_compile",
"cr_toast:closure_compile",
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js
index 79a96c0b038..50e7eabd04b 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js
@@ -13,19 +13,22 @@
* Dimensions for camera capture.
* @const
*/
-var CAPTURE_SIZE = {width: 576, height: 576};
+const CAPTURE_SIZE = {
+ width: 576,
+ height: 576
+};
/**
* Interval between frames for camera capture (milliseconds).
* @const
*/
-var CAPTURE_INTERVAL_MS = 1000 / 10;
+const CAPTURE_INTERVAL_MS = 1000 / 10;
/**
* Duration of camera capture (milliseconds).
* @const
*/
-var CAPTURE_DURATION_MS = 1000;
+const CAPTURE_DURATION_MS = 1000;
Polymer({
is: 'cr-camera',
@@ -104,14 +107,14 @@ Polymer({
this.cameraCaptureInProgress_ = true;
/** Pre-allocate all frames needed for capture. */
- var frames = [];
+ const frames = [];
if (this.videomode) {
/** Reduce capture size when in video mode. */
- var captureSize = {
+ const captureSize = {
width: CAPTURE_SIZE.width / 2,
height: CAPTURE_SIZE.height / 2
};
- var captureFrameCount = CAPTURE_DURATION_MS / CAPTURE_INTERVAL_MS;
+ const captureFrameCount = CAPTURE_DURATION_MS / CAPTURE_INTERVAL_MS;
while (frames.length < captureFrameCount)
frames.push(this.allocateFrame_(captureSize));
} else {
@@ -119,10 +122,10 @@ Polymer({
}
/** Start capturing frames at an interval. */
- var capturedFrames = [];
+ const capturedFrames = [];
this.$.userImageStreamCrop.classList.remove('preview');
this.$.userImageStreamCrop.classList.add('capture');
- var interval = setInterval(() => {
+ const interval = setInterval(() => {
/** Stop capturing frames when all allocated frames have been consumed. */
if (frames.length) {
capturedFrames.push(
@@ -143,7 +146,7 @@ Polymer({
this.stopCamera();
this.cameraStartInProgress_ = true;
- var successCallback = function(stream) {
+ const successCallback = function(stream) {
if (this.cameraStartInProgress_) {
this.$.cameraVideo.srcObject = stream;
this.cameraStream_ = stream;
@@ -153,12 +156,12 @@ Polymer({
this.cameraStartInProgress_ = false;
}.bind(this);
- var errorCallback = function() {
+ const errorCallback = function() {
this.cameraOnline_ = false;
this.cameraStartInProgress_ = false;
}.bind(this);
- var videoConstraints = {
+ const videoConstraints = {
width: {ideal: CAPTURE_SIZE.width},
height: {ideal: CAPTURE_SIZE.height},
};
@@ -185,8 +188,8 @@ Polymer({
* @private
*/
stopVideoTracks_: function(stream) {
- var tracks = stream.getVideoTracks();
- for (var i = 0; i < tracks.length; i++)
+ const tracks = stream.getVideoTracks();
+ for (let i = 0; i < tracks.length; i++)
tracks[i].stop();
},
@@ -206,11 +209,11 @@ Polymer({
* @private
*/
allocateFrame_: function(size) {
- var canvas =
+ const canvas =
/** @type {!HTMLCanvasElement} */ (document.createElement('canvas'));
canvas.width = size.width;
canvas.height = size.height;
- var ctx = /** @type {!CanvasRenderingContext2D} */ (
+ const ctx = /** @type {!CanvasRenderingContext2D} */ (
canvas.getContext('2d', {alpha: false}));
// Flip frame horizontally.
ctx.translate(size.width, 0);
@@ -227,16 +230,16 @@ Polymer({
* @private
*/
captureFrame_: function(video, canvas) {
- var ctx =
+ const ctx =
/** @type {!CanvasRenderingContext2D} */ (
canvas.getContext('2d', {alpha: false}));
- var width = video.videoWidth;
- var height = video.videoHeight;
+ const width = video.videoWidth;
+ const height = video.videoHeight;
if (width < canvas.width || height < canvas.height) {
console.error(
'Video capture size too small: ' + width + 'x' + height + '!');
}
- var src = {};
+ const src = {};
if (width / canvas.width > height / canvas.height) {
// Full height, crop left/right.
src.height = height;
@@ -262,7 +265,7 @@ Polymer({
*/
convertFramesToPng_: function(frames) {
/** Encode captured frames. */
- var encodedImages = frames.map(function(frame) {
+ const encodedImages = frames.map(function(frame) {
return frame.toDataURL('image/png');
});
@@ -271,7 +274,7 @@ Polymer({
return encodedImages[0];
/** Create forward/backward image sequence. */
- var forwardBackwardImageSequence =
+ const forwardBackwardImageSequence =
encodedImages.concat(encodedImages.slice(1, -1).reverse());
/** Convert image sequence to animated PNG. */
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js
index 174a48a25c8..2187d436ead 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js
@@ -128,7 +128,7 @@ Polymer({
* @param {string} imageUrl
*/
setSelectedImageUrl(imageUrl) {
- var image = this.$.selector.items.find(function(image) {
+ const image = this.$.selector.items.find(function(image) {
return image.dataset.url == imageUrl;
});
if (image) {
@@ -193,9 +193,9 @@ Polymer({
if (!this.selectedItem)
return;
- var selector = /** @type {IronSelectorElement} */ (this.$.selector);
- var prevSelected = this.selectedItem;
- var activate = false;
+ const selector = /** @type {IronSelectorElement} */ (this.$.selector);
+ const prevSelected = this.selectedItem;
+ let activate = false;
switch (e.detail.key) {
case 'enter':
case 'space':
@@ -244,9 +244,9 @@ Polymer({
* @private
*/
onIronActivate_: function(event) {
- var type = event.detail.item.dataset.type;
+ const type = event.detail.item.dataset.type;
// Don't change focus when activating the camera via mouse.
- var activate = type != CrPicture.SelectionTypes.CAMERA;
+ const activate = type != CrPicture.SelectionTypes.CAMERA;
this.selectImage_(event.detail.item, activate);
},
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js
index c7a869d8f2c..37b3f654ac4 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js
@@ -63,7 +63,7 @@ Polymer({
* event when the photo is completed.
*/
takePhoto: function() {
- var camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
+ const camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
if (camera)
camera.takePhoto();
},
@@ -87,7 +87,7 @@ Polymer({
/** @private */
cameraActiveChanged_: function() {
- var camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
+ const camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
if (!camera)
return; // Camera will be started when attached.
if (this.cameraActive_)
@@ -109,13 +109,13 @@ Polymer({
* Data URLs for PNG images can be large. Create an object URL to avoid
* URL length limits.
*/
- var image = /** @type {!HTMLImageElement} */ (this.$$('#image'));
+ const image = /** @type {!HTMLImageElement} */ (this.$$('#image'));
if (this.imageSrc.startsWith('data:image/png')) {
- var byteString = atob(this.imageSrc.split(',')[1]);
- var bytes = new Uint8Array(byteString.length);
- for (var i = 0; i < byteString.length; i++)
+ const byteString = atob(this.imageSrc.split(',')[1]);
+ const bytes = new Uint8Array(byteString.length);
+ for (let i = 0; i < byteString.length; i++)
bytes[i] = byteString.charCodeAt(i);
- var blob = new Blob([bytes], {'type': 'image/png'});
+ const blob = new Blob([bytes], {'type': 'image/png'});
// Use first frame as placeholder while rest of image loads.
image.style.backgroundImage = 'url(' +
CrPngBehavior.convertImageSequenceToPng([this.imageSrc]) + ')';
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.js
index b86039895dc..8afb666d23e 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-var CrPicture = {};
+const CrPicture = {};
/**
* Contains the possible types for picture list image elements.
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_png_behavior.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_png_behavior.js
index 7f2d9ae303b..d57600ebfb1 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_png_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_png_behavior.js
@@ -12,44 +12,44 @@
* PNG frame delay fraction numerator.
* @const
*/
-var PNG_FRAME_DELAY_NUMERATOR = 1;
+const PNG_FRAME_DELAY_NUMERATOR = 1;
/**
* PNG frame delay fraction denominator.
* @const
*/
-var PNG_FRAME_DELAY_DENOMINATOR = 20;
+const PNG_FRAME_DELAY_DENOMINATOR = 20;
/**
* PNG signature.
* @const
*/
-var PNG_SIGNATURE = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
+const PNG_SIGNATURE = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
/**
* PNG bit depth (8 = 32bpp).
* @const
*/
-var PNG_BIT_DEPTH = 8;
+const PNG_BIT_DEPTH = 8;
/**
* PNG compression method (0 = deflate/inflate compression with a sliding
* window PNG compression).
* @const
*/
-var PNG_COMPRESSION_METHOD = 0;
+const PNG_COMPRESSION_METHOD = 0;
/**
* PNG filter method (0 = adaptive filtering with five basic filter types).
* @const
*/
-var PNG_FILTER_METHOD = 0;
+const PNG_FILTER_METHOD = 0;
/**
* PNG interlace method (0 = no interlace).
* @const
*/
-var PNG_INTERLACE_METHOD = 0;
+const PNG_INTERLACE_METHOD = 0;
/**
* CRC table for PNG encode.
@@ -69,7 +69,7 @@ var PNG_INTERLACE_METHOD = 0;
*
* @const
*/
-var PNG_CRC_TABLE = [
+const PNG_CRC_TABLE = [
0x0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x76DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0xEDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x9B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
@@ -126,10 +126,10 @@ var PNG_CRC_TABLE = [
* chunks: !Array<Uint8Array>
* }}
*/
-var CrPngState;
+let CrPngState;
/** @polymerBehavior */
-var CrPngBehavior = {
+const CrPngBehavior = {
/**
* Returns a data URL for an animated PNG image that is created
* from a sequence of images.
@@ -137,7 +137,7 @@ var CrPngBehavior = {
* @return {string} A data URL for an animated PNG image.
*/
convertImageSequenceToPng: function(images) {
- var png =
+ const png =
/** @type {!CrPngState} */ ({frames: 0, sequences: 0, chunks: []});
/** Append signature. */
@@ -154,7 +154,7 @@ var CrPngBehavior = {
* Filter method 1 byte
* Interlace method 1 byte
*/
- var IHDR = new Uint8Array(12 + 13);
+ const IHDR = new Uint8Array(12 + 13);
this.writeUInt32_(IHDR, 13, 0);
this.writeFourCC_(IHDR, 'IHDR', 4);
/** Write size at the end when known. */
@@ -172,7 +172,7 @@ var CrPngBehavior = {
* Number of frames 4 bytes
* Number of times to loop 4 bytes
*/
- var acTL = new Uint8Array(12 + 8);
+ const acTL = new Uint8Array(12 + 8);
this.writeUInt32_(acTL, 8, 0);
this.writeFourCC_(acTL, 'acTL', 4);
this.writeUInt32_(acTL, images.length, 8);
@@ -181,7 +181,7 @@ var CrPngBehavior = {
png.chunks.push(acTL);
/** Append each image as a PNG frame. */
- for (var i = 0; i < images.length; ++i)
+ for (let i = 0; i < images.length; ++i)
this.appendFrameFromDataURL_(images[i], png);
/** Update IHDR now that size and colour is known. */
@@ -193,7 +193,7 @@ var CrPngBehavior = {
/**
* http://www.w3.org/TR/2003/REC-PNG-20031110/#11IEND
*/
- var IEND = new Uint8Array(12);
+ const IEND = new Uint8Array(12);
this.writeUInt32_(IEND, 0, 0);
this.writeFourCC_(IEND, 'IEND', 4);
this.writeUInt32_(IEND, this.getCRC_(IEND, 4, 8), 8);
@@ -228,8 +228,8 @@ var CrPngBehavior = {
* @private
*/
readString_: function(buffer, offset, length) {
- var str = '';
- for (var i = 0; i < length; i++) {
+ let str = '';
+ for (let i = 0; i < length; i++) {
str += String.fromCharCode(buffer[offset + i]);
}
return str;
@@ -243,7 +243,7 @@ var CrPngBehavior = {
* @private
*/
writeBytes_: function(buffer, bytes, offset) {
- for (var i = 0; i < bytes.length; i++) {
+ for (let i = 0; i < bytes.length; i++) {
buffer[offset + i] = bytes[i] & 0xFF;
}
},
@@ -293,7 +293,7 @@ var CrPngBehavior = {
* @private
*/
writeString_: function(buffer, string, offset) {
- for (var i = 0; i < string.length; i++) {
+ for (let i = 0; i < string.length; i++) {
buffer[offset + i] = string.charCodeAt(i);
}
},
@@ -321,9 +321,9 @@ var CrPngBehavior = {
* @private
*/
getCRC_: function(buffer, start, end) {
- var crc = 0xFFFFFFFF;
- for (var i = start; i < end; i++) {
- var crcTableIndex = (crc ^ (buffer[i])) & 0xFF;
+ let crc = 0xFFFFFFFF;
+ for (let i = start; i < end; i++) {
+ const crcTableIndex = (crc ^ (buffer[i])) & 0xFF;
crc = PNG_CRC_TABLE[crcTableIndex] ^ (crc >>> 8);
}
return crc ^ 0xFFFFFFFF;
@@ -337,12 +337,12 @@ var CrPngBehavior = {
*/
appendFrameFromDataURL_: function(dataURL, png) {
/** Convert data URL to Uint8Array. */
- var byteString = atob(dataURL.split(',')[1]);
- var bytes = new Uint8Array(byteString.length);
+ const byteString = atob(dataURL.split(',')[1]);
+ const bytes = new Uint8Array(byteString.length);
this.writeString_(bytes, byteString, 0);
/** Check signature. */
- var signature = bytes.subarray(0, PNG_SIGNATURE.length);
+ const signature = bytes.subarray(0, PNG_SIGNATURE.length);
if (signature.toString() != PNG_SIGNATURE.toString()) {
console.error('Bad PNG signature');
}
@@ -360,7 +360,7 @@ var CrPngBehavior = {
* Dispose op 1 bytes
* Blend op 1 bytes
*/
- var fcTL = new Uint8Array(12 + 26);
+ const fcTL = new Uint8Array(12 + 26);
this.writeUInt32_(fcTL, 26, 0);
this.writeFourCC_(fcTL, 'fcTL', 4);
this.writeUInt32_(fcTL, png.sequences, 8);
@@ -376,7 +376,7 @@ var CrPngBehavior = {
png.chunks.push(fcTL);
/** Append data chunks for frame. */
- var i = PNG_SIGNATURE.length;
+ let i = PNG_SIGNATURE.length;
while ((i + 12) <= bytes.length) {
/**
* http://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-layout
@@ -386,9 +386,9 @@ var CrPngBehavior = {
* chunk = length bytes
* crc = 4 bytes
*/
- var length = this.readUInt32_(bytes, i);
- var type = this.readString_(bytes, i + 4, 4);
- var chunk = bytes.subarray(i + 8, i + 8 + length);
+ const length = this.readUInt32_(bytes, i);
+ const type = this.readString_(bytes, i + 4, 4);
+ const chunk = bytes.subarray(i + 8, i + 8 + length);
/** We should have enough bytes left for length. */
if (length != chunk.length) {
@@ -408,13 +408,13 @@ var CrPngBehavior = {
* Filter method 1 byte
* Interlace method 1 byte
*/
- var width = this.readUInt32_(chunk, 0);
- var height = this.readUInt32_(chunk, 4);
- var depth = chunk[8];
- var colour = chunk[9];
- var compression = chunk[10];
- var filter = chunk[11];
- var interlace = chunk[12];
+ const width = this.readUInt32_(chunk, 0);
+ const height = this.readUInt32_(chunk, 4);
+ const depth = chunk[8];
+ const colour = chunk[9];
+ const compression = chunk[10];
+ const filter = chunk[11];
+ const interlace = chunk[12];
/** Initialize size and colour if this is the first frame. */
if (png.frames == 0) {
@@ -447,7 +447,7 @@ var CrPngBehavior = {
*
* Data X bytes
*/
- var IDAT = new Uint8Array(12 + length);
+ const IDAT = new Uint8Array(12 + length);
this.writeUInt32_(IDAT, length, 0);
this.writeFourCC_(IDAT, 'IDAT', 4);
this.writeBytes_(IDAT, chunk, 8);
@@ -461,7 +461,7 @@ var CrPngBehavior = {
* Sequence number 4 bytes
* Frame data X bytes
*/
- var fdAT = new Uint8Array(12 + 4 + length);
+ const fdAT = new Uint8Array(12 + 4 + length);
this.writeUInt32_(fdAT, 4 + length, 0);
this.writeFourCC_(fdAT, 'fdAT', 4);
this.writeUInt32_(fdAT, png.sequences, 8);
@@ -478,7 +478,7 @@ var CrPngBehavior = {
*
* Palette data X bytes
*/
- var PLTE = new Uint8Array(12 + length);
+ const PLTE = new Uint8Array(12 + length);
this.writeUInt32_(PLTE, length, 0);
this.writeFourCC_(PLTE, 'PLTE', 4);
this.writeBytes_(PLTE, chunk, 8);
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
index b6d205e7900..723ed41d021 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
@@ -47,17 +47,17 @@ Polymer({
getIconClass_: function() {
if (!this.networkState)
return '';
- var type = this.networkState.Type;
+ const type = this.networkState.Type;
if (type == CrOnc.Type.ETHERNET)
return 'ethernet';
if (type == CrOnc.Type.VPN)
return 'vpn';
- var prefix = (type == CrOnc.Type.CELLULAR || type == CrOnc.Type.TETHER) ?
+ const prefix = (type == CrOnc.Type.CELLULAR || type == CrOnc.Type.TETHER) ?
'cellular-' :
'wifi-';
if (!this.isListItem && !this.networkState.GUID) {
- var deviceState = this.deviceState;
+ const deviceState = this.deviceState;
if (!deviceState || deviceState.State == 'Enabled' ||
deviceState.State == 'Enabling') {
return prefix + 'no-network';
@@ -65,7 +65,7 @@ Polymer({
return prefix + 'off';
}
- var connectionState = this.networkState.ConnectionState;
+ const connectionState = this.networkState.ConnectionState;
if (connectionState == CrOnc.ConnectionState.CONNECTING)
return prefix + 'connecting';
@@ -75,7 +75,7 @@ Polymer({
return prefix + 'not-connected';
}
- var strength = CrOnc.getSignalStrength(this.networkState);
+ const strength = CrOnc.getSignalStrength(this.networkState);
return prefix + this.strengthToIndex_(strength).toString(10);
},
@@ -103,14 +103,14 @@ Polymer({
* @private
*/
getTechnology_: function() {
- var networkState = this.networkState;
+ const networkState = this.networkState;
if (!networkState)
return '';
- var type = networkState.Type;
+ const type = networkState.Type;
if (type == CrOnc.Type.WI_MAX)
return 'network:4g';
if (type == CrOnc.Type.CELLULAR && networkState.Cellular) {
- var technology =
+ const technology =
this.getTechnologyId_(networkState.Cellular.NetworkTechnology);
if (technology != '')
return 'network:' + technology;
@@ -153,7 +153,7 @@ Polymer({
* @private
*/
showSecure_: function() {
- var networkState = this.networkState;
+ const networkState = this.networkState;
if (!this.networkState)
return false;
if (networkState.Type != CrOnc.Type.WI_FI || !networkState.WiFi)
@@ -162,7 +162,7 @@ Polymer({
networkState.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED) {
return false;
}
- var security = CrOnc.getStateOrActiveString(networkState.WiFi.Security);
+ const security = CrOnc.getStateOrActiveString(networkState.WiFi.Security);
return !!security && security != 'None';
},
});
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list.js
index 0942eb367b9..8d68577901c 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list.js
@@ -78,10 +78,10 @@ Polymer({
/** @private */
updateListItems_: function() {
this.saveScroll(this.$.networkList);
- var beforeNetworks = this.customItems.filter(function(item) {
+ const beforeNetworks = this.customItems.filter(function(item) {
return item.showBeforeNetworksList == true;
});
- var afterNetworks = this.customItems.filter(function(item) {
+ const afterNetworks = this.customItems.filter(function(item) {
return item.showBeforeNetworksList == false;
});
this.listItems_ = beforeNetworks.concat(this.networks, afterNetworks);
@@ -97,7 +97,7 @@ Polymer({
/** @private */
focusFirstItem_: function() {
// Select the first cr-network-list-item if there is one.
- var item = this.$$('cr-network-list-item');
+ const item = this.$$('cr-network-list-item');
if (!item)
return;
item.focus();
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
index 2b878fd620d..b3fff16a2d3 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
@@ -74,7 +74,7 @@ Polymer({
networkStateChanged_: function() {
if (!this.networkState)
return;
- var connectionState = this.networkState.ConnectionState;
+ const connectionState = this.networkState.ConnectionState;
if (connectionState == this.connectionState_)
return;
this.connectionState_ = connectionState;
@@ -88,13 +88,13 @@ Polymer({
*/
getItemName_: function() {
if (this.item.hasOwnProperty('customItemName')) {
- var item = /** @type {!CrNetworkList.CustomItemState} */ (this.item);
- var name = item.customItemName || '';
+ const item = /** @type {!CrNetworkList.CustomItemState} */ (this.item);
+ let name = item.customItemName || '';
if (CrOncStrings.hasOwnProperty(item.customItemName))
name = CrOncStrings[item.customItemName];
return name;
}
- var network = /** @type {!CrOnc.NetworkStateProperties} */ (this.item);
+ const network = /** @type {!CrOnc.NetworkStateProperties} */ (this.item);
return CrOnc.getNetworkName(network);
},
@@ -114,7 +114,7 @@ Polymer({
getNetworkStateText_: function() {
if (!this.networkState)
return '';
- var connectionState = this.networkState.ConnectionState;
+ const connectionState = this.networkState.ConnectionState;
if (this.networkState.Type == CrOnc.Type.CELLULAR) {
// For Cellular, an empty ConnectionState indicates that the device is
// still initializing.
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_types.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_types.js
index 55e2f4ac443..93d258c61f4 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_types.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_types.js
@@ -8,7 +8,7 @@
* CrNetworkListItem.
*/
-var CrNetworkList = {};
+const CrNetworkList = {};
/**
* Generic managed property type. This should match any of the basic managed
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
index 026500d90ee..c467b9aa093 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_listener_behavior.js
@@ -8,7 +8,7 @@
*/
/** @polymerBehavior */
-var CrNetworkListenerBehavior = {
+const CrNetworkListenerBehavior = {
properties: {
/**
* Array of selectors specifying all children to alert of changes to the
@@ -63,8 +63,8 @@ var CrNetworkListenerBehavior = {
* @private
*/
onNetworkListChanged_: function(networkIds) {
- var event = new CustomEvent('network-list-changed', {detail: networkIds});
- for (var i = 0; i < this.networkListChangeSubscriberSelectors_.length;
+ const event = new CustomEvent('network-list-changed', {detail: networkIds});
+ for (let i = 0; i < this.networkListChangeSubscriberSelectors_.length;
i++) {
this.maybeDispatchEvent_(
this.networkListChangeSubscriberSelectors_[i], event);
@@ -79,8 +79,8 @@ var CrNetworkListenerBehavior = {
* @private
*/
onNetworksChanged_: function(networkIds) {
- var event = new CustomEvent('networks-changed', {detail: networkIds});
- for (var i = 0; i < this.networksChangeSubscriberSelectors_.length; i++) {
+ const event = new CustomEvent('networks-changed', {detail: networkIds});
+ for (let i = 0; i < this.networksChangeSubscriberSelectors_.length; i++) {
this.maybeDispatchEvent_(
this.networksChangeSubscriberSelectors_[i], event);
}
@@ -91,7 +91,7 @@ var CrNetworkListenerBehavior = {
* @private
*/
maybeDispatchEvent_: function(selectors, event) {
- var element = this.$$(selectors);
+ const element = this.$$(selectors);
if (!element)
return;
element.dispatchEvent(event);
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js
index 66036c7283d..ee42242945c 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_network_select.js
@@ -106,7 +106,7 @@ Polymer({
this.refreshNetworks();
- /** @const */ var INTERVAL_MS = 10 * 1000;
+ /** @const */ const INTERVAL_MS = 10 * 1000;
chrome.networkingPrivate.requestNetworkScan();
this.scanIntervalId_ = window.setInterval(function() {
chrome.networkingPrivate.requestNetworkScan();
@@ -133,11 +133,46 @@ Polymer({
},
/**
+ * Returns default network if it is present.
+ * @return {!CrOnc.NetworkStateProperties|undefined}
+ */
+ getDefaultNetwork: function() {
+ let defaultNetwork;
+ for (let i = 0; i < this.networkStateList_.length; ++i) {
+ const state = this.networkStateList_[i];
+ if (state.ConnectionState == CrOnc.ConnectionState.CONNECTED) {
+ defaultNetwork = state;
+ break;
+ }
+ if (state.ConnectionState == CrOnc.ConnectionState.CONNECTING &&
+ !defaultNetwork) {
+ defaultNetwork = state;
+ // Do not break here in case a non WiFi network is connecting but a
+ // WiFi network is connected.
+ } else if (state.Type == CrOnc.Type.WI_FI) {
+ break; // Non connecting or connected WiFI networks are always last.
+ }
+ }
+ return defaultNetwork;
+ },
+
+ /**
+ * Returns network with specified GUID if it is available.
+ * @param {string} guid of network.
+ * @return {!CrOnc.NetworkStateProperties|undefined}
+ */
+ getNetwork: function(guid) {
+ return this.networkStateList_.find(function(network) {
+ return network.GUID == guid;
+ });
+ },
+
+ /**
* @param {!Array<!CrOnc.DeviceStateProperties>} deviceStates
* @private
*/
getDeviceStatesCallback_: function(deviceStates) {
- var filter = {
+ const filter = {
networkType: chrome.networkingPrivate.NetworkType.ALL,
visible: true,
configured: false
@@ -161,22 +196,8 @@ Polymer({
this.networkStateList_ = networkStates;
this.fire('network-list-changed', networkStates);
- var defaultNetwork;
- for (var i = 0; i < networkStates.length; ++i) {
- var state = networkStates[i];
- if (state.ConnectionState == CrOnc.ConnectionState.CONNECTED) {
- defaultNetwork = state;
- break;
- }
- if (state.ConnectionState == CrOnc.ConnectionState.CONNECTING &&
- !defaultNetwork) {
- defaultNetwork = state;
- // Do not break here in case a non WiFi network is connecting but a
- // WiFi network is connected.
- } else if (state.Type == CrOnc.Type.WI_FI) {
- break; // Non connecting or connected WiFI networks are always last.
- }
- }
+ const defaultNetwork = this.getDefaultNetwork();
+
if ((!defaultNetwork && !this.defaultNetworkState_) ||
(defaultNetwork && this.defaultNetworkState_ &&
defaultNetwork.GUID == this.defaultNetworkState_.GUID &&
@@ -203,11 +224,11 @@ Polymer({
return;
}
// Add a Cellular network after the Ethernet network if it exists.
- var idx = networkStates.length > 0 &&
+ const idx = networkStates.length > 0 &&
networkStates[0].Type == CrOnc.Type.ETHERNET ?
1 :
0;
- var cellular = {
+ const cellular = {
GUID: '',
Type: CrOnc.Type.CELLULAR,
Cellular: {Scanning: this.cellularDeviceState_.Scanning}
@@ -221,7 +242,7 @@ Polymer({
* @private
*/
onNetworkListItemSelected_: function(e) {
- var state = e.detail;
+ const state = e.detail;
e.target.blur();
if (!this.handleNetworkItemSelected) {
@@ -232,7 +253,7 @@ Polymer({
// NOTE: This isn't used by OOBE (no handle-network-item-selected).
// TODO(stevenjb): Remove custom OOBE handling.
if (state.Type == CrOnc.Type.CELLULAR && this.cellularDeviceState_) {
- var cellularDevice = this.cellularDeviceState_;
+ const cellularDevice = this.cellularDeviceState_;
// If Cellular is not enabled and not SIM locked, enable Cellular.
if (cellularDevice.State != CrOnc.DeviceState.ENABLED &&
(!cellularDevice.SIMLockStatus ||
@@ -245,7 +266,7 @@ Polymer({
return;
chrome.networkingPrivate.startConnect(state.GUID, function() {
- var lastError = chrome.runtime.lastError;
+ const lastError = chrome.runtime.lastError;
if (lastError && lastError != 'connecting')
console.error('networkingPrivate.startConnect error: ' + lastError);
});
diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
index bab6ac84837..f5664dda588 100644
--- a/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
+++ b/chromium/ui/webui/resources/cr_elements/chromeos/network/cr_onc_types.js
@@ -36,9 +36,9 @@
* vpnNameTemplate: string,
* }}
*/
-var CrOncStrings;
+let CrOncStrings;
-var CrOnc = {};
+const CrOnc = {};
/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
CrOnc.NetworkStateProperties;
@@ -239,16 +239,23 @@ CrOnc.getActiveValue = function(property) {
// If no Active value is defined, return the effective value.
if ('Effective' in property) {
- var effective = property.Effective;
+ const effective = property.Effective;
if (effective in property)
return property[effective];
}
- // If no Effective value, return the UserSetting or DeviceSetting.
+ // If no Effective value, return the UserSetting or SharedSetting.
if ('UserSetting' in property)
return property['UserSetting'];
- if ('DeviceSetting' in property)
- return property['DeviceSetting'];
+ if ('SharedSetting' in property)
+ return property['SharedSetting'];
+
+ // Effective, UserEditable or DeviceEditable properties may not have a value
+ // set.
+ if ('Effective' in property || 'UserEditable' in property ||
+ 'DeviceEditable' in property) {
+ return undefined;
+ }
console.error(
'getActiveValue called on invalid ONC object: ' +
@@ -270,29 +277,48 @@ CrOnc.getStateOrActiveString = function(property) {
};
/**
+ * Return if the property is simple, i.e. doesn't contain any nested
+ * dictionaries.
+ * @param property {!Object|undefined}
+ * @return {boolean}
+ */
+CrOnc.isSimpleProperty = function(property) {
+ const requiredProperties = [
+ 'Active', 'Effective', 'UserSetting', 'SharedSetting', 'UserEditable',
+ 'DeviceEditable'
+ ];
+ for (const prop of requiredProperties) {
+ if (prop in property)
+ return true;
+ }
+ return false;
+};
+
+/**
* Converts a managed ONC dictionary into an unmanaged dictionary (i.e. a
* dictionary of active values).
- * NOTE: This is not intended to be used with dictionaries that contain
- * nested dictionaries. This will fail and return undefined in that case.
* @param {!Object|undefined} properties A managed ONC dictionary
* @return {!Object|undefined} An unmanaged version of |properties|.
*/
-CrOnc.getSimpleActiveProperties = function(properties) {
+CrOnc.getActiveProperties = function(properties) {
'use strict';
if (!properties)
return undefined;
- var result = {};
- var keys = Object.keys(properties);
- for (var i = 0; i < keys.length; ++i) {
- var k = keys[i];
- var prop = CrOnc.getActiveValue(properties[k]);
- if (prop == undefined) {
- console.error(
- 'getSimpleActiveProperties called on invalid ONC object: ' +
- JSON.stringify(properties));
- return undefined;
+ const result = {};
+ const keys = Object.keys(properties);
+ for (let i = 0; i < keys.length; ++i) {
+ const k = keys[i];
+ const property = properties[k];
+ let propertyValue;
+ if (typeof property === 'object') {
+ if (CrOnc.isSimpleProperty(property))
+ propertyValue = CrOnc.getActiveValue(property);
+ else
+ propertyValue = CrOnc.getActiveProperties(property);
+ } else {
+ propertyValue = property;
}
- result[k] = prop;
+ result[k] = propertyValue;
}
return result;
};
@@ -307,11 +333,11 @@ CrOnc.getSimpleActiveProperties = function(properties) {
*/
CrOnc.getIPConfigForType = function(properties, type) {
'use strict';
- /** @type {!CrOnc.IPConfigProperties|undefined} */ var ipConfig = undefined;
- /** @type {!CrOnc.IPType|undefined} */ var ipType = undefined;
- var ipConfigs = properties.IPConfigs;
+ /** @type {!CrOnc.IPConfigProperties|undefined} */ let ipConfig = undefined;
+ /** @type {!CrOnc.IPType|undefined} */ let ipType = undefined;
+ const ipConfigs = properties.IPConfigs;
if (ipConfigs) {
- for (var i = 0; i < ipConfigs.length; ++i) {
+ for (let i = 0; i < ipConfigs.length; ++i) {
ipConfig = ipConfigs[i];
ipType = ipConfig.Type ? /** @type {CrOnc.IPType} */ (ipConfig.Type) :
undefined;
@@ -322,9 +348,9 @@ CrOnc.getIPConfigForType = function(properties, type) {
if (type != CrOnc.IPType.IPV4)
return type == ipType ? ipConfig : undefined;
- var staticIpConfig =
+ const staticIpConfig =
/** @type {!CrOnc.IPConfigProperties|undefined} */ (
- CrOnc.getSimpleActiveProperties(properties.StaticIPConfig));
+ CrOnc.getActiveProperties(properties.StaticIPConfig));
if (!staticIpConfig)
return ipConfig;
@@ -354,7 +380,7 @@ CrOnc.getIPConfigForType = function(properties, type) {
* @return {number} The signal strength value if it exists or 0.
*/
CrOnc.getSignalStrength = function(properties) {
- var type = properties.Type;
+ const type = properties.Type;
if (type == CrOnc.Type.CELLULAR && properties.Cellular)
return properties.Cellular.SignalStrength || 0;
if (type == CrOnc.Type.TETHER && properties.Tether)
@@ -375,7 +401,7 @@ CrOnc.getSignalStrength = function(properties) {
* managed dictionary or undefined.
*/
CrOnc.getManagedAutoConnect = function(properties) {
- var type = properties.Type;
+ const type = properties.Type;
if (type == CrOnc.Type.CELLULAR && properties.Cellular)
return properties.Cellular.AutoConnect;
if (type == CrOnc.Type.VPN && properties.VPN)
@@ -394,7 +420,7 @@ CrOnc.getManagedAutoConnect = function(properties) {
* @return {boolean} The AutoConnect value if it exists or false.
*/
CrOnc.getAutoConnect = function(properties) {
- var autoconnect = CrOnc.getManagedAutoConnect(properties);
+ const autoconnect = CrOnc.getManagedAutoConnect(properties);
return !!CrOnc.getActiveValue(autoconnect);
};
@@ -406,14 +432,14 @@ CrOnc.getAutoConnect = function(properties) {
CrOnc.getNetworkName = function(properties) {
if (!properties)
return '';
- var name = CrOnc.getStateOrActiveString(properties.Name);
- var type = CrOnc.getStateOrActiveString(properties.Type);
+ const name = CrOnc.getStateOrActiveString(properties.Name);
+ const type = CrOnc.getStateOrActiveString(properties.Type);
if (!name)
return CrOncStrings['OncType' + type];
if (type == 'VPN' && properties.VPN) {
- var vpnType = CrOnc.getStateOrActiveString(properties.VPN.Type);
+ const vpnType = CrOnc.getStateOrActiveString(properties.VPN.Type);
if (vpnType == 'ThirdPartyVPN' && properties.VPN.ThirdPartyVPN) {
- var providerName = properties.VPN.ThirdPartyVPN.ProviderName;
+ const providerName = properties.VPN.ThirdPartyVPN.ProviderName;
if (providerName) {
return CrOncStrings.vpnNameTemplate.replace('$1', providerName)
.replace('$2', name);
@@ -441,7 +467,7 @@ CrOnc.getEscapedNetworkName = function(properties) {
CrOnc.isSimLocked = function(properties) {
if (!properties.Cellular)
return false;
- var simLockStatus = properties.Cellular.SIMLockStatus;
+ const simLockStatus = properties.Cellular.SIMLockStatus;
if (simLockStatus == undefined)
return false;
return simLockStatus.LockType == CrOnc.LockType.PIN ||
@@ -458,12 +484,12 @@ CrOnc.isSimLocked = function(properties) {
*/
CrOnc.setValidStaticIPConfig = function(config, properties) {
if (!config.IPAddressConfigType) {
- var ipConfigType = /** @type {chrome.networkingPrivate.IPConfigType} */ (
+ const ipConfigType = /** @type {chrome.networkingPrivate.IPConfigType} */ (
CrOnc.getActiveValue(properties.IPAddressConfigType));
config.IPAddressConfigType = ipConfigType || CrOnc.IPConfigType.DHCP;
}
if (!config.NameServersConfigType) {
- var nsConfigType = /** @type {chrome.networkingPrivate.IPConfigType} */ (
+ const nsConfigType = /** @type {chrome.networkingPrivate.IPConfigType} */ (
CrOnc.getActiveValue(properties.NameServersConfigType));
config.NameServersConfigType = nsConfigType || CrOnc.IPConfigType.DHCP;
}
@@ -478,8 +504,8 @@ CrOnc.setValidStaticIPConfig = function(config, properties) {
config.StaticIPConfig =
/** @type {chrome.networkingPrivate.IPConfigProperties} */ ({});
}
- var staticIP = config.StaticIPConfig;
- var stateIPConfig = CrOnc.getIPConfigForType(properties, CrOnc.IPType.IPV4);
+ const staticIP = config.StaticIPConfig;
+ const stateIPConfig = CrOnc.getIPConfigForType(properties, CrOnc.IPType.IPV4);
if (config.IPAddressConfigType == 'Static') {
staticIP.Gateway = staticIP.Gateway || stateIPConfig.Gateway || '';
staticIP.IPAddress = staticIP.IPAddress || stateIPConfig.IPAddress || '';
@@ -504,10 +530,10 @@ CrOnc.setValidStaticIPConfig = function(config, properties) {
*/
CrOnc.setProperty = function(properties, key, value) {
while (true) {
- var index = key.indexOf('.');
+ const index = key.indexOf('.');
if (index < 0)
break;
- var keyComponent = key.substr(0, index);
+ const keyComponent = key.substr(0, index);
if (!properties.hasOwnProperty(keyComponent))
properties[keyComponent] = {};
properties = properties[keyComponent];
@@ -533,7 +559,7 @@ CrOnc.setTypeProperty = function(properties, key, value) {
'Type not defined in properties: ' + JSON.stringify(properties));
return;
}
- var typeKey = properties.Type + '.' + key;
+ const typeKey = properties.Type + '.' + key;
CrOnc.setProperty(properties, typeKey, value);
};
@@ -547,9 +573,9 @@ CrOnc.getRoutingPrefixAsNetmask = function(prefixLength) {
// Return the empty string for invalid inputs.
if (prefixLength < 0 || prefixLength > 32)
return '';
- var netmask = '';
- for (var i = 0; i < 4; ++i) {
- var remainder = 8;
+ let netmask = '';
+ for (let i = 0; i < 4; ++i) {
+ let remainder = 8;
if (prefixLength >= 8) {
prefixLength -= 8;
} else {
@@ -558,7 +584,7 @@ CrOnc.getRoutingPrefixAsNetmask = function(prefixLength) {
}
if (i > 0)
netmask += '.';
- var value = 0;
+ let value = 0;
if (remainder != 0)
value = ((2 << (remainder - 1)) - 1) << (8 - remainder);
netmask += value.toString();
@@ -573,12 +599,12 @@ CrOnc.getRoutingPrefixAsNetmask = function(prefixLength) {
*/
CrOnc.getRoutingPrefixAsLength = function(netmask) {
'use strict';
- var prefixLength = 0;
- var tokens = netmask.split('.');
+ let prefixLength = 0;
+ const tokens = netmask.split('.');
if (tokens.length != 4)
return -1;
- for (var i = 0; i < tokens.length; ++i) {
- var token = tokens[i];
+ for (let i = 0; i < tokens.length; ++i) {
+ const token = tokens[i];
// If we already found the last mask and the current one is not
// '0' then the netmask is invalid. For example, 255.224.255.0
if (prefixLength / 8 != i) {
diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
index 3c87967d159..4b59b25bc40 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
@@ -60,8 +60,9 @@
outline: none;
}
</style>
- <dialog id="dialog" tabindex="0" on-close="onNativeDialogClose_">
- <div class="item-wrapper" tabindex="-1" role="menu">
+ <dialog id="dialog" tabindex="0" on-close="onNativeDialogClose_" role="menu"
+ aria-label$="[[ariaLabel]]">
+ <div class="item-wrapper" tabindex="-1">
<slot name="item" id="contentNode"></slot>
</div>
</dialog>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
index 9c70ecede80..477e0ed7456 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
@@ -16,7 +16,7 @@
* maxY: (number|undefined),
* }}
*/
-var ShowAtConfig;
+let ShowAtConfig;
/**
* @typedef {{
@@ -32,13 +32,13 @@ var ShowAtConfig;
* maxY: (number|undefined),
* }}
*/
-var ShowAtPositionConfig;
+let ShowAtPositionConfig;
/**
* @enum {number}
* @const
*/
-var AnchorAlignment = {
+const AnchorAlignment = {
BEFORE_START: -2,
AFTER_START: -1,
CENTER: 0,
@@ -47,7 +47,7 @@ var AnchorAlignment = {
};
/** @const {string} */
-var DROPDOWN_ITEM_CLASS = 'dropdown-item';
+const DROPDOWN_ITEM_CLASS = 'dropdown-item';
(function() {
/**
@@ -66,7 +66,7 @@ var DROPDOWN_ITEM_CLASS = 'dropdown-item';
*/
function getStartPointWithAnchor(
start, end, menuLength, anchorAlignment, min, max) {
- var startPoint = 0;
+ let startPoint = 0;
switch (anchorAlignment) {
case AnchorAlignment.BEFORE_START:
startPoint = -menuLength;
@@ -100,7 +100,7 @@ function getStartPointWithAnchor(
* @return {!ShowAtPositionConfig}
*/
function getDefaultShowConfig() {
- var doc = document.scrollingElement;
+ const doc = document.scrollingElement;
return {
top: 0,
left: 0,
@@ -157,6 +157,8 @@ Polymer({
type: Boolean,
value: false,
},
+
+ ariaLabel: String,
},
listeners: {
@@ -238,7 +240,7 @@ Polymer({
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')
return;
- var nextOption = this.getNextOption_(e.key == 'ArrowDown' ? 1 : -1);
+ const nextOption = this.getNextOption_(e.key == 'ArrowDown' ? 1 : -1);
if (nextOption) {
if (!this.hasMousemoveListener_) {
this.hasMousemoveListener_ = true;
@@ -260,9 +262,10 @@ Polymer({
onMouseover_: function(e) {
// TODO(scottchen): Using "focus" to determine selected item might mess
// with screen readers in some edge cases.
- var i = 0;
+ let i = 0;
+ let target;
do {
- var target = e.path[i++];
+ target = e.path[i++];
if (target.classList && target.classList.contains('dropdown-item') &&
!target.disabled) {
target.focus();
@@ -284,11 +287,11 @@ Polymer({
getNextOption_: function(step) {
// Using a counter to ensure no infinite loop occurs if all elements are
// hidden/disabled.
- var counter = 0;
- var nextOption = null;
- var options = this.querySelectorAll('.dropdown-item');
- var numOptions = options.length;
- var focusedIndex =
+ let counter = 0;
+ let nextOption = null;
+ const options = this.querySelectorAll('.dropdown-item');
+ const numOptions = options.length;
+ let focusedIndex =
Array.prototype.indexOf.call(options, getDeepActiveElement());
// Handle case where nothing is focused and up is pressed.
@@ -331,7 +334,7 @@ Polymer({
// accurate for where the menu should be shown.
this.anchorElement_.scrollIntoViewIfNeeded();
- var rect = this.anchorElement_.getBoundingClientRect();
+ const rect = this.anchorElement_.getBoundingClientRect();
this.showAtPosition(/** @type {ShowAtPositionConfig} */ (Object.assign(
{
top: rect.top,
@@ -373,9 +376,9 @@ Polymer({
*/
showAtPosition: function(config) {
// Save the scroll position of the viewport.
- var doc = document.scrollingElement;
- var scrollLeft = doc.scrollLeft;
- var scrollTop = doc.scrollTop;
+ const doc = document.scrollingElement;
+ const scrollLeft = doc.scrollLeft;
+ const scrollTop = doc.scrollTop;
// Reset position so that layout isn't affected by the previous position,
// and so that the dialog is positioned at the top-start corner of the
@@ -417,31 +420,31 @@ Polymer({
*/
positionDialog_: function(config) {
this.lastConfig_ = config;
- var c = Object.assign(getDefaultShowConfig(), config);
+ const c = Object.assign(getDefaultShowConfig(), config);
- var top = c.top;
- var left = c.left;
- var bottom = top + c.height;
- var right = left + c.width;
+ const top = c.top;
+ const left = c.left;
+ const bottom = top + c.height;
+ const right = left + c.width;
// Flip the X anchor in RTL.
- var rtl = getComputedStyle(this).direction == 'rtl';
+ const rtl = getComputedStyle(this).direction == 'rtl';
if (rtl)
c.anchorAlignmentX *= -1;
const offsetWidth = this.$.dialog.offsetWidth;
- var menuLeft = getStartPointWithAnchor(
+ const menuLeft = getStartPointWithAnchor(
left, right, offsetWidth, c.anchorAlignmentX, c.minX, c.maxX);
if (rtl) {
- var menuRight =
+ const menuRight =
document.scrollingElement.clientWidth - menuLeft - offsetWidth;
this.$.dialog.style.right = menuRight + 'px';
} else {
this.$.dialog.style.left = menuLeft + 'px';
}
- var menuTop = getStartPointWithAnchor(
+ const menuTop = getStartPointWithAnchor(
top, bottom, this.$.dialog.offsetHeight, c.anchorAlignmentY, c.minY,
c.maxY);
this.$.dialog.style.top = menuTop + 'px';
diff --git a/chromium/ui/webui/resources/cr_elements/cr_container_shadow_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_container_shadow_behavior.js
index 3eb059ebfcf..1c6789f9956 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_container_shadow_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_container_shadow_behavior.js
@@ -19,24 +19,24 @@
*/
/** @polymerBehavior */
-var CrContainerShadowBehavior = {
+const CrContainerShadowBehavior = {
/** @private {?IntersectionObserver} */
intersectionObserver_: null,
/** @override */
attached: function() {
// The element holding the drop shadow effect to be shown.
- var dropShadow = document.createElement('div');
+ const dropShadow = document.createElement('div');
// This ID should match the CSS rules in shared_styles_css.html.
dropShadow.id = 'cr-container-shadow';
this.$.container.parentNode.insertBefore(dropShadow, this.$.container);
// Dummy element used to detect scrolling. Has a 0px height intentionally.
- var intersectionProbe = document.createElement('div');
+ const intersectionProbe = document.createElement('div');
this.$.container.prepend(intersectionProbe);
// Setup drop shadow logic.
- var callback = entries => {
+ const callback = entries => {
dropShadow.classList.toggle(
'has-shadow', entries[entries.length - 1].intersectionRatio == 0);
};
diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js
index ebf0ad52afa..9d71e19854f 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js
@@ -74,6 +74,11 @@ Polymer({
type: Boolean,
value: false,
},
+
+ showOnAttach: {
+ type: Boolean,
+ value: false,
+ },
},
listeners: {
@@ -104,7 +109,7 @@ Polymer({
/** @override */
attached: function() {
- var mutationObserverCallback = function() {
+ const mutationObserverCallback = function() {
if (this.$.dialog.open) {
this.addIntersectionObserver_();
this.addKeydownListener_();
@@ -123,6 +128,8 @@ Polymer({
// In some cases dialog already has the 'open' attribute by this point.
mutationObserverCallback();
+ if (this.showOnAttach)
+ this.showModal();
},
/** @override */
@@ -140,19 +147,19 @@ Polymer({
if (this.intersectionObserver_)
return;
- var bodyContainer = this.$$('.body-container');
+ const bodyContainer = this.$$('.body-container');
- var bottomMarker = this.$.bodyBottomMarker;
- var topMarker = this.$.bodyTopMarker;
+ const bottomMarker = this.$.bodyBottomMarker;
+ const topMarker = this.$.bodyTopMarker;
- var callback = function(entries) {
+ const callback = function(entries) {
// In some rare cases, there could be more than one entry per observed
// element, in which case the last entry's result stands.
- for (var i = 0; i < entries.length; i++) {
- var target = entries[i].target;
+ for (let i = 0; i < entries.length; i++) {
+ const target = entries[i].target;
assert(target == bottomMarker || target == topMarker);
- var classToToggle =
+ const classToToggle =
target == bottomMarker ? 'bottom-scrollable' : 'top-scrollable';
bodyContainer.classList.toggle(
@@ -302,7 +309,7 @@ Polymer({
if (e.target != this && e.target.tagName != 'CR-INPUT')
return;
- var actionButton =
+ const actionButton =
this.querySelector('.action-button:not([disabled]):not([hidden])');
if (actionButton) {
actionButton.click();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
index 5ca559e9de2..f085891431b 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
+++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn
@@ -11,4 +11,8 @@ js_type_check("closure_compile") {
}
js_library("cr_drawer") {
+ deps = [
+ "//ui/webui/resources/js:assert",
+ "//ui/webui/resources/js:util",
+ ]
}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
index a904f7fbff9..eae9c1c22ff 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
@@ -1,5 +1,7 @@
<link rel="import" href="../../html/polymer.html">
+<link rel="import" href="../../html/assert.html">
+<link rel="import" href="../../html/util.html">
<link rel="import" href="../shared_vars_css.html">
<dom-module id="cr-drawer">
@@ -27,7 +29,7 @@
word-break: break-word;
}
- :host(.opening) dialog {
+ :host([show_]) dialog {
left: 0;
}
@@ -37,7 +39,7 @@
transition: right var(--transition-timing);
}
- :host(.opening[align=rtl]) dialog {
+ :host([show_][align=rtl]) dialog {
right: 0;
}
@@ -52,7 +54,7 @@
transition: opacity var(--transition-timing);
}
- :host(.opening) dialog::backdrop {
+ :host([show_]) dialog::backdrop {
opacity: 1;
}
@@ -72,7 +74,7 @@
}
</style>
<dialog id="dialog" on-cancel="onDialogCancel_" on-tap="onDialogTap_"
- on-transitionend="onDialogTransitionEnd_" on-close="onDialogClose_">
+ on-close="onDialogClose_">
<div id="container" on-tap="onContainerTap_">
<div class="drawer-header" tabindex="-1">[[heading]]</div>
<slot></slot>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js
index 6e5227b3179..5ba1e551929 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js
@@ -8,10 +8,10 @@ Polymer({
properties: {
heading: String,
- open: {
+ /** @private */
+ show_: {
type: Boolean,
- // Enables 'open-changed' events.
- notify: true,
+ reflectToAttribute: true,
},
/** The alignment of the drawer on the screen ('ltr' or 'rtl'). */
@@ -22,29 +22,61 @@ Polymer({
},
},
+ /** @type {boolean} */
+ get open() {
+ return this.$.dialog.open;
+ },
+
+ set open(value) {
+ assertNotReached('Cannot set |open|.');
+ },
+
/** Toggles the drawer open and close. */
toggle: function() {
- if (this.$.dialog.open)
- this.closeDrawer();
+ if (this.open)
+ this.cancel();
else
this.openDrawer();
},
/** Shows drawer and slides it into view. */
openDrawer: function() {
- if (!this.$.dialog.open) {
- this.$.dialog.showModal();
- this.open = true;
- this.classList.add('opening');
- }
+ if (this.open)
+ return;
+ this.$.dialog.showModal();
+ this.show_ = true;
+ this.fire('cr-drawer-opening');
+ listenOnce(this.$.dialog, 'transitionend', () => {
+ this.fire('cr-drawer-opened');
+ });
+ },
+
+ /**
+ * Slides the drawer away, then closes it after the transition has ended. It
+ * is up to the owner of this component to differentiate between close and
+ * cancel.
+ * @param {boolean} cancel
+ */
+ dismiss_: function(cancel) {
+ if (!this.open)
+ return;
+ this.show_ = false;
+ listenOnce(this.$.dialog, 'transitionend', () => {
+ this.$.dialog.close(cancel ? 'canceled' : 'closed');
+ });
},
- /** Slides the drawer away, then closes it after the transition has ended. */
- closeDrawer: function() {
- if (this.$.dialog.open) {
- this.classList.remove('opening');
- this.classList.add('closing');
- }
+ cancel: function() {
+ this.dismiss_(true);
+ },
+
+ close: function() {
+ this.dismiss_(false);
+ },
+
+ /** @return {boolean} */
+ wasCanceled: function() {
+ return !this.open && this.$.dialog.returnValue == 'canceled';
},
/**
@@ -62,7 +94,7 @@ Polymer({
* @private
*/
onDialogTap_: function() {
- this.closeDrawer();
+ this.cancel();
},
/**
@@ -72,7 +104,7 @@ Polymer({
*/
onDialogCancel_: function(event) {
event.preventDefault();
- this.closeDrawer();
+ this.cancel();
},
/**
@@ -88,18 +120,4 @@ Polymer({
// DOM v1.
this.fire('close');
},
-
- /**
- * Closes the dialog when the closing animation is over.
- * @private
- */
- onDialogTransitionEnd_: function() {
- if (this.classList.contains('closing')) {
- this.classList.remove('closing');
- this.$.dialog.close();
- this.open = false;
- } else if (this.classList.contains('opening')) {
- this.fire('cr-drawer-opened');
- }
- },
});
diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
index 37a0ca53b6c..bee36844e23 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
@@ -25,8 +25,8 @@
flex: 1;
}
</style>
- <div id="outer" actionable>
- <div id="label"><slot></slot></div>
+ <div id="outer">
+ <div id="label" actionable><slot></slot></div>
<paper-icon-button-light class$="[[iconName_(expanded)]]">
<button disabled="[[disabled]]" aria-label$="[[alt]]"
aria-pressed$="[[getAriaPressed_(expanded)]]"
diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html
index b328ee4b72e..f66e06127a2 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html
@@ -40,7 +40,7 @@
/* Margin between <input> and <paper-button> in the 'suffix' slot */
:host ::slotted(paper-button[slot=suffix]) {
- margin-inline-start: var(--cr-button-edge-spacing);
+ margin-inline-start: var(--cr-button-edge-spacing) !important;
}
:host([invalid]) #label {
diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js
index 67b9484a99b..a14a8ba95e1 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js
@@ -284,8 +284,14 @@ Polymer({
this.focus();
},
- /** @private */
- onValueChanged_: function() {
+ /**
+ * @param {string} newValue
+ * @param {string} oldValue
+ * @private
+ */
+ onValueChanged_: function(newValue, oldValue) {
+ if (!newValue && !oldValue)
+ return;
if (this.autoValidate)
this.validate();
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js
index 19b3d920a5b..43db9123f86 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js
@@ -50,10 +50,10 @@ Polymer({
/** @private */
render_: function() {
- var template = this.getContentChildren()[0];
+ const template = this.getContentChildren()[0];
if (!this.ctor)
this.templatize(template);
- var parentNode = this.parentNode;
+ const parentNode = this.parentNode;
if (parentNode && !this.child_) {
this.instance_ = this.stamp({});
this.child_ = this.instance_.root.firstElementChild;
diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js
index 4267639b0b9..2ccbc9ad1a3 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js
@@ -62,7 +62,7 @@ Polymer({
_createRipple: function() {
this._rippleContainer = this.$.icon;
- var ripple = Polymer.PaperRippleBehavior._createRipple();
+ const ripple = Polymer.PaperRippleBehavior._createRipple();
ripple.id = 'ink';
ripple.setAttribute('recenters', '');
ripple.classList.add('circle');
diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js
index b0c4fdfd483..444e458585f 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js
@@ -26,7 +26,7 @@ Polymer({
* @private
*/
onKeyDown_: function(e) {
- var items = this.querySelectorAll('.avatar');
+ const items = this.querySelectorAll('.avatar');
switch (e.key) {
case 'ArrowDown':
case 'ArrowUp':
@@ -54,24 +54,24 @@ Polymer({
* @private
*/
moveFocusRow_: function(items, direction) {
- var offset =
+ let offset =
(direction == 'ArrowDown' || direction == 'ArrowRight') ? 1 : -1;
- var style = getComputedStyle(this);
- var avatarSpacing =
+ const style = getComputedStyle(this);
+ const avatarSpacing =
parseInt(style.getPropertyValue('--avatar-spacing'), 10);
- var avatarSize = parseInt(style.getPropertyValue('--avatar-size'), 10);
- var rowSize = Math.floor(this.clientWidth / (avatarSpacing + avatarSize));
- var rows = Math.ceil(items.length / rowSize);
- var gridSize = rows * rowSize;
+ const avatarSize = parseInt(style.getPropertyValue('--avatar-size'), 10);
+ const rowSize = Math.floor(this.clientWidth / (avatarSpacing + avatarSize));
+ const rows = Math.ceil(items.length / rowSize);
+ const gridSize = rows * rowSize;
- var focusIndex =
+ const focusIndex =
Array.prototype.slice.call(items).findIndex(function(item) {
return Polymer.dom(item).getOwnerRoot().activeElement == item;
});
- var nextItem = null;
+ let nextItem = null;
if (direction == 'ArrowDown' || direction == 'ArrowUp') {
- for (var i = offset; Math.abs(i) <= rows; i += offset) {
+ for (let i = offset; Math.abs(i) <= rows; i += offset) {
nextItem = items[(focusIndex + i * rowSize + gridSize) % gridSize];
if (nextItem)
break;
@@ -82,7 +82,7 @@ Polymer({
} else {
if (style.direction == 'rtl')
offset *= -1;
- var nextIndex = (focusIndex + offset) % items.length;
+ let nextIndex = (focusIndex + offset) % items.length;
if (nextIndex < 0)
nextIndex = items.length - 1;
nextItem = items[nextIndex];
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js
index 864e016a96f..c08463e25ae 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js
@@ -7,7 +7,7 @@
*/
/** @polymerBehavior */
-var CrRadioButtonBehaviorImpl = {
+const CrRadioButtonBehaviorImpl = {
properties: {
checked: {
type: Boolean,
@@ -20,6 +20,7 @@ var CrRadioButtonBehaviorImpl = {
type: Boolean,
value: false,
reflectToAttribute: true,
+ notify: true,
observer: 'disabledChanged_',
},
@@ -27,21 +28,24 @@ var CrRadioButtonBehaviorImpl = {
type: String,
value: '', // Allows the hidden$= binding to run without being set.
},
+
+ name: {
+ type: String,
+ notify: true,
+ reflectToAttribute: true,
+ },
},
listeners: {
- 'blur': 'cancelRipple_',
- 'click': 'onClick_',
- 'focus': 'onFocus_',
- 'keyup': 'onKeyUp_',
- 'pointerup': 'cancelRipple_',
+ blur: 'cancelRipple_',
+ focus: 'onFocus_',
+ pointerup: 'cancelRipple_',
},
hostAttributes: {
'aria-disabled': 'false',
'aria-checked': 'false',
role: 'radio',
- tabindex: 0,
},
/** @private */
@@ -58,7 +62,6 @@ var CrRadioButtonBehaviorImpl = {
if (previous === undefined && !this.disabled)
return;
- this.setAttribute('tabindex', this.disabled ? -1 : 0);
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
},
@@ -68,30 +71,6 @@ var CrRadioButtonBehaviorImpl = {
this.$$('paper-ripple').holdDown = true;
},
- /**
- * @param {!Event} e
- * @private
- */
- onClick_: function(e) {
- // If this element is disabled, or event fired on a link, don't propagate
- // to the parent paper-radio-group to avoid incorrect selection.
- if (this.disabled || e.target.tagName == 'A')
- e.stopPropagation();
- },
-
- /**
- * @param {!Event} e
- * @private
- */
- onKeyUp_: function(e) {
- if (e.key != ' ' && e.key != 'Enter')
- return;
-
- // Simulating click on the key-up target, and let onClick decide if it
- // should be propagated to the parent paper-radio-group.
- e.target.click();
- },
-
/** @private */
cancelRipple_: function() {
this.ensureRipple();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html
index 3da38f4789c..4ff9b856567 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html
@@ -10,6 +10,7 @@
:host {
--cr-radio-button-ink-size: 40px;
--cr-radio-button-size: 16px;
+ --cr-radio-button-unchecked-color: var(--google-grey-refresh-700);
--cr-radio-button-checked-color: var(--google-blue-600);
--ink-to-circle: calc((var(--cr-radio-button-ink-size) -
@@ -65,7 +66,7 @@
}
.disc-border {
- border: 2px solid var(--google-grey-refresh-700);
+ border: 2px solid var(--cr-radio-button-unchecked-color);
}
:host([checked]) .disc-border {
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn
new file mode 100644
index 00000000000..9d50b536d20
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn
@@ -0,0 +1,18 @@
+# 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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":cr_radio_group",
+ ]
+}
+
+js_library("cr_radio_group") {
+ deps = [
+ "//ui/webui/resources/js:event_tracker",
+ ]
+ externs_list = [ "$externs_path/pending.js" ]
+}
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.html b/chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.html
new file mode 100644
index 00000000000..28215247498
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.html
@@ -0,0 +1,30 @@
+<link rel="import" href="../../html/polymer.html">
+
+<link rel="import" href="../../html/event_tracker.html">
+<link rel="import" href="../shared_vars_css.html">
+
+<dom-module id="cr-radio-group">
+ <template>
+ <style>
+ :host {
+ display: inline-block;
+ }
+
+ :host ::slotted(*) {
+ padding: var(--cr-radio-group-item-padding, 12px);
+ }
+
+ :host([disabled]) {
+ cursor: initial;
+ pointer-events: none;
+ user-select: none;
+ }
+
+ :host([disabled]) ::slotted(*) {
+ opacity: var(--cr-disabled-opacity);
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <script src="cr_radio_group.js"></script>
+</dom-module>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js b/chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js
new file mode 100644
index 00000000000..328f071d894
--- /dev/null
+++ b/chromium/ui/webui/resources/cr_elements/cr_radio_group/cr_radio_group.js
@@ -0,0 +1,250 @@
+// 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.
+
+(() => {
+
+ /**
+ * @param {!Element} radio
+ * @return {boolean}
+ */
+ function isEnabled(radio) {
+ return radio.matches(':not([disabled]):not([hidden])') &&
+ radio.style.display != 'none' && radio.style.visibility != 'hidden';
+ }
+
+ Polymer({
+ is: 'cr-radio-group',
+
+ properties: {
+ disabled: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
+
+ selected: {
+ type: String,
+ notify: true,
+ },
+
+ selectable: {
+ type: String,
+ value: 'cr-radio-button, controlled-radio-button',
+ },
+
+ /**
+ * @type {!RegExp}
+ * @private
+ */
+ selectableRegExp_: {
+ value: Object,
+ computed: 'computeSelectableRegExp_(selectable)',
+ },
+ },
+
+ listeners: {
+ keydown: 'onKeyDown_',
+ click: 'onClick_',
+ },
+
+ observers: [
+ 'update_(disabled, selected)',
+ ],
+
+ hostAttributes: {
+ role: 'radiogroup',
+ },
+
+ /** @private {Array<!Element>} */
+ buttons_: null,
+
+ /** @private {EventTracker} */
+ buttonEventTracker_: null,
+
+ /** @private {Map<string, number>} */
+ deltaKeyMap_: null,
+
+ /** @private {boolean} */
+ isRtl_: false,
+
+ /** @private {PolymerDomApi.ObserveHandle} */
+ observer_: null,
+
+ /** @private {Function} */
+ populateBound_: null,
+
+ /** @override */
+ attached: function() {
+ this.isRtl_ = this.matches(':host-context([dir=rtl]) cr-slider');
+ this.deltaKeyMap_ = new Map([
+ ['ArrowDown', 1],
+ ['ArrowLeft', this.isRtl_ ? 1 : -1],
+ ['ArrowRight', this.isRtl_ ? -1 : 1],
+ ['ArrowUp', -1],
+ ['PageDown', 1],
+ ['PageUp', -1],
+ ]);
+ this.buttonEventTracker_ = new EventTracker();
+
+ this.populateBound_ = () => this.populate_();
+ // Needed for when the radio buttons change when using dom-repeat or
+ // dom-if.
+ // TODO(crbug.com/738611): After migration to Polymer 2, remove Polymer 1
+ // references.
+ if (Polymer.DomIf)
+ this.$$('slot').addEventListener('slotchange', this.populateBound_);
+ else
+ this.observer_ = Polymer.dom(this).observeNodes(this.populateBound_);
+
+ this.populate_();
+ },
+
+ /** @override */
+ detached: function() {
+ if (Polymer.DomIf)
+ this.$$('slot').removeEventListener('slotchange', this.populateBound_);
+ else if (this.observer_) {
+ Polymer.dom(this).unobserveNodes(
+ /** @type {!PolymerDomApi.ObserveHandle} */ (this.observer_));
+ }
+ this.buttonEventTracker_.removeAll();
+ },
+
+ /** @override */
+ focus: function() {
+ if (this.disabled || !this.buttons_)
+ return;
+
+ const radio =
+ this.buttons_.find(radio => radio.getAttribute('tabindex') == '0');
+ if (radio)
+ radio.focus();
+ },
+
+ /**
+ * @param {!KeyboardEvent} event
+ * @private
+ */
+ onKeyDown_: function(event) {
+ if (this.disabled)
+ return;
+
+ if (event.ctrlKey || event.shiftKey || event.metaKey || event.altKey)
+ return;
+
+ const targetElement = /** @type {!Element} */ (event.target);
+ if (!this.buttons_.includes(targetElement))
+ return;
+
+ if (event.key == ' ' || event.key == 'Enter') {
+ event.preventDefault();
+ this.select_(/** @type {!Element} */ (event.target));
+ return;
+ }
+
+ const enabledRadios = this.buttons_.filter(isEnabled);
+ if (enabledRadios.length == 0)
+ return;
+
+ let selectedIndex;
+ const max = enabledRadios.length - 1;
+ if (event.key == 'Home') {
+ selectedIndex = 0;
+ } else if (event.key == 'End') {
+ selectedIndex = max;
+ } else if (this.deltaKeyMap_.has(event.key)) {
+ const delta = this.deltaKeyMap_.get(event.key);
+ // If nothing selected, start from the first radio then add |delta|.
+ const lastSelection = enabledRadios.findIndex(radio => radio.checked);
+ selectedIndex = Math.max(0, lastSelection) + delta;
+ selectedIndex = Math.min(max, Math.max(0, selectedIndex));
+ } else {
+ return;
+ }
+
+ const radio = enabledRadios[selectedIndex];
+ const name = `${radio.name}`;
+ if (this.selected != name) {
+ event.preventDefault();
+ this.selected = name;
+ radio.focus();
+ }
+ },
+
+ /**
+ * @return {!RegExp}
+ * @private
+ */
+ computeSelectableRegExp_: function() {
+ const tags = this.selectable.split(', ').join('|');
+ return new RegExp(`^(${tags})$`, 'i');
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onClick_: function(event) {
+ const path = event.composedPath();
+ if (path.some(target => /^a$/i.test(target.tagName)))
+ return;
+ const target = /** @type {!Element} */ (
+ path.find(n => this.selectableRegExp_.test(n.tagName)));
+ if (target && this.buttons_.includes(target))
+ this.select_(/** @type {!Element} */ (target));
+ },
+
+ /** @private */
+ populate_: function() {
+ // TODO(crbug.com/738611): After migration to Polymer 2, remove
+ // Polymer 1 references.
+ this.buttons_ = Polymer.DomIf ?
+ this.$$('slot')
+ .assignedNodes({flatten: true})
+ .filter(n => this.selectableRegExp_.test(n.tagName)) :
+ this.queryAllEffectiveChildren(this.selectable);
+ this.buttonEventTracker_.removeAll();
+ this.buttons_.forEach(el => {
+ this.buttonEventTracker_.add(
+ el, 'disabled-changed', () => this.populate_());
+ this.buttonEventTracker_.add(
+ el, 'name-changed', () => this.populate_());
+ });
+ this.update_();
+ },
+
+ /**
+ * @param {!Element} button
+ * @private
+ */
+ select_: function(button) {
+ if (!isEnabled(button))
+ return;
+
+ const name = `${button.name}`;
+ if (this.selected != name)
+ this.selected = name;
+ },
+
+ /** @private */
+ update_: function() {
+ if (!this.buttons_)
+ return;
+ let noneMadeFocusable = true;
+ this.buttons_.forEach(radio => {
+ radio.checked = this.selected != undefined &&
+ radio.name == this.selected;
+ const canBeFocused =
+ radio.checked && !this.disabled && isEnabled(radio);
+ noneMadeFocusable &= !canBeFocused;
+ radio.setAttribute('tabindex', canBeFocused ? '0' : '-1');
+ });
+ if (noneMadeFocusable && !this.disabled) {
+ const focusable = this.buttons_.find(isEnabled);
+ if (focusable)
+ focusable.setAttribute('tabindex', '0');
+ }
+ },
+ });
+})();
diff --git a/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
index 9535c1a9b40..b27a0f80b54 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
@@ -35,20 +35,30 @@
*/
/** @polymerBehavior */
-var CrScrollableBehavior = {
+const CrScrollableBehavior = {
/** @private {number|null} */
intervalId_: null,
ready: function() {
- this.requestUpdateScroll();
+ const readyAsync = () => {
+ this.requestUpdateScroll();
+
+ // Listen to the 'scroll' event for each scrollable container.
+ const scrollableElements = this.root.querySelectorAll('[scrollable]');
+ for (let i = 0; i < scrollableElements.length; i++) {
+ scrollableElements[i].addEventListener(
+ 'scroll', this.updateScrollEvent_.bind(this));
+ }
+ };
- // Listen to the 'scroll' event for each scrollable container.
- var scrollableElements = this.root.querySelectorAll('[scrollable]');
- for (var i = 0; i < scrollableElements.length; i++) {
- scrollableElements[i].addEventListener(
- 'scroll', this.updateScrollEvent_.bind(this));
+ // TODO(dpapad): Remove Polymer 1 codepath when Polymer 2 migration has
+ // completed.
+ if (Polymer.DomIf) {
+ Polymer.RenderStatus.beforeNextRender(this, readyAsync);
+ return;
}
+ readyAsync();
},
detached: function() {
@@ -67,20 +77,20 @@ var CrScrollableBehavior = {
this.requestUpdateScroll();
- var nodeList = this.root.querySelectorAll('[scrollable] iron-list');
+ let nodeList = this.root.querySelectorAll('[scrollable] iron-list');
if (!nodeList.length)
return;
// Use setInterval to avoid initial render / sizing issues.
this.intervalId_ = window.setInterval(function() {
- var unreadyNodes = [];
- for (var i = 0; i < nodeList.length; i++) {
- var node = nodeList[i];
+ const unreadyNodes = [];
+ for (let i = 0; i < nodeList.length; i++) {
+ const node = nodeList[i];
if (node.parentNode.scrollHeight == 0) {
unreadyNodes.push(node);
continue;
}
- var ironList = /** @type {!IronListElement} */ (node);
+ const ironList = /** @type {!IronListElement} */ (node);
ironList.notifyResize();
}
if (unreadyNodes.length == 0) {
@@ -99,8 +109,8 @@ var CrScrollableBehavior = {
*/
requestUpdateScroll: function() {
requestAnimationFrame(function() {
- var scrollableElements = this.root.querySelectorAll('[scrollable]');
- for (var i = 0; i < scrollableElements.length; i++)
+ const scrollableElements = this.root.querySelectorAll('[scrollable]');
+ for (let i = 0; i < scrollableElements.length; i++)
this.updateScroll_(/** @type {!HTMLElement} */ (scrollableElements[i]));
}.bind(this));
},
@@ -117,7 +127,7 @@ var CrScrollableBehavior = {
/** @param {!IronListElement} list */
restoreScroll: function(list) {
this.async(function() {
- var scrollTop = list.savedScrollTops.shift();
+ const scrollTop = list.savedScrollTops.shift();
// Ignore scrollTop of 0 in case it was intermittent (we do not need to
// explicitly scroll to 0).
if (scrollTop != 0)
@@ -131,7 +141,7 @@ var CrScrollableBehavior = {
* @private
*/
updateScrollEvent_: function(event) {
- var scrollable = /** @type {!HTMLElement} */ (event.target);
+ const scrollable = /** @type {!HTMLElement} */ (event.target);
this.updateScroll_(scrollable);
},
diff --git a/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js
index 179a09753c2..929058b4344 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js
@@ -7,7 +7,7 @@
* <settings-subpage-search> for a simple implementation.
* @polymerBehavior
*/
-var CrSearchFieldBehavior = {
+const CrSearchFieldBehavior = {
properties: {
label: {
type: String,
@@ -55,7 +55,7 @@ var CrSearchFieldBehavior = {
* firing for this change.
*/
setValue: function(value, opt_noEvent) {
- var searchInput = this.getSearchInput();
+ const searchInput = this.getSearchInput();
searchInput.value = value;
this.onSearchTermInput();
@@ -73,8 +73,8 @@ var CrSearchFieldBehavior = {
// 300ms if the value length is 3
// 200ms if the value length is 4 or greater.
// The logic here was copied from WebKit's native 'search' event.
- var length = this.getValue().length;
- var timeoutMs = length > 0 ? (500 - 100 * (Math.min(length, 4) - 1)) : 0;
+ const length = this.getValue().length;
+ const timeoutMs = length > 0 ? (500 - 100 * (Math.min(length, 4) - 1)) : 0;
this.searchDelayTimer_ = setTimeout(() => {
this.getSearchInput().dispatchEvent(
new CustomEvent('search', {composed: true, detail: this.getValue()}));
diff --git a/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.html b/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.html
index f6203a2f110..7f6bcd2d7bd 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.html
@@ -11,6 +11,7 @@
<template>
<style include="cr-hidden-style">
:host {
+ --cr-slider-bar-height: 2px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
cursor: default;
user-select: none;
@@ -25,27 +26,37 @@
position: relative;
}
+ #barContainer,
+ #bar {
+ /* Using border instead of background-color to address pixel rounding
+ at low zoom levels (e.g. 33%). The browser will round border widths
+ to a minimum of 1px.*/
+ border-top-style: solid;
+ border-top-width: 2px;
+ }
+
#barContainer {
- background-color: var(--google-blue-600-opacity-24);
- border-radius: 1px;
- height: 2px;
+ border-top-color: var(--google-blue-600-opacity-24);
+ height: var(--cr-slider-bar-height);
margin: 0 16px;
position: absolute;
top: 15px;
width: calc(100% - 32px);
}
+ #barContainer div {
+ top: calc(-1 * var(--cr-slider-bar-height));
+ }
+
#bar {
- background-color: var(--google-blue-600);
- border-radius: 1px;
- height: 2px;
+ border-top-color: var(--cr-slider-active-color, var(--google-blue-600));
left: 0;
position: absolute;
transition: width 80ms ease;
width: 0;
}
- :host-context([dir=rtl]) #bar {
+ :host([is-rtl_]) #bar {
left: initial;
right: 0;
}
@@ -58,7 +69,7 @@
}
#knob {
- background-color: var(--google-blue-600);
+ background-color: var(--cr-slider-knob-color, var(--google-blue-600));
border: 0;
border-radius: 50%;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
@@ -80,7 +91,7 @@
width: 32px;
}
- :host-context([dir=rtl]) paper-ripple {
+ :host([is-rtl_]) paper-ripple {
left: auto;
right: -11px;
}
@@ -90,7 +101,6 @@
pointer-events: none;
position: absolute;
right: 0;
- top: 0;
@apply --layout-horizontal;
}
@@ -148,28 +158,28 @@
white-space: nowrap;
}
- :host([disabled]) {
+ :host([disabled_]) {
pointer-events: none;
}
- :host([disabled]) #barContainer {
- background-color: var(--google-grey-600-opacity-24);
+ :host([disabled_]) #barContainer {
+ border-top-color: var(--google-grey-600-opacity-24);
}
- :host([disabled]) #bar {
- background-color: var(--google-grey-600);
+ :host([disabled_]) #bar {
+ border-top-color: var(--google-grey-600);
}
- :host([disabled]) inactive-marker::after,
- :host([disabled]) #markers::after {
- background-color: rgba(255, 255, 255, 0.54);
+ :host([disabled_]) .inactive-marker::after,
+ :host([disabled_]) #markers::after {
+ background-color: rgba(128, 134, 139, 0.54);
}
- :host([disabled]) #knobContainer {
- margin-inline-start: 9px;
+ :host([disabled_]) #knobContainer {
+ margin-inline-start: 10px;
top: 9px;
}
- :host([disabled]) #knob {
+ :host([disabled_]) #knob {
background-color: var(--google-grey-600);
border: 2px solid white;
box-shadow: unset;
diff --git a/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js b/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
index 97033f5ade8..c2671d9b700 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
@@ -45,12 +45,24 @@ cr_slider.SliderTick;
disabled: {
type: Boolean,
value: false,
+ },
+
+ /**
+ * Internal representation of disabled depending on |disabled| and
+ * |ticks|.
+ * @private
+ */
+ disabled_: {
+ type: Boolean,
+ computed: 'computeDisabled_(disabled, ticks.*)',
reflectToAttribute: true,
+ observer: 'onDisabledChanged_',
},
dragging: {
type: Boolean,
value: false,
+ notify: true,
reflectToAttribute: true,
},
@@ -69,6 +81,16 @@ cr_slider.SliderTick;
value: 0,
},
+ /**
+ * When set to false, the keybindings are not handled by this component,
+ * for example when the owner of the component wants to set up its own
+ * keybindings.
+ */
+ noKeybindings: {
+ type: Boolean,
+ value: false,
+ },
+
snaps: {
type: Boolean,
value: false,
@@ -82,7 +104,6 @@ cr_slider.SliderTick;
ticks: {
type: Array,
value: () => [],
- observer: 'onTicksChanged_',
},
value: {
@@ -125,6 +146,13 @@ cr_slider.SliderTick;
type: String,
value: '',
},
+
+ /** @private */
+ isRtl_: {
+ type: Boolean,
+ value: false,
+ reflectToAttribute: true,
+ },
},
hostAttributes: {
@@ -132,6 +160,7 @@ cr_slider.SliderTick;
},
observers: [
+ 'onTicksChanged_(ticks.*)',
'updateLabelAndAria_(immediateValue_, min, max)',
'updateKnobAndBar_(immediateValue_, min, max)',
],
@@ -146,15 +175,13 @@ cr_slider.SliderTick;
/** @private {Map<string, number>} */
deltaKeyMap_: null,
- /** @private {boolean} */
- isRtl_: false,
/** @private {EventTracker} */
draggingEventTracker_: null,
/** @override */
attached: function() {
- this.isRtl_ = this.matches(':host-context([dir=rtl]) cr-slider');
+ this.isRtl_ = window.getComputedStyle(this)['direction'] === 'rtl';
this.deltaKeyMap_ = new Map([
['ArrowDown', -1],
['ArrowUp', 1],
@@ -166,6 +193,11 @@ cr_slider.SliderTick;
this.draggingEventTracker_ = new EventTracker();
},
+ /** @private */
+ computeDisabled_: function() {
+ return this.disabled || this.ticks.length == 1;
+ },
+
/**
* When markers are displayed on the slider, they are evenly spaced across
* the entire slider bar container and are rendered on top of the bar and
@@ -218,15 +250,17 @@ cr_slider.SliderTick;
* @private
*/
stopDragging_: function(pointerId) {
- this.dragging = false;
- this.draggingEventTracker_.removeAll();
+ // Update |value| before updating |dragging| so dragging-changed event
+ // handlers will have access to the updated |value|.
this.value = this.immediateValue_;
+ this.draggingEventTracker_.removeAll();
+ this.releasePointerCapture(pointerId);
+ this.dragging = false;
// If there is a ripple animation in progress, setTimeout will hold off
// on updating |holdDown_|.
setTimeout(() => {
this.holdDown_ = false;
});
- this.releasePointerCapture(pointerId);
},
/** @private */
@@ -235,6 +269,12 @@ cr_slider.SliderTick;
},
/** @private */
+ onDisabledChanged_: function() {
+ this.$.knob.setAttribute('tabindex', this.disabled_ ? '-1' : '0');
+ this.blur();
+ },
+
+ /** @private */
onFocus_: function() {
this.holdDown_ = true;
},
@@ -249,25 +289,28 @@ cr_slider.SliderTick;
* @private
*/
onKeyDown_: function(event) {
- if (this.disabled)
+ if (this.disabled_ || this.noKeybindings)
return;
if (event.metaKey || event.shiftKey || event.altKey || event.ctrlKey)
return;
let handled = true;
- if (event.key == 'Home')
- this.value = this.min;
- else if (event.key == 'End')
- this.value = this.max;
- else if (this.deltaKeyMap_.has(event.key)) {
+ if (event.key == 'Home') {
+ this.immediateValue_ = this.min;
+ } else if (event.key == 'End') {
+ this.immediateValue_ = this.max;
+ } else if (this.deltaKeyMap_.has(event.key)) {
const newValue = this.value + this.deltaKeyMap_.get(event.key);
- this.value = clamp(this.min, this.max, newValue);
- } else
+ this.immediateValue_ = clamp(this.min, this.max, newValue);
+ } else {
handled = false;
+ }
if (handled) {
+ this.value = this.immediateValue_;
event.preventDefault();
+ event.stopPropagation();
setTimeout(() => {
this.holdDown_ = true;
});
@@ -281,17 +324,17 @@ cr_slider.SliderTick;
* @private
*/
onPointerDown_: function(event) {
- if (this.disabled || event.buttons != 1 && event.pointerType == 'mouse')
+ if (this.disabled_ || event.buttons != 1 && event.pointerType == 'mouse')
return;
this.dragging = true;
+ this.updateValueFromClientX_(event.clientX);
// If there is a ripple animation in progress, setTimeout will hold off on
// updating |holdDown_|.
setTimeout(() => {
this.$.knob.focus();
this.holdDown_ = true;
});
- this.updateValueFromClientX_(event.clientX);
this.setPointerCapture(event.pointerId);
const stopDragging = this.stopDragging_.bind(this, event.pointerId);
@@ -318,12 +361,8 @@ cr_slider.SliderTick;
/** @private */
onTicksChanged_: function() {
if (this.ticks.length == 0) {
- this.disabled = false;
this.snaps = false;
- } else if (this.ticks.length == 1) {
- this.disabled = true;
- } else {
- this.disabled = false;
+ } else if (this.ticks.length > 1) {
this.snaps = true;
this.max = this.ticks.length - 1;
this.min = 0;
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
index 0f5bcbfe904..722567559d7 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
+++ b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.html
@@ -23,7 +23,6 @@
transform: translateY(100px);
transition: opacity 300ms, transform 300ms, visibility 300ms;
visibility: hidden;
- white-space: nowrap;
z-index: 1;
}
@@ -34,16 +33,16 @@
}
:host ::slotted(paper-button) {
- background-color: transparent;
- border: none;
- color: var(--google-blue-300);
- margin-inline-start: 32px;
- min-width: 52px;
- padding: 8px;
+ background-color: transparent !important;
+ border: none !important;
+ color: var(--google-blue-300) !important;
+ margin-inline-start: 32px !important;
+ min-width: 52px !important;
+ padding: 8px !important;
}
:host ::slotted(paper-button:hover) {
- background-color: transparent;
+ background-color: transparent !important;
}
</style>
<slot></slot>
diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js
index 0f4f1a58275..7d8e04fc56a 100644
--- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js
+++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js
@@ -94,7 +94,7 @@ Polymer({
* @private
*/
computeIsSpinnerShown_: function() {
- var showSpinner = this.spinnerActive && this.showingSearch;
+ const showSpinner = this.spinnerActive && this.showingSearch;
if (showSpinner)
this.$.spinnerTemplate.if = true;
return showSpinner;
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
index 9a0f93e7644..7e4e460d6c9 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
@@ -21,10 +21,11 @@
* controlledSettingOwner: (string|undefined),
* }}
*/
+// eslint-disable-next-line no-var
var CrPolicyStrings;
/** @enum {string} */
-var CrPolicyIndicatorType = {
+const CrPolicyIndicatorType = {
DEVICE_POLICY: 'devicePolicy',
EXTENSION: 'extension',
NONE: 'none',
@@ -35,7 +36,7 @@ var CrPolicyIndicatorType = {
};
/** @polymerBehavior */
-var CrPolicyIndicatorBehavior = {
+const CrPolicyIndicatorBehavior = {
// Properties exposed to all policy indicators.
properties: {
/**
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
index c20b1ca4ec6..e1a2bad50fe 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
@@ -7,7 +7,7 @@
*/
/** @polymerBehavior */
-var CrPolicyNetworkBehavior = {
+const CrPolicyNetworkBehavior = {
/**
* @param {!CrOnc.ManagedProperty|undefined} property
* @return {boolean} True if the network property is controlled by a policy
@@ -19,7 +19,7 @@ var CrPolicyNetworkBehavior = {
if (typeof property != 'object' || !property.Effective)
return false;
// Enforced
- var effective = property.Effective;
+ const effective = property.Effective;
if (effective == 'UserPolicy' || effective == 'DevicePolicy')
return true;
// Recommended
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
index 94247f53552..52a50e3c9fa 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
@@ -7,9 +7,23 @@
<dom-module id="cr-policy-network-indicator">
<template>
- <style include="cr-hidden-style"></style>
+ <style include="cr-hidden-style">
+ /* This field is used for controlling margin of icon outside the indicator
+ * element (i.e. in the element which uses indicator itself). It's useful
+ * when we don't want to add margin to indicator if it's hidden and also
+ * don't want to move/duplicate logic about showing indicator and margin
+ * outside of indicator element. */
+ :host {
+ --cr-tooltip-icon-margin-start: 0;
+ }
+
+ cr-tooltip-icon {
+ margin-inline-start: var(--cr-tooltip-icon-margin-start);
+ }
+ </style>
<cr-tooltip-icon hidden$="[[!indicatorVisible]]"
- tooltip-text="[[indicatorTooltip_]]" icon-class="[[indicatorIcon]]">
+ tooltip-text="[[indicatorTooltip_]]" icon-class="[[indicatorIcon]]"
+ tooltip-position="[[tooltipPosition]]">
</cr-tooltip-icon>
</template>
<script src="cr_policy_network_indicator.js"></script>
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js
index b499ed4dd03..3d139581290 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js
@@ -15,10 +15,13 @@ Polymer({
properties: {
/**
* Network property associated with the indicator.
- * @type {!CrOnc.ManagedProperty|undefined}
+ * @type {?CrOnc.ManagedProperty|undefined}
*/
property: Object,
+ /** Position of tooltip popup related to the policy indicator. */
+ tooltipPosition: String,
+
/**
* Recommended value for non enforced properties.
* @private {!CrOnc.NetworkPropertyType|undefined}
@@ -36,13 +39,13 @@ Polymer({
/** @private */
propertyChanged_: function() {
- var property = this.property;
- if (!this.isControlled(property)) {
+ const property = this.property;
+ if (property == null || !this.isControlled(property)) {
this.indicatorType = CrPolicyIndicatorType.NONE;
return;
}
- var effective = property.Effective;
- var active = property.Active;
+ const effective = property.Effective;
+ let active = property.Active;
if (active == undefined)
active = property[effective];
@@ -78,10 +81,10 @@ Polymer({
if (this.property === undefined)
return '';
- var matches;
+ let matches;
if (this.indicatorType == CrPolicyIndicatorType.RECOMMENDED &&
this.property) {
- var value = this.property.Active;
+ let value = this.property.Active;
if (value == undefined && this.property.Effective)
value = this.property[this.property.Effective];
matches = value == this.recommended_;
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js
index 974bb293213..2acb61d6fa5 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_behavior.js
@@ -7,7 +7,7 @@
*/
/** @polymerBehavior */
-var CrPolicyPrefBehavior = {
+const CrPolicyPrefBehavior = {
properties: {
/**
* Showing that an extension is controlling a pref is sometimes done with a
@@ -32,6 +32,9 @@ var CrPolicyPrefBehavior = {
* @return {boolean} True if |this.pref| has a recommended or enforced policy.
*/
hasPrefPolicyIndicator: function() {
+ if (!this.pref) {
+ return false;
+ }
if (this.noExtensionIndicator &&
this.pref.controlledBy ==
chrome.settingsPrivate.ControlledBy.EXTENSION) {
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
index b83f94971b0..2898061a3ed 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
@@ -71,10 +71,10 @@ Polymer({
* @private
*/
getIndicatorTooltipForPref_: function(indicatorType) {
- if (this.pref === undefined)
+ if (!this.pref)
return '';
- var matches = this.pref && this.pref.value == this.pref.recommendedValue;
+ const matches = this.pref && this.pref.value == this.pref.recommendedValue;
return this.getIndicatorTooltip(
indicatorType, this.pref.controlledByName || '', matches);
},
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
index c080e10f7d6..9be843aa737 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
@@ -23,7 +23,7 @@
</style>
<iron-icon id="indicator" tabindex="0" aria-label$="[[iconAriaLabel]]"
aria-describedby="tooltip" icon="[[iconClass]]"></iron-icon>
- <paper-tooltip id="tooltip" for="indicator" position="top"
+ <paper-tooltip id="tooltip" for="indicator" position="[[tooltipPosition]]"
fit-to-visible-bounds>
[[tooltipText]]
</paper-tooltip>
diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.js b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.js
index cd8cd9cc2ab..d0dda6ebde5 100644
--- a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.js
+++ b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.js
@@ -4,10 +4,19 @@
Polymer({
is: 'cr-tooltip-icon',
+
properties: {
iconAriaLabel: String,
+
iconClass: String,
+
tooltipText: String,
+
+ /** Position of tooltip popup related to the icon. */
+ tooltipPosition: {
+ type: String,
+ value: 'top',
+ }
},
/** @return {!Element} */
diff --git a/chromium/ui/webui/resources/cr_elements/shared_style_css.html b/chromium/ui/webui/resources/cr_elements/shared_style_css.html
index 6b0631c4a79..f0a0b5de7bc 100644
--- a/chromium/ui/webui/resources/cr_elements/shared_style_css.html
+++ b/chromium/ui/webui/resources/cr_elements/shared_style_css.html
@@ -55,11 +55,11 @@
min-height: 1px;
}
- [selectable]:not(paper-radio-group):focus,
- [selectable]:not(paper-radio-group) > :focus {
+ [selectable]:not(cr-radio-group):focus,
+ [selectable]:not(cr-radio-group) > :focus {
@apply --cr-selectable-focus;
}
- [selectable]:not(paper-radio-group) > * {
+ [selectable]:not(cr-radio-group) > * {
@apply --cr-actionable;
}
diff --git a/chromium/ui/webui/resources/cr_elements_resources.grdp b/chromium/ui/webui/resources/cr_elements_resources.grdp
index 040b089fbef..a5ee1112548 100644
--- a/chromium/ui/webui/resources/cr_elements_resources.grdp
+++ b/chromium/ui/webui/resources/cr_elements_resources.grdp
@@ -110,6 +110,14 @@
file="cr_elements/cr_radio_button/cr_radio_button_style_css.html"
type="chrome_html"
compress="gzip" />
+ <structure name="IDR_CR_ELEMENTS_CR_RADIO_GROUP_HTML"
+ file="cr_elements/cr_radio_group/cr_radio_group.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_CR_ELEMENTS_CR_RADIO_GROUP_JS"
+ file="cr_elements/cr_radio_group/cr_radio_group.js"
+ type="chrome_html"
+ compress="gzip" />
<structure name="IDR_CR_ELEMENTS_CR_SLIDER_HTML"
file="cr_elements/cr_slider/cr_slider.html"
type="chrome_html"
diff --git a/chromium/ui/webui/resources/js/action_link.js b/chromium/ui/webui/resources/js/action_link.js
index ac67d320ebe..99dc0fdf3df 100644
--- a/chromium/ui/webui/resources/js/action_link.js
+++ b/chromium/ui/webui/resources/js/action_link.js
@@ -27,90 +27,78 @@
//
// NOTE: <action-link> and document.createElement('action-link') don't work.
-/**
- * See crbug.com/837381
- * @suppress {deprecated}
- *
- * @constructor
- * @extends {HTMLAnchorElement}
- */
-var ActionLink = document.registerElement('action-link', {
- prototype: {
- __proto__: HTMLAnchorElement.prototype,
+class ActionLink extends HTMLAnchorElement {
+ connectedCallback() {
+ // Action links can start disabled (e.g. <a is="action-link" disabled>).
+ this.tabIndex = this.disabled ? -1 : 0;
- /** @this {ActionLink} */
- createdCallback: function() {
- // Action links can start disabled (e.g. <a is="action-link" disabled>).
- this.tabIndex = this.disabled ? -1 : 0;
+ if (!this.hasAttribute('role'))
+ this.setAttribute('role', 'link');
- if (!this.hasAttribute('role'))
- this.setAttribute('role', 'link');
-
- this.addEventListener('keydown', function(e) {
- if (!this.disabled && e.key == 'Enter' && !this.href) {
- // Schedule a click asynchronously because other 'keydown' handlers
- // may still run later (e.g. document.addEventListener('keydown')).
- // Specifically options dialogs break when this timeout isn't here.
- // NOTE: this affects the "trusted" state of the ensuing click. I
- // haven't found anything that breaks because of this (yet).
- window.setTimeout(this.click.bind(this), 0);
- }
- });
-
- function preventDefault(e) {
- e.preventDefault();
+ this.addEventListener('keydown', function(e) {
+ if (!this.disabled && e.key == 'Enter' && !this.href) {
+ // Schedule a click asynchronously because other 'keydown' handlers
+ // may still run later (e.g. document.addEventListener('keydown')).
+ // Specifically options dialogs break when this timeout isn't here.
+ // NOTE: this affects the "trusted" state of the ensuing click. I
+ // haven't found anything that breaks because of this (yet).
+ window.setTimeout(this.click.bind(this), 0);
}
+ });
- function removePreventDefault() {
- document.removeEventListener('selectstart', preventDefault);
- document.removeEventListener('mouseup', removePreventDefault);
- }
+ function preventDefault(e) {
+ e.preventDefault();
+ }
+
+ function removePreventDefault() {
+ document.removeEventListener('selectstart', preventDefault);
+ document.removeEventListener('mouseup', removePreventDefault);
+ }
- this.addEventListener('mousedown', function() {
- // This handlers strives to match the behavior of <a href="...">.
+ this.addEventListener('mousedown', function() {
+ // This handlers strives to match the behavior of <a href="...">.
- // While the mouse is down, prevent text selection from dragging.
- document.addEventListener('selectstart', preventDefault);
- document.addEventListener('mouseup', removePreventDefault);
+ // While the mouse is down, prevent text selection from dragging.
+ document.addEventListener('selectstart', preventDefault);
+ document.addEventListener('mouseup', removePreventDefault);
- // If focus started via mouse press, don't show an outline.
- if (document.activeElement != this)
- this.classList.add('no-outline');
- });
+ // If focus started via mouse press, don't show an outline.
+ if (document.activeElement != this)
+ this.classList.add('no-outline');
+ });
- this.addEventListener('blur', function() {
- this.classList.remove('no-outline');
- });
- },
+ this.addEventListener('blur', function() {
+ this.classList.remove('no-outline');
+ });
+ }
- /** @type {boolean} */
- set disabled(disabled) {
- if (disabled)
- HTMLAnchorElement.prototype.setAttribute.call(this, 'disabled', '');
- else
- HTMLAnchorElement.prototype.removeAttribute.call(this, 'disabled');
- this.tabIndex = disabled ? -1 : 0;
- },
- get disabled() {
- return this.hasAttribute('disabled');
- },
+ /** @param {boolean} disabled */
+ set disabled(disabled) {
+ if (disabled)
+ HTMLAnchorElement.prototype.setAttribute.call(this, 'disabled', '');
+ else
+ HTMLAnchorElement.prototype.removeAttribute.call(this, 'disabled');
+ this.tabIndex = disabled ? -1 : 0;
+ }
- /** @override */
- setAttribute: function(attr, val) {
- if (attr.toLowerCase() == 'disabled')
- this.disabled = true;
- else
- HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
- },
+ get disabled() {
+ return this.hasAttribute('disabled');
+ }
- /** @override */
- removeAttribute: function(attr) {
- if (attr.toLowerCase() == 'disabled')
- this.disabled = false;
- else
- HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
- },
- },
+ /** @override */
+ setAttribute(attr, val) {
+ if (attr.toLowerCase() == 'disabled')
+ this.disabled = true;
+ else
+ HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
+ }
- extends: 'a',
-});
+ /** @override */
+ removeAttribute(attr) {
+ if (attr.toLowerCase() == 'disabled')
+ this.disabled = false;
+ else
+ HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
+ }
+}
+customElements.define('action-link', ActionLink, {extends: 'a'});
diff --git a/chromium/ui/webui/resources/js/analytics.js b/chromium/ui/webui/resources/js/analytics.js
deleted file mode 100644
index b0893a6f98c..00000000000
--- a/chromium/ui/webui/resources/js/analytics.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 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.
-
-// This file serves as a proxy to bring the included js file from /third_party
-// into its correct location under the resources directory tree, whence it is
-// delivered via a chrome://resources URL. See ../webui_resources.grd.
-
-// Note: this <include> is not behind a single-line comment because the first
-// line of the file is source code (so the first line would be skipped) instead
-// of a licence header.
-// clang-format off
-<include src="../../../../third_party/analytics/google-analytics-bundle.js">
diff --git a/chromium/ui/webui/resources/js/cr/ui/command.js b/chromium/ui/webui/resources/js/cr/ui/command.js
index f42f3ef0b4f..e2bd5193b33 100644
--- a/chromium/ui/webui/resources/js/cr/ui/command.js
+++ b/chromium/ui/webui/resources/js/cr/ui/command.js
@@ -24,26 +24,30 @@ cr.define('cr.ui', function() {
* @constructor
*/
function KeyboardShortcut(shortcut) {
- var mods = {};
- var ident = '';
- shortcut.split('|').forEach(function(part) {
+ this.useKeyCode_ = false;
+ this.mods_ = {};
+ shortcut.split('|').forEach((part) => {
var partLc = part.toLowerCase();
switch (partLc) {
case 'alt':
case 'ctrl':
case 'meta':
case 'shift':
- mods[partLc + 'Key'] = true;
+ this.mods_[partLc + 'Key'] = true;
break;
default:
- if (ident)
+ if (this.key_)
throw Error('Invalid shortcut');
- ident = part;
+ this.key_ = part;
+ // For single key alpha shortcuts use event.keyCode rather than
+ // event.key to match how chrome handles shortcuts and allow
+ // non-english language input to work.
+ if (part.match(/^[a-z]$/)) {
+ this.useKeyCode_ = true;
+ this.keyCode_ = part.toUpperCase().charCodeAt(0);
+ }
}
});
-
- this.ident_ = ident;
- this.mods_ = mods;
}
KeyboardShortcut.prototype = {
@@ -53,8 +57,9 @@ cr.define('cr.ui', function() {
* @return {boolean} Whether we found a match or not.
*/
matchesEvent: function(e) {
- if (e.key == this.ident_) {
- // All keyboard modifiers needs to match.
+ if ((this.useKeyCode_ && e.keyCode == this.keyCode_) ||
+ e.key == this.key_) {
+ // All keyboard modifiers need to match.
var mods = this.mods_;
return ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].every(function(k) {
return e[k] == !!mods[k];
diff --git a/chromium/ui/webui/resources/js/cr/ui/dialogs.js b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
index a2aff076194..086560391fc 100644
--- a/chromium/ui/webui/resources/js/cr/ui/dialogs.js
+++ b/chromium/ui/webui/resources/js/cr/ui/dialogs.js
@@ -112,7 +112,7 @@ cr.define('cr.ui.dialogs', function() {
/** @private */
BaseDialog.prototype.onContainerMouseDown_ = function(event) {
if (event.target == this.container_) {
- var classList = this.frame_.classList;
+ var classList = this.container_.classList;
// Start 'pulse' animation.
classList.remove('pulse');
setTimeout(classList.add.bind(classList, 'pulse'), 0);
diff --git a/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js b/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js
index a51f2ac9bff..9f293041a02 100644
--- a/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js
+++ b/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js
@@ -105,8 +105,14 @@ cr.define('cr.ui', function() {
* @private
*/
getNearestSelectedIndex_: function(index) {
- if (index == -1)
+ if (index == -1) {
+ // If no index is provided, pick the first selected index if there is
+ // one.
+ if (this.selectedIndexes.length) {
+ return this.selectedIndexes[0];
+ }
return -1;
+ }
var result = Infinity;
for (var i in this.selectedIndexes_) {
@@ -348,8 +354,15 @@ cr.define('cr.ui', function() {
if (oldSelectedItemsCount && !this.selectedIndexes.length &&
this.length_ && oldLeadIndex != -1) {
// All selected items are deleted. We move selection to next item of
- // last selected item.
- this.selectedIndexes = [Math.min(oldLeadIndex, this.length_ - 1)];
+ // last selected item, following it to its new position.
+ let newSelectedIndex = Math.min(oldLeadIndex, this.length_ - 1);
+ for (let i = oldLeadIndex + 1; i < permutation.length; ++i) {
+ if (permutation[i] != -1) {
+ newSelectedIndex = permutation[i];
+ break;
+ }
+ }
+ this.selectedIndexes = [newSelectedIndex];
}
this.endChange();
diff --git a/chromium/ui/webui/resources/js/cr/ui/menu.js b/chromium/ui/webui/resources/js/cr/ui/menu.js
index ed00ed84f6a..7560a63fb4f 100644
--- a/chromium/ui/webui/resources/js/cr/ui/menu.js
+++ b/chromium/ui/webui/resources/js/cr/ui/menu.js
@@ -202,14 +202,16 @@ cr.define('cr.ui', function() {
},
/**
- * Returns if the menu has any visible item.
+ * Returns whether the menu has any visible items.
* @return {boolean} True if the menu has visible item. Otherwise, false.
*/
hasVisibleItems: function() {
- var menuItems = this.menuItems; // Cache.
- for (var i = 0, menuItem; menuItem = menuItems[i]; i++) {
- if (!menuItem.isSeparator() && this.isItemVisible_(menuItem))
+ // Inspect items in reverse order to determine if the separator above each
+ // set of items is required.
+ for (let menuItem of this.menuItems) {
+ if (this.isItemVisible_(menuItem)) {
return true;
+ }
}
return false;
},
@@ -310,6 +312,27 @@ cr.define('cr.ui', function() {
if (!menuItem.isSeparator())
menuItem.updateCommand(node);
}
+
+ let separatorRequired = false;
+ let lastSeparator = null;
+ // Hide any separators without a visible item between them and the next
+ // separator or the end of the menu.
+ for (let menuItem of menuItems) {
+ if (menuItem.isSeparator()) {
+ if (separatorRequired) {
+ lastSeparator = menuItem;
+ }
+ menuItem.hidden = true;
+ separatorRequired = false;
+ continue;
+ }
+ if (this.isItemVisible_(menuItem)) {
+ if (lastSeparator) {
+ lastSeparator.hidden = false;
+ }
+ separatorRequired = true;
+ }
+ }
}
};
diff --git a/chromium/ui/webui/resources/js/cr/ui/menu_test.html b/chromium/ui/webui/resources/js/cr/ui/menu_test.html
deleted file mode 100644
index 05b601edf6c..00000000000
--- a/chromium/ui/webui/resources/js/cr/ui/menu_test.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<script src="https://cdn.rawgit.com/google/closure-library/master/closure/goog/base.js"></script>
-<script src="../../cr.js"></script>
-<script src="../event_target.js"></script>
-<script src="../ui.js"></script>
-<script src="command.js"></script>
-<script src="menu.js"></script>
-<script src="menu_item.js"></script>
-<script>
-
-goog.require('goog.testing.jsunit');
-
-</script>
-
-</head>
-<body>
-
-<script>
-
-/**
- * Tests that if the command attributes are spacified, they are copied to the
- * corresponding menuitem.
- */
-function testCommandMenuItem() {
- // Test 1: The case that the command label is set and other attributes copied.
- var command = new cr.ui.Command();
- command.id = 'the-command';
- command.label = 'CommandLabel';
- command.disabled = true;
- command.hidden = true;
- command.checked = true;
- document.body.appendChild(command);
-
- var menuItem = new cr.ui.MenuItem();
- menuItem.command = '#the-command';
-
- // Confirms the label is copied from the command.
- assertEquals('CommandLabel', menuItem.label);
- // Confirms the attributes are copied from the command.
- assertEquals(true, menuItem.disabled);
- assertEquals(true, menuItem.hidden);
- assertEquals(true, menuItem.checked);
-
- // Test 2: The case that the command label is not set, and other attributes
- // have default values.
- var command2 = new cr.ui.Command();
- command2.id = 'the-command2';
- document.body.appendChild(command2);
-
- var menuItem2 = new cr.ui.MenuItem();
- menuItem2.label = 'MenuLabel';
- menuItem2.command = '#the-command2';
-
- // Confirms the label is not copied, keeping the original label.
- assertEquals('MenuLabel', menuItem2.label);
- // Confirms the attributes are copied from the command.
- assertEquals(false, menuItem2.disabled);
- assertEquals(false, menuItem2.hidden);
- assertEquals(false, menuItem2.checked);
-}
-
-</script>
-
-</body>
-</html>
diff --git a/chromium/ui/webui/resources/js/polymer_config.js b/chromium/ui/webui/resources/js/polymer_config.js
index 5ceafb2ee7e..119d9479024 100644
--- a/chromium/ui/webui/resources/js/polymer_config.js
+++ b/chromium/ui/webui/resources/js/polymer_config.js
@@ -6,6 +6,7 @@ if (typeof Polymer == 'undefined') {
Polymer = {
dom: 'shadow',
lazyRegister: true,
+ legacyOptimizations: true,
preserveStyleIncludes: true, // Only matters when using polymer-css-build.
suppressBindingNotifications: true,
suppressTemplateNotifications: true,
diff --git a/chromium/ui/webui/resources/polymer_resources.grdp b/chromium/ui/webui/resources/polymer_resources.grdp
index 4327022a41f..dd29898881a 100644
--- a/chromium/ui/webui/resources/polymer_resources.grdp
+++ b/chromium/ui/webui/resources/polymer_resources.grdp
@@ -48,14 +48,6 @@
file="../../../third_party/polymer/v1_0/components-chromium/iron-a11y-keys/iron-a11y-keys.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_AUTOGROW_TEXTAREA_IRON_AUTOGROW_TEXTAREA_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_AUTOGROW_TEXTAREA_IRON_AUTOGROW_TEXTAREA_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_IRON_BEHAVIORS_IRON_BUTTON_STATE_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state-extracted.js"
type="chrome_html"
@@ -72,14 +64,6 @@
file="../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_CHECKED_ELEMENT_BEHAVIOR_IRON_CHECKED_ELEMENT_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-checked-element-behavior/iron-checked-element-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_CHECKED_ELEMENT_BEHAVIOR_IRON_CHECKED_ELEMENT_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-checked-element-behavior/iron-checked-element-behavior.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_IRON_COLLAPSE_IRON_COLLAPSE_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/iron-collapse/iron-collapse-extracted.js"
type="chrome_html"
@@ -144,14 +128,16 @@
file="../../../third_party/polymer/v1_0/components-chromium/iron-iconset-svg/iron-iconset-svg.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_INPUT_IRON_INPUT_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-input/iron-input-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_IRON_INPUT_IRON_INPUT_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/iron-input/iron-input.html"
- type="chrome_html"
- compress="gzip" />
+ <if expr="chromeos">
+ <structure name="IDR_POLYMER_1_0_IRON_INPUT_IRON_INPUT_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-input/iron-input-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_IRON_INPUT_IRON_INPUT_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/iron-input/iron-input.html"
+ type="chrome_html"
+ compress="gzip" />
+ </if>
<structure name="IDR_POLYMER_1_0_IRON_LIST_IRON_LIST_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/iron-list/iron-list-extracted.js"
type="chrome_html"
@@ -508,14 +494,6 @@
file="../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-button-behavior.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_BEHAVIORS_PAPER_CHECKED_ELEMENT_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-checked-element-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_BEHAVIORS_PAPER_CHECKED_ELEMENT_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-checked-element-behavior.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_PAPER_BEHAVIORS_PAPER_INKY_FOCUS_BEHAVIOR_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-inky-focus-behavior-extracted.js"
type="chrome_html"
@@ -564,106 +542,52 @@
file="../../../third_party/polymer/v1_0/components-chromium/paper-icon-button/paper-icon-button.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ADDON_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-addon-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ADDON_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-addon-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_CHAR_COUNTER_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-char-counter-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_CHAR_COUNTER_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-char-counter.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_CONTAINER_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_CONTAINER_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ERROR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ERROR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_TEXTAREA_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_TEXTAREA_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ICON_ITEM_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ICON_ITEM_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_BEHAVIOR_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-behavior-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_BEHAVIOR_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-behavior.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_BODY_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-body-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_BODY_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-body.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_SHARED_STYLES_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-shared-styles.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item.html"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_LISTBOX_PAPER_LISTBOX_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_LISTBOX_PAPER_LISTBOX_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox.html"
- type="chrome_html"
- compress="gzip" />
+ <if expr="chromeos">
+ <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ADDON_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-addon-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ADDON_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-addon-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_CONTAINER_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_CONTAINER_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-container.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ERROR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_ERROR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ICON_ITEM_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ICON_ITEM_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_BEHAVIOR_EXTRACTED_JS"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-behavior-extracted.js"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_BEHAVIOR_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-behavior.html"
+ type="chrome_html"
+ compress="gzip" />
+ <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ITEM_SHARED_STYLES_HTML"
+ file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-shared-styles.html"
+ type="chrome_html"
+ compress="gzip" />
+ </if>
<structure name="IDR_POLYMER_1_0_PAPER_PROGRESS_PAPER_PROGRESS_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress-extracted.js"
type="chrome_html"
@@ -672,14 +596,6 @@
file="../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress.html"
type="chrome_html"
compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_RADIO_GROUP_PAPER_RADIO_GROUP_EXTRACTED_JS"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-group/paper-radio-group-extracted.js"
- type="chrome_html"
- compress="gzip" />
- <structure name="IDR_POLYMER_1_0_PAPER_RADIO_GROUP_PAPER_RADIO_GROUP_HTML"
- file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-group/paper-radio-group.html"
- type="chrome_html"
- compress="gzip" />
<structure name="IDR_POLYMER_1_0_PAPER_RIPPLE_PAPER_RIPPLE_EXTRACTED_JS"
file="../../../third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js"
type="chrome_html"
diff --git a/chromium/ui/webui/resources/webui_resources.grd b/chromium/ui/webui/resources/webui_resources.grd
index a2b2e2d14bc..46c8b372f96 100644
--- a/chromium/ui/webui/resources/webui_resources.grd
+++ b/chromium/ui/webui/resources/webui_resources.grd
@@ -15,7 +15,6 @@ without changes to the corresponding grd file. -->
<includes>
<include name="IDR_WEBUI_I18N_TEMPLATE_JS" file="js/i18n_template.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_WEBUI_JSTEMPLATE_JS" file="js/jstemplate_compiled.js" flattenhtml="true" type="BINDATA" />
- <include name="IDR_WEBUI_ANALYTICS_JS" file="js/analytics.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<!-- Roboto Font. Roboto-Regular and Roboto-Light is already available on
Android, and Roboto-Medium is not used on Android. All 6 weights of
Roboto are available on Chrome OS.-->
diff --git a/chromium/ui/wm/core/accelerator_filter.cc b/chromium/ui/wm/core/accelerator_filter.cc
index 21f10d5bf05..598b141a885 100644
--- a/chromium/ui/wm/core/accelerator_filter.cc
+++ b/chromium/ui/wm/core/accelerator_filter.cc
@@ -28,16 +28,29 @@ AcceleratorFilter::AcceleratorFilter(
AcceleratorFilter::~AcceleratorFilter() {
}
+bool AcceleratorFilter::ShouldFilter(ui::KeyEvent* event) {
+ const ui::EventType type = event->type();
+ if (!event->target() ||
+ (type != ui::ET_KEY_PRESSED && type != ui::ET_KEY_RELEASED) ||
+ event->is_char() || !event->target() ||
+ // Key events with key code of VKEY_PROCESSKEY, usually created by virtual
+ // keyboard (like handwriting input), have no effect on accelerator and
+ // they may disturb the accelerator history. So filter them out. (see
+ // https://crbug.com/918317)
+ event->key_code() == ui::VKEY_PROCESSKEY) {
+ return true;
+ }
+
+ return false;
+}
+
////////////////////////////////////////////////////////////////////////////////
// AcceleratorFilter, EventFilter implementation:
void AcceleratorFilter::OnKeyEvent(ui::KeyEvent* event) {
- const ui::EventType type = event->type();
DCHECK(event->target());
- if ((type != ui::ET_KEY_PRESSED && type != ui::ET_KEY_RELEASED) ||
- event->is_char() || !event->target()) {
+ if (ShouldFilter(event))
return;
- }
ui::Accelerator accelerator(*event);
accelerator_history_->StoreCurrentAccelerator(accelerator);
diff --git a/chromium/ui/wm/core/accelerator_filter.h b/chromium/ui/wm/core/accelerator_filter.h
index 86bdf77e24f..18f2764512a 100644
--- a/chromium/ui/wm/core/accelerator_filter.h
+++ b/chromium/ui/wm/core/accelerator_filter.h
@@ -28,6 +28,9 @@ class WM_CORE_EXPORT AcceleratorFilter : public ui::EventHandler {
ui::AcceleratorHistory* accelerator_history);
~AcceleratorFilter() override;
+ // If the return value is true, |event| should be filtered out.
+ static bool ShouldFilter(ui::KeyEvent* event);
+
// Overridden from ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
diff --git a/chromium/ui/wm/core/window_animations_unittest.cc b/chromium/ui/wm/core/window_animations_unittest.cc
index f8e993a6814..dfd3127ce88 100644
--- a/chromium/ui/wm/core/window_animations_unittest.cc
+++ b/chromium/ui/wm/core/window_animations_unittest.cc
@@ -50,8 +50,6 @@ class WindowAnimationsTest : public aura::test::AuraTestBase {
public:
WindowAnimationsTest() {}
- void TearDown() override { AuraTestBase::TearDown(); }
-
private:
DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest);
};
diff --git a/chromium/ui/wm/core/window_modality_controller.cc b/chromium/ui/wm/core/window_modality_controller.cc
index 847e6cb70f1..44fbc4f8713 100644
--- a/chromium/ui/wm/core/window_modality_controller.cc
+++ b/chromium/ui/wm/core/window_modality_controller.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <algorithm>
+#include <queue>
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.h"
@@ -52,9 +53,8 @@ bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
HasAncestor(original, GetModalParent(transient))));
}
-aura::Window* GetModalTransientChild(
- aura::Window* activatable,
- aura::Window* original) {
+aura::Window* GetModalTransientChild(aura::Window* activatable,
+ aura::Window* original) {
for (aura::Window* transient : GetTransientChildren(activatable)) {
if (IsModalTransientChild(transient, original)) {
if (GetTransientChildren(transient).empty())
@@ -116,7 +116,7 @@ void WindowModalityController::OnKeyEvent(ui::KeyEvent* event) {
void WindowModalityController::OnMouseEvent(ui::MouseEvent* event) {
aura::Window* target = static_cast<aura::Window*>(event->target());
if (ProcessLocatedEvent(target, event))
- event->SetHandled();
+ event->SetHandled();
}
void WindowModalityController::OnTouchEvent(ui::TouchEvent* event) {
@@ -145,16 +145,16 @@ void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE &&
window->IsVisible()) {
ActivateWindow(window);
- env_->gesture_recognizer()->CancelActiveTouchesExcept(nullptr);
+ CancelTouchesOnTransientWindowTree(window);
}
}
-void WindowModalityController::OnWindowVisibilityChanged(
- aura::Window* window,
- bool visible) {
+void WindowModalityController::OnWindowVisibilityChanged(aura::Window* window,
+ bool visible) {
if (visible &&
window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) {
- env_->gesture_recognizer()->CancelActiveTouchesExcept(nullptr);
+ CancelTouchesOnTransientWindowTree(window);
+
// Make sure no other window has capture, otherwise |window| won't get mouse
// events.
aura::Window* capture_window = aura::client::GetCaptureWindow(window);
@@ -201,4 +201,28 @@ bool WindowModalityController::ProcessLocatedEvent(aura::Window* target,
return !!modal_transient_child;
}
+void WindowModalityController::CancelTouchesOnTransientWindowTree(
+ aura::Window* window) {
+ // Find the top level transient window.
+ aura::Window* top_level_window = window;
+ while (wm::GetTransientParent(top_level_window))
+ top_level_window = wm::GetTransientParent(top_level_window);
+
+ // BFS to get all transient windows in the tree rooted to the top level
+ // transient window.
+ std::vector<ui::GestureConsumer*> blocked_consumers;
+ std::queue<aura::Window*> que;
+ que.emplace(top_level_window);
+ while (!que.empty()) {
+ aura::Window* parent = que.front();
+ que.pop();
+ blocked_consumers.emplace_back(parent);
+ for (auto* w : wm::GetTransientChildren(parent))
+ que.emplace(w);
+ }
+
+ // Cancel touches on all the transient windows.
+ env_->gesture_recognizer()->CancelActiveTouchesOn(blocked_consumers);
+}
+
} // namespace wm
diff --git a/chromium/ui/wm/core/window_modality_controller.h b/chromium/ui/wm/core/window_modality_controller.h
index ff2ae00f0fc..e9349e5aad3 100644
--- a/chromium/ui/wm/core/window_modality_controller.h
+++ b/chromium/ui/wm/core/window_modality_controller.h
@@ -21,7 +21,7 @@ class Env;
namespace ui {
class EventTarget;
class LocatedEvent;
-}
+} // namespace ui
namespace wm {
@@ -61,8 +61,11 @@ class WM_CORE_EXPORT WindowModalityController : public ui::EventHandler,
private:
// Processes a mouse/touch event, and returns true if the event should be
// consumed.
- bool ProcessLocatedEvent(aura::Window* target,
- ui::LocatedEvent* event);
+ bool ProcessLocatedEvent(aura::Window* target, ui::LocatedEvent* event);
+
+ // Cancel touches on the transient window tree rooted to the top level
+ // transient window of the |window|.
+ void CancelTouchesOnTransientWindowTree(aura::Window* window);
aura::Env* env_;